Deploy e DevOps con Claude
Il deploy è spesso la fase più trascurata nei progetti personali, ma è fondamentale per trasformare il codice in un prodotto funzionante. Claude può aiutarti a configurare containerizzazione, CI/CD, monitoring e logging in modo professionale.
In questo articolo vedremo come usare Claude per preparare il progetto alla produzione, creare pipeline di deploy automatizzate e configurare l'infrastruttura.
Cosa Imparerai
- Containerizzazione con Docker (multi-stage builds)
- Docker Compose per sviluppo locale
- CI/CD con GitHub Actions
- Deploy su cloud (AWS, Railway, Fly.io)
- Logging e monitoring base
Containerizzazione con Docker
Multi-Stage Build per Spring Boot
# Stage 1: Build
FROM eclipse-temurin:21-jdk-alpine AS builder
WORKDIR /app
# Cache dependencies
COPY pom.xml mvnw ./
COPY .mvn .mvn
RUN ./mvnw dependency:go-offline -B
# Build application
COPY src src
RUN ./mvnw package -DskipTests -B
# Extract layers for better caching
RUN java -Djarmode=layertools -jar target/*.jar extract
# Stage 2: Runtime
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
# Security: non-root user
RUN addgroup -g 1001 appgroup && \
adduser -u 1001 -G appgroup -D appuser
USER appuser
# Copy layers in order of change frequency
COPY --from=builder /app/dependencies/ ./
COPY --from=builder /app/spring-boot-loader/ ./
COPY --from=builder /app/snapshot-dependencies/ ./
COPY --from=builder /app/application/ ./
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=30s \
CMD wget -q --spider http://localhost:8080/actuator/health || exit 1
EXPOSE 8080
ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]
Multi-Stage Build per Angular
# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
# Cache dependencies
COPY package*.json ./
RUN npm ci
# Build application
COPY . .
RUN npm run build -- --configuration=production
# Stage 2: Serve
FROM nginx:alpine
COPY --from=builder /app/dist/*/browser /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
server {{ '{' }}
listen 80;
root /usr/share/nginx/html;
index index.html;
# Gzip compression
gzip on;
gzip_types text/plain text/css application/json application/javascript;
# SPA routing
location / {{ '{' }}
try_files $uri $uri/ /index.html;
{{ '}' }}
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2)$ {{ '{' }}
expires 1y;
add_header Cache-Control "public, immutable";
{{ '}' }}
# API proxy (development)
location /api/ {{ '{' }}
proxy_pass http://backend:8080/api/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
{{ '}' }}
{{ '}' }}
Docker Compose per Sviluppo
version: '3.8'
services:
backend:
build:
context: ./backend
dockerfile: Dockerfile
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=docker
- DATABASE_URL=jdbc:postgresql://postgres:5432/orders
- DATABASE_USER=postgres
- DATABASE_PASSWORD=postgres
- KAFKA_BOOTSTRAP_SERVERS=kafka:9092
depends_on:
postgres:
condition: service_healthy
kafka:
condition: service_started
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 5s
retries: 3
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
ports:
- "4200:80"
depends_on:
- backend
postgres:
image: postgres:16-alpine
environment:
- POSTGRES_DB=orders
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
kafka:
image: confluentinc/cp-kafka:7.5.0
environment:
KAFKA_NODE_ID: 1
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092
KAFKA_PROCESS_ROLES: broker,controller
KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:9093
KAFKA_LISTENERS: PLAINTEXT://kafka:9092,CONTROLLER://kafka:9093
KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
CLUSTER_ID: MkU3OEVBNTcwNTJENDM2Qk
ports:
- "9092:9092"
volumes:
postgres_data:
CI/CD con GitHub Actions
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ '{{' }} github.repository {{ '}}' }}
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
cache: maven
- name: Run tests
run: ./mvnw verify
working-directory: ./backend
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
files: ./backend/target/site/jacoco/jacoco.xml
build:
needs: test
runs-on: ubuntu-latest
if: github.event_name == 'push'
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ '{{' }} env.REGISTRY {{ '}}' }}
username: ${{ '{{' }} github.actor {{ '}}' }}
password: ${{ '{{' }} secrets.GITHUB_TOKEN {{ '}}' }}
- name: Build and push Backend
uses: docker/build-push-action@v5
with:
context: ./backend
push: true
tags: ${{ '{{' }} env.REGISTRY {{ '}}' }}/${{ '{{' }} env.IMAGE_NAME {{ '}}' }}-backend:${{ '{{' }} github.sha {{ '}}' }}
cache-from: type=gha
cache-to: type=gha,mode=max
deploy:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Deploy to Railway
uses: berviantoleo/railway-deploy@main
with:
railway_token: ${{ '{{' }} secrets.RAILWAY_TOKEN {{ '}}' }}
service: order-service
Logging e Monitoring
logging:
level:
root: INFO
com.company.orders: DEBUG
pattern:
console: "%d{{ '{' }}yyyy-MM-dd HH:mm:ss{{ '}' }} [%thread] %-5level %logger{{ '{' }}36{{ '}' }} - %msg%n"
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: when_authorized
metrics:
tags:
application: order-service
# Structured logging for production
---
spring:
config:
activate:
on-profile: prod
logging:
pattern:
console: '{{ '{' }}"timestamp":"%d{{ '{' }}ISO8601{{ '}' }}","level":"%level","logger":"%logger","message":"%msg","thread":"%thread"{{ '}' }}%n'
Checklist Deploy
Checklist Pre-Deploy
- Dockerfile multi-stage ottimizzato
- Docker Compose per sviluppo locale
- Health check configurato
- CI/CD pipeline funzionante
- Secrets gestiti correttamente (non in git)
- Logging strutturato per produzione
- Metriche esposte (Prometheus/Actuator)
- Backup database automatizzato
Conclusione
In questo articolo abbiamo visto come preparare il progetto per il deploy in produzione. Nel prossimo e ultimo articolo, esploreremo l'evoluzione del progetto: scalabilità, manutenzione e aggiunta di nuove feature.
Punti Chiave da Ricordare
- Multi-stage builds: Immagini piccole e sicure
- Docker Compose: Ambiente locale riproducibile
- CI/CD automatizzato: Deploy consistente e affidabile
- Health checks: Fondamentali per orchestratori
- Logging strutturato: Facilità debugging in produzione

Commenti
Caricamento commenti...
Accedi per commentare