Running Docker in Production Lessons Learned from Real World Deployments
Explore key takeaways, pitfalls, and best practices from deploying Docker at scale in real-world production environments
Docker has revolutionized the way we build, ship, and run applications by introducing containerization — enabling consistency across development, testing, and production. But running Docker in production brings a unique set of challenges, from security and resource isolation to logging, networking, and orchestration.
This blog post dives into real-world lessons learned from deploying Docker in production, providing actionable insights for DevOps engineers, architects, and developers who want to scale containers safely and efficiently.
Lesson 1: Don’t Run Containers as Root
By default, Docker containers run as root, which can be dangerous in production environments.
Best Practice:
- Use a non-root user in your Dockerfile:
RUN adduser --system appuser
USER appuser
- Enable user namespaces and Linux capabilities for further hardening
Lesson 2: Treat Images as Immutable, Layered Builds
Frequent image changes and latest
tags lead to inconsistencies and debugging nightmares.
Best Practice:
- Use semantic versioning (e.g.,
myapp:1.2.3
) - Build images with multi-stage Dockerfiles for lean, secure final images:
FROM golang:1.20 AS builder
WORKDIR /app
COPY . .
RUN go build -o main .
FROM alpine:latest
COPY --from=builder /app/main /main
CMD ["/main"]
Lesson 3: Always Set Resource Limits
Without resource constraints, a misbehaving container can starve the host.
Best Practice:
- Use CPU and memory limits via Docker or orchestrators:
docker run --memory="512m" --cpus="1.0" myapp:1.2.3
- Monitor with Prometheus and cAdvisor for usage trends
Lesson 4: Centralized Logging is Non-Negotiable
Containers are ephemeral, and so are their logs — unless you centralize them.
Best Practice:
- Use the
json-file
driver in development, but forward logs to:- Fluentd
- Logstash + Elasticsearch
- AWS CloudWatch Logs
- Datadog / Splunk
Avoid writing logs to files inside the container. Stream to stdout/stderr and aggregate externally.
Lesson 5: Health Checks Matter
Without proper health checks, Docker and orchestrators cannot detect if an app is functioning correctly.
Best Practice:
- Add health checks to Dockerfiles:
HEALTHCHECK CMD curl --fail http://localhost:8080/health || exit 1
- Configure liveness and readiness probes in Kubernetes as well
Lesson 6: Orchestration is Essential Beyond a Few Hosts
Docker Swarm and Kubernetes solve issues like:
- Auto-restart and self-healing
- Rolling deployments
- Secrets management
- Network overlay
Best Practice:
- Use Docker Compose for local dev
- Use Kubernetes or Nomad in production
- Define infrastructure as code using Helm, Terraform, or Ansible
Lesson 7: Clean Up Regularly
Disk bloat is real — orphaned images and stopped containers eat space quickly.
Best Practice:
- Set up cron jobs to clean unused assets:
docker system prune -af --volumes
- Monitor disk space usage in CI/CD and nodes
Lesson 8: Secure the Container and Host
Security must be multi-layered:
- Avoid
latest
and scan images (Trivy, Clair, Grype) - Use Docker Content Trust for image signing
- Restrict capabilities using seccomp/apparmor
- Patch host OS and Docker Engine regularly
Bonus: Use rootless Docker for enhanced protection
Lesson 9: Network Config and DNS Pitfalls
By default, Docker uses user-defined bridge networks. In production, this can lead to DNS and latency issues.
Best Practice:
- Prefer overlay networks in orchestration tools
- Leverage service discovery (KubeDNS, Consul)
- Use traefik, nginx, or Envoy as reverse proxies
Lesson 10: Build CI/CD Pipelines for Containers
Manually deploying containers is error-prone.
Best Practice:
- Automate image building, testing, and pushing with:
- GitHub Actions
- GitLab CI
- Jenkins + Docker agents
- Use tag promotion (e.g.,
:staging
,:prod
) to control rollouts
Conclusion
Docker makes development and deployment faster, but running it in production requires careful attention to security, observability, orchestration, and resource management. By applying the lessons learned from real-world deployments, you can build resilient and scalable container infrastructure that’s ready for production workloads.
Whether you’re managing one node or a thousand, these practices will help you turn your Docker environment from a proof of concept into a battle-tested platform.