Introduction
If you’re a DevOps lead tasked with rolling out a Docker‑centric CI/CD pipeline, a solid checklist can keep you from missing critical steps. This guide walks you through the essential pieces—from image hardening to monitoring—so you can ship code fast and keep your environment safe.
1. Repository Hygiene
-
Branch protection: Require pull‑request reviews and status checks before merging to
main
. - Secret scanning: Enable tools like GitGuardian or TruffleHog to catch API keys early.
- Commit linting: Enforce conventional commits to keep changelogs readable.
2. Dockerfile Best Practices
A well‑crafted Dockerfile
reduces attack surface and improves build speed.
# Use an official, minimal base image
FROM python:3.12-slim-alpine AS builder
# Set a non‑root user early
ARG USERNAME=appuser
ARG USER_UID=1001
ARG USER_GID=$USER_UID
RUN addgroup -g $USER_GID $USERNAME \
&& adduser -u $USER_UID -G $USERNAME -s /bin/sh -D $USERNAME
# Install only build‑time dependencies
RUN apk add --no-cache gcc musl-dev libffi-dev
# Copy source code and install runtime deps
COPY requirements.txt /app/
WORKDIR /app
RUN pip install --no-cache-dir -r requirements.txt
# Switch to non‑root user for runtime
USER $USERNAME
# Final stage – slim runtime image
FROM python:3.12-slim-alpine
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=builder /app /app
WORKDIR /app
CMD ["python", "-m", "myapp"]
Key takeaways:
- Multi‑stage builds keep the final image lean.
- Run as a non‑root user.
- Pin exact base image versions.
- Remove build‑time packages before the final stage.
3. Image Scanning & Signing
- Scanning: Integrate tools like Trivy or Clair into your CI pipeline. Example GitHub Actions step:
- name: Scan Docker image
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
severity: HIGH,CRITICAL
- Signing: Use Docker Content Trust (DCT) or Cosign to sign images before pushing to your registry.
4. CI Workflow Structure
Stage | Purpose | Typical Tool |
---|---|---|
Lint | Static analysis of Dockerfile and code | Hadolint, ESLint |
Test | Unit & integration tests | pytest, Jest |
Build | Create image, run scans | Docker, BuildKit |
Push | Push signed image to registry | Docker, Cosign |
Deploy | Deploy to staging/production | Argo CD, Helm |
Sample GitHub Actions CI
name: CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Lint Dockerfile
uses: hadolint/hadolint-action@v2
with:
dockerfile: Dockerfile
- name: Run tests
run: |
python -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
pytest
- name: Build image
run: |
docker build -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} .
- name: Scan image
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
- name: Sign image
run: |
cosign sign --key ${{ secrets.COSIGN_KEY }} ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
5. Runtime Hardening
-
Resource limits: Define CPU and memory caps in
docker-compose.yml
or Kubernetes manifests. - Read‑only file systems: Where possible, mount volumes as read‑only.
- Seccomp & AppArmor: Apply default profiles, then tighten as needed.
- Network segmentation: Use user‑defined bridge networks to isolate containers.
services:
web:
image: myorg/webapp:latest
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M
read_only: true
networks:
- frontend
networks:
frontend:
driver: bridge
6. Monitoring & Observability
-
Metrics: Export Docker daemon metrics to Prometheus via
cadvisor
. -
Logs: Ship container stdout/stderr to Loki or Elastic Stack using the
json-file
driver. - Alerting: Set up alerts for high CPU, memory spikes, or image vulnerabilities.
# docker-compose snippet for cAdvisor
services:
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
ports:
- "8080:8080"
volumes:
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
7. Backup & Disaster Recovery
-
Registry backups: Periodically
docker save
critical images and store them in an immutable S3 bucket. -
Stateful data: Use volume snapshots (e.g.,
docker volume create --driver local ...
) and store snapshots off‑site. - Runbooks: Document a step‑by‑step rollback procedure, including image tag rollback and database restore.
8. Periodic Review Checklist
- [ ] Are all base images up‑to‑date with security patches?
- [ ] Have you removed any unnecessary packages from the final image?
- [ ] Do all images pass Trivy/Clair scans with no HIGH or CRITICAL findings?
- [ ] Are runtime containers running with least‑privilege user IDs?
- [ ] Is resource throttling configured for each service?
- [ ] Are logs and metrics being shipped to a central store?
- [ ] Have you tested a full restore from your backup store in the last month?
Conclusion
Building a Docker‑centric CI/CD pipeline isn’t just about automation; it’s about embedding security and observability into every step. By ticking off the items above, you’ll reduce the risk of supply‑chain attacks, keep performance predictable, and give your team confidence that releases are both fast and safe.
If you’re looking for a partner that can help audit your pipeline or provide managed Docker hosting, consider checking out https://lacidaweb.com for a low‑key, no‑pressure conversation.
Top comments (0)