Deploy y DevOps con Claude
El deploy es a menudo la fase más descuidada en los proyectos personales, pero es fundamental para transformar el código en un producto funcional. Claude puede ayudarte a configurar contenedorización, CI/CD, monitoring y logging de manera profesional.
En este artículo veremos cómo usar Claude para preparar el proyecto para producción, crear pipelines de deploy automatizados y configurar la infraestructura.
Lo que Aprenderás
- Contenedorización con Docker (multi-stage builds)
- Docker Compose para desarrollo local
- CI/CD con GitHub Actions
- Deploy en la nube (AWS, Railway, Fly.io)
- Logging y monitoring básico
Contenedorización con Docker
Multi-Stage Build para 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 para 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 para Desarrollo
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: 






