Learn production-grade Docker deployment strategies including zero-downtime updates, monitoring, logging, backup strategies, and disaster recovery.
Deploying Docker containers to production requires careful consideration of reliability, scalability, security, and observability. Production environments demand high availability, automated deployments, comprehensive monitoring, and robust recovery procedures.
This lesson covers the complete production deployment lifecycle, from infrastructure design through day-2 operations. You'll learn how to build resilient container deployments that can handle real-world traffic, maintain uptime during updates, and recover from failures automatically.
A production Docker environment requires careful architectural planning to ensure reliability and performance.
Key Architecture Components:
Infrastructure Patterns:
High Availability Considerations:
Zero-downtime deployments ensure continuous service availability during updates. Multiple strategies exist, each with different trade-offs.
Deployment Strategies:
Key Requirements:
Production containers require comprehensive logging and monitoring for troubleshooting, performance analysis, and alerting.
Logging Strategy:
Logging Drivers:
Monitoring Stack:
Production deployments require robust backup strategies and tested disaster recovery procedures to ensure business continuity.
Backup Components:
Backup Strategies:
Disaster Recovery:
Production environments require systematic hardening across all layers. Use this checklist to verify your deployment meets production standards.
Host Security:
Docker Daemon:
Container Runtime:
Network:
Implement a full production deployment with CI/CD, monitoring, and automated rollback.
1# Complete Production Deployment System
2
3# === CI/CD Pipeline ===
4# .github/workflows/deploy-production.yml
5name: Deploy to Production
6
7on:
8 push:
9 tags:
10 - 'v*'
11
12env:
13 REGISTRY: ghcr.io
14 IMAGE_NAME: ${{ github.repository }}
15
16jobs:
17 test:
18 runs-on: ubuntu-latest
19 steps:
20 - uses: actions/checkout@v4
21 - name: Run tests
22 run: |
23 docker compose -f docker-compose.test.yml up --build --exit-code-from test
24
25 security-scan:
26 needs: test
27 runs-on: ubuntu-latest
28 steps:
29 - uses: actions/checkout@v4
30 - name: Build image
31 run: docker build -t ${{ env.IMAGE_NAME }}:${{ github.sha }} .
32 - name: Scan with Trivy
33 uses: aquasecurity/trivy-action@master
34 with:
35 image-ref: ${{ env.IMAGE_NAME }}:${{ github.sha }}
36 exit-code: '1'
37 severity: 'CRITICAL'
38
39 build-push:
40 needs: security-scan
41 runs-on: ubuntu-latest
42 permissions:
43 contents: read
44 packages: write
45 steps:
46 - uses: actions/checkout@v4
47 - name: Login to Registry
48 uses: docker/login-action@v3
49 with:
50 registry: ${{ env.REGISTRY }}
51 username: ${{ github.actor }}
52 password: ${{ secrets.GITHUB_TOKEN }}
53 - name: Build and push
54 uses: docker/build-push-action@v5
55 with:
56 push: true
57 tags: |
58 ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}
59 ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
60
61 deploy:
62 needs: build-push
63 runs-on: ubuntu-latest
64 environment: production
65 steps:
66 - uses: actions/checkout@v4
67 - name: Deploy to production
68 env:
69 SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
70 DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
71 run: |
72 echo "$SSH_KEY" > deploy_key
73 chmod 600 deploy_key
74 ssh -i deploy_key -o StrictHostKeyChecking=no deploy@$DEPLOY_HOST \
75 "cd /app && ./deploy.sh ${{ github.ref_name }}"
76
77 - name: Health check
78 run: |
79 sleep 30
80 curl -sf https://app.example.com/health || exit 1
81
82 - name: Notify on success
83 uses: 8398a7/action-slack@v3
84 with:
85 status: success
86 fields: repo,message,author
87 env:
88 SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
89
90 - name: Rollback on failure
91 if: failure()
92 run: |
93 ssh -i deploy_key deploy@$DEPLOY_HOST "cd /app && ./rollback.sh"
94
95# === Deployment Script ===
96#!/bin/bash
97# deploy.sh
98set -e
99
100VERSION=${1:-latest}
101COMPOSE_FILE="docker-compose.prod.yml"
102TIMEOUT=300
103
104echo "=== Deploying version $VERSION ==="
105echo "Time: $(date)"
106
107# Pre-deployment checks
108./pre-deploy-check.sh
109
110# Backup current state
111./backup.sh
112
113# Pull new images
114VERSION=$VERSION docker compose -f $COMPOSE_FILE pull
115
116# Deploy with rolling update
117VERSION=$VERSION docker compose -f $COMPOSE_FILE up -d --remove-orphans
118
119# Wait for health
120echo "Waiting for containers to be healthy..."
121start_time=$(date +%s)
122while true; do
123 healthy=$(docker compose -f $COMPOSE_FILE ps --format json | jq -r 'select(.Health == "healthy")' | wc -l)
124 total=$(docker compose -f $COMPOSE_FILE ps --format json | wc -l)
125
126 if [ "$healthy" -eq "$total" ]; then
127 echo "All containers healthy!"
128 break
129 fi
130
131 elapsed=$(($(date +%s) - start_time))
132 if [ $elapsed -gt $TIMEOUT ]; then
133 echo "Deployment timeout - rolling back"
134 ./rollback.sh
135 exit 1
136 fi
137
138 echo "Healthy: $healthy/$total (elapsed: ${elapsed}s)"
139 sleep 10
140done
141
142# Record deployment
143echo "$VERSION $(date)" >> /var/log/deployments.log
144
145echo "=== Deployment Complete ==="
146
147# === Rollback Script ===
148#!/bin/bash
149# rollback.sh
150set -e
151
152echo "=== Rolling Back ==="
153
154PREVIOUS_VERSION=$(tail -2 /var/log/deployments.log | head -1 | awk '{print $1}')
155echo "Rolling back to version: $PREVIOUS_VERSION"
156
157VERSION=$PREVIOUS_VERSION docker compose -f docker-compose.prod.yml up -d
158
159echo "=== Rollback Complete ==="
160
161# === Production Docker Compose ===
162# docker-compose.prod.yml
163version: '3.8'
164
165services:
166 app:
167 image: ghcr.io/myorg/myapp:${VERSION:-latest}
168 deploy:
169 mode: replicated
170 replicas: 3
171 update_config:
172 parallelism: 1
173 delay: 30s
174 failure_action: rollback
175 order: start-first
176 rollback_config:
177 parallelism: 0
178 resources:
179 limits:
180 cpus: '1'
181 memory: 512M
182 healthcheck:
183 test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
184 interval: 10s
185 timeout: 5s
186 retries: 3
187 start_period: 30s
188 logging:
189 driver: "json-file"
190 options:
191 max-size: "10m"
192 max-file: "5"
193 labels:
194 - "traefik.enable=true"
195 - "traefik.http.routers.app.rule=Host(`app.example.com`)"
196 - "traefik.http.routers.app.tls.certresolver=letsencrypt"
197 networks:
198 - frontend
199 - backend
200 secrets:
201 - db_password
202 - api_key
203
204secrets:
205 db_password:
206 external: true
207 api_key:
208 external: true
209
210networks:
211 frontend:
212 backend:
213 internal: trueYour progress is saved in this browser, on this device only.