Docker has transformed software delivery, but using containers in production requires discipline. Large images increase storage costs and deployment times, while vulnerabilities can expose your environment to attacks. This guide presents best practices that ensure lightweight, secure and versionable images.
Essential good practices
- Multi-stage builds, compile the code in one stage and copy only the final artifacts.
- Minimalist base images, prefer
alpineordistrolessto reduce the attack surface. - Never include credentials,
.envfiles, keys or tokens should never be copied to the image. - Run as non-root user, create a dedicated user and configure the container to use it.
- Version without
latest, use semantic tags (v1.2.3) for traceability and rollback.
Lean example of multi-stage Dockerfile (Node.js), 9 lines
FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . RUN npm run build # gera artefatos estáticos FROM gcr.io/distroless/nodejs20 WORKDIR /app COPY /app/dist ./dist COPY /app/node_modules ./node_modules USER nonroot EXPOSE 3000 CMD ["dist/index.js"]
Image security checklist
- Scan vulnerabilities with Trivy, Clair or Snyk.
- Check unnecessary layers (
docker history). - Define non-root user in Dockerfile.
- Remove temporary files (
npm cache clean --force). - Sign the image using Docker Content Trust to ensure integrity.
Versioning strategy
| Tag | When to use |
|---|---|
v1.2.3 | Stable release, compatible with semver. |
v1.2.3-rc.1 | Release candidate for testing. |
v1.2.3-sha.<commit> | Automated build for CI, traceable. |
Simplified CI/CD integration (GitHub Actions), 7 lines
name: Build & Push Docker Image on: push: branches: [main] jobs: docker: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Build image run: docker build -t myapp:$ . - name: Login to Docker Hub uses: docker/login-action@v2 with: username: $ password: $ - name: Push image run: docker push myapp:$
Conclusion
By applying these practices you obtain smaller, more secure and easily versionable images, reducing operational costs and mitigating the risk of vulnerabilities in production.
What Docker strategies have you already adopted? Share in the comments!
Also read
- Kubernetes in production: what no one tells you before you migrate
- Modern CI/CD: The Art of Deploying with Confidence
- Cloudflare Workers in production: what changes after hello world
- D1 in production: performance, limits and what doesn’t scale alone
- Durable Objects in production: what the bill will look like and the limits that surprise
- Implementing Feature Flags and Gradual Rollouts in Production
