Aller au contenu

Déploiement


Docker

Build de l'image

make docker-build

Ou manuellement:

docker build -t mon-projet:latest .

Le Dockerfile généré utilise un build multi-stage:

# Stage 1: Build
FROM golang:1.25-alpine AS builder

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod tidy

COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main cmd/main.go

# Stage 2: Runtime
FROM alpine:latest

RUN apk --no-cache add ca-certificates
WORKDIR /root/

COPY --from=builder /app/main .
COPY .env.example .env

EXPOSE 8080
CMD ["./main"]

Avantages: - Image finale légère (~15-20MB vs ~1GB) - Sécurité (image alpine minimale) - Binaire statique (pas de dépendances)

Run avec Docker

docker run -p 8080:8080 \
  -e DB_HOST=host.docker.internal \
  -e DB_PASSWORD=postgres \
  -e JWT_SECRET=<votre_secret> \
  mon-projet:latest

Note: host.docker.internal permet d'accéder à localhost depuis Docker.

Docker Compose

Si docker-compose.yml est généré:

version: '3.8'

services:
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      DB_HOST: postgres
      DB_USER: postgres
      DB_PASSWORD: postgres
      DB_NAME: mon-projet
      JWT_SECRET: ${JWT_SECRET}
    depends_on:
      - postgres

  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: mon-projet
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

Lancer:

# Set JWT_SECRET
export JWT_SECRET=$(openssl rand -base64 32)

# Start all services
docker-compose up -d

# View logs
docker-compose logs -f app

# Stop
docker-compose down

Kubernetes

Manifests basiques pour déploiement K8s:

Secret

# k8s/secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mon-projet-secret
type: Opaque
stringData:
  jwt-secret: "<votre_secret_base64>"
  db-password: "postgres"
kubectl apply -f k8s/secret.yaml

Deployment

# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mon-projet
  labels:
    app: mon-projet
spec:
  replicas: 3
  selector:
    matchLabels:
      app: mon-projet
  template:
    metadata:
      labels:
        app: mon-projet
    spec:
      containers:
      - name: mon-projet
        image: mon-projet:latest
        ports:
        - containerPort: 8080
        env:
        - name: APP_PORT
          value: "8080"
        - name: DB_HOST
          value: postgres-service
        - name: DB_USER
          value: postgres
        - name: DB_NAME
          value: mon-projet
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mon-projet-secret
              key: db-password
        - name: JWT_SECRET
          valueFrom:
            secretKeyRef:
              name: mon-projet-secret
              key: jwt-secret
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 30
        readinessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 10
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "500m"
kubectl apply -f k8s/deployment.yaml

Service

# k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: mon-projet-service
spec:
  selector:
    app: mon-projet
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
  type: LoadBalancer
kubectl apply -f k8s/service.yaml

Déployer PostgreSQL (StatefulSet)

# k8s/postgres.yaml
apiVersion: v1
kind: Service
metadata:
  name: postgres-service
spec:
  selector:
    app: postgres
  ports:
  - port: 5432
  clusterIP: None
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  serviceName: postgres-service
  replicas: 1
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
      - name: postgres
        image: postgres:16-alpine
        ports:
        - containerPort: 5432
        env:
        - name: POSTGRES_DB
          value: mon-projet
        - name: POSTGRES_USER
          value: postgres
        - name: POSTGRES_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mon-projet-secret
              key: db-password
        volumeMounts:
        - name: postgres-storage
          mountPath: /var/lib/postgresql/data
  volumeClaimTemplates:
  - metadata:
      name: postgres-storage
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 10Gi
kubectl apply -f k8s/postgres.yaml

CI/CD avec GitHub Actions

Le workflow généré (.github/workflows/ci.yml):

name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  quality:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3

    - name: Set up Go
      uses: actions/setup-go@v4
      with:
        go-version: '1.25'

    - name: golangci-lint
      uses: golangci/golangci-lint-action@v3
      with:
        version: latest

  test:
    runs-on: ubuntu-latest

    services:
      postgres:
        image: postgres:16-alpine
        env:
          POSTGRES_DB: test_db
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: postgres
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 5432:5432

    steps:
    - uses: actions/checkout@v3

    - name: Set up Go
      uses: actions/setup-go@v4
      with:
        go-version: '1.25'

    - name: Run tests
      env:
        DB_HOST: localhost
        DB_PORT: 5432
        DB_USER: postgres
        DB_PASSWORD: postgres
        DB_NAME: test_db
        JWT_SECRET: test-secret
      run: go test -v -race -coverprofile=coverage.out ./...

    - name: Upload coverage
      uses: codecov/codecov-action@v3
      with:
        files: ./coverage.out

  build:
    runs-on: ubuntu-latest
    needs: [quality, test]
    steps:
    - uses: actions/checkout@v3

    - name: Set up Go
      uses: actions/setup-go@v4
      with:
        go-version: '1.25'

    - name: Build
      run: go build -v -o mon-projet cmd/main.go

Pipeline: 1. Quality: golangci-lint 2. Test: Tests avec PostgreSQL (service container) 3. Build: Vérification build

Déploiement en production

Checklist pré-déploiement

  • [ ] Tous les tests passent (make test)
  • [ ] Lint passe (make lint)
  • [ ] Variables d'environnement configurées
  • [ ] JWT_SECRET généré (fort, aléatoire)
  • [ ] DB_SSLMODE=require
  • [ ] Migrations DB exécutées
  • [ ] Health check fonctionne
  • [ ] Logs configurés
  • [ ] Monitoring en place

Plateformes recommandées

1. Google Cloud Run (le plus simple):

# Build et push image
gcloud builds submit --tag gcr.io/PROJECT_ID/mon-projet

# Deploy
gcloud run deploy mon-projet \
  --image gcr.io/PROJECT_ID/mon-projet \
  --platform managed \
  --region us-central1 \
  --allow-unauthenticated \
  --set-env-vars JWT_SECRET=$JWT_SECRET,DB_HOST=$DB_HOST

2. AWS ECS/Fargate:

  • Build image → Push to ECR
  • Create Task Definition
  • Create ECS Service
  • Configure ALB

3. Heroku:

# Login
heroku login

# Create app
heroku create mon-projet

# Add PostgreSQL
heroku addons:create heroku-postgresql:hobby-dev

# Set env vars
heroku config:set JWT_SECRET=$(openssl rand -base64 32)

# Deploy
git push heroku main

4. Kubernetes (le plus flexible):

# Apply all manifests
kubectl apply -f k8s/

# Check status
kubectl get pods
kubectl get services

# View logs
kubectl logs -f deployment/mon-projet


Previous: Sécurité
Next: Monitoring
Index: Guide Index