Introduction
As a DevOps lead, you know that downtime is the enemy of user trust. Deploying new versions of a service without interrupting traffic is a classic challenge, but with Docker and Nginx you can build a reliable, zero‑downtime pipeline. This checklist walks you through the essential steps—from container image hygiene to Nginx blue‑green routing—so you can ship updates confidently.
1. Prepare a Production‑Ready Docker Image
1.1 Use a Minimal Base Image
- Alpine is tiny (≈5 MB) and reduces attack surface.
- Pin the exact version to avoid surprise upgrades.
FROM alpine:3.18
LABEL maintainer="you@example.com"
# Install only what you need
RUN apk add --no-cache python3 py3-pip
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
CMD ["python3", "-m", "gunicorn", "app:app", "--bind", "0.0.0.0:8000"]
1.2 Multi‑Stage Builds for Smaller Images
Separate the build environment from the runtime:
# ---- Build Stage ----
FROM node:20-alpine AS builder
WORKDIR /src
COPY package*.json ./
RUN npm ci && npm run build
# ---- Runtime Stage ----
FROM nginx:alpine
COPY --from=builder /src/dist /usr/share/nginx/html
1.3 Verify Image Size & Layers
docker image ls --format "{{.Repository}}:{{.Tag}} {{.Size}}"
Keep the final image under 150 MB for faster pulls.
2. Implement Blue‑Green Deployments with Nginx
2.1 Nginx Upstream Configuration
Define two upstream blocks—green
and blue
—pointing at the respective Docker containers.
upstream green {
server 127.0.0.1:8001;
keepalive 16;
}
upstream blue {
server 127.0.0.1:8002;
keepalive 16;
}
# Default to green (current production)
server {
listen 80;
location / {
proxy_pass http://green;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
2.2 Switch Traffic Atomically
When the new version is ready, update the proxy_pass
line to point at blue
and reload Nginx without dropping connections:
# Edit the config (or use a templating tool)
sed -i 's/http:\/\/green/http:\/\/blue/' /etc/nginx/conf.d/app.conf
# Reload gracefully
nginx -s reload
Because Nginx reloads the configuration in a worker‑by‑worker fashion, existing connections finish on the old upstream while new requests flow to the updated container.
3. Automate the Workflow with Docker Compose
A single docker-compose.yml
can spin up both green and blue containers, expose the correct ports, and tag the services for easy swapping.
version: "3.9"
services:
app-green:
image: myorg/app:{{CURRENT_TAG}}
ports: ["8001:8000"]
restart: always
app-blue:
image: myorg/app:{{NEW_TAG}}
ports: ["8002:8000"]
restart: always
nginx:
image: nginx:alpine
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
ports: ["80:80"]
depends_on:
- app-green
- app-blue
Deploy steps:
- Pull the new image (
docker pull myorg/app:1.2.3
). - Bring up the blue container (
docker-compose up -d app-blue
). - Verify health checks.
- Switch Nginx upstream (as shown above).
- After traffic stabilizes, tear down the green container.
4. Health Checks & Observability
4.1 Container‑Level Health Checks
Add a simple HTTP endpoint (/healthz
) to your app and declare it in Docker:
HEALTHCHECK --interval=10s --timeout=2s \
CMD curl -f http://localhost:8000/healthz || exit 1
Docker will mark the container unhealthy if the endpoint fails, preventing Nginx from routing to a broken instance.
4.2 Centralized Logging
Send logs to a lightweight sidecar like Fluent Bit and forward them to Loki or CloudWatch. Example fluent-bit.conf
:
[INPUT]
Name tail
Path /var/log/app/*.log
Tag app.*
[OUTPUT]
Name stdout
Match *
4.3 Metrics for Rollback Decisions
Expose Prometheus metrics (/metrics
) and watch the error rate during the switch. If the new version spikes above a threshold, roll back by re‑pointing Nginx to the green upstream.
5. Security & Secrets Management
- Store Docker registry credentials in Docker secrets or a secret manager (AWS Secrets Manager, HashiCorp Vault).
- Use TLS termination at Nginx: generate certs with Let’s Encrypt or use a corporate PKI.
- Add a strict
Content‑Security‑Policy
header in Nginx to mitigate XSS.
add_header Content-Security-Policy "default-src 'self'" always;
6. Checklist Summary
- [ ] Build minimal, multi‑stage Docker images.
- [ ] Tag images with immutable version identifiers.
- [ ] Define
green
andblue
upstreams in Nginx. - [ ] Use Docker Compose to run both versions side‑by‑side.
- [ ] Add container health checks and expose
/healthz
. - [ ] Verify new container health before traffic switch.
- [ ] Reload Nginx gracefully (
nginx -s reload
). - [ ] Monitor Prometheus metrics for error spikes.
- [ ] Log to a central system (Fluent Bit → Loki/CloudWatch).
- [ ] Secure secrets and enable TLS on Nginx.
- [ ] After successful rollout, decommission the old container.
Conclusion
Zero‑downtime deployments become repeatable when you treat the Docker image, Nginx routing, and observability as a single, versioned artifact. By following this checklist you’ll reduce risk, improve developer velocity, and keep users blissfully unaware of any behind‑the‑scenes changes. If you need help shipping this, the team at https://ramerlabs.com can help.
Top comments (0)