post 8:
You run a container.
It starts successfully.
The application works.
So… is it production-ready?
Not necessarily.
The real test of a production container isn't what happens when everything works.
It's what happens when something goes wrong.
What happens when the application consumes all available memory?
What happens when the process crashes?
What happens when the application is running, but isn't actually healthy?
Where do the logs go?
How do you know something is wrong before users tell you?
And when the container fails, how do you find the actual cause?
Running Docker in production isn't just about starting containers.
It's about making them reliable, observable, manageable, and recoverable.
1. Production Starts With Boundaries
A container that works perfectly on a developer's laptop can behave very differently under production load.
Development often prioritizes:
- Speed
- Convenience
- Easy debugging
- Frequent changes
Production prioritizes:
- Reliability
- Predictability
- Security
- Observability
- Recovery
One of the first production questions is:
What happens if this container consumes more resources than expected?
That's where resource limits come in.
2. Resource Limits – Don't Let One Container Consume Everything
Without appropriate resource limits, a container can consume more host resources than intended.
For example:
docker run \
--memory=512m \
--cpus=1.0 \
nginx
This limits the container to:
- 512 MB memory
- 1 CPU
Why does this matter?
Imagine one application suddenly starts consuming several gigabytes of memory.
Without appropriate limits, it could affect other workloads running on the same host.
Resource limits create boundaries between workloads.
But remember:
A resource limit doesn't fix a memory leak.
It only limits how much damage that container can cause to the host.
So now we have another question:
What if the container is running, but the application inside it is broken?
3. Health Checks – Running Doesn't Mean Healthy
One of the most important production concepts is the difference between:
Container is running
and
Application is healthy.
A container can be running while the application inside is:
- Hung
- Unable to connect to a database
- Returning errors
- Failing internal checks
Docker supports health checks.
For example:
HEALTHCHECK --interval=30s --timeout=5s \
CMD curl -f http://localhost:8080/health || exit 1
Now Docker can track the application's health status.
The important idea is:
Process alive ≠ application healthy
A health check only reports the container's health status. Docker does not automatically restart a container simply because it becomes unhealthy.
An orchestrator or external health-monitoring tool is needed to take further action.
Health vs. Recovery
| Situation | What happens |
|---|---|
| Process exits | A restart policy can restart the container |
Health check becomes unhealthy
|
Docker reports the status; it doesn't automatically restart the container |
| Container repeatedly crashes | A restart policy may keep retrying |
| Application is unhealthy but still running | Monitoring or orchestration is needed to take further action |
So what happens when the application actually crashes and exits?
That's where restart policies come in.
4. Restart Policies – What Happens After a Crash?
Applications crash.
Processes exit unexpectedly.
Production systems need a recovery strategy.
Docker provides restart policies such as:
docker run --restart=unless-stopped nginx
Common policies include:
noon-failurealwaysunless-stopped
For example:
--restart=on-failure
tells Docker to restart the container when it exits with a failure.
Notice the distinction:
Health check → reports health
Restart policy → reacts to container exits
A restart policy doesn't automatically fix an application that is alive but unhealthy.
And if an application crashes repeatedly, restarting it doesn't solve the underlying problem.
It simply keeps trying to recover.
Recovery and diagnosis are two different problems.
Which leads to another question:
When something fails, where is the evidence?
5. Logging – Keep the Evidence
When something fails in production, logs are often your first source of evidence.
Docker captures container output from:
stdout
stderr
You can inspect it with:
docker logs <container>
Follow logs in real time:
docker logs -f <container>
And limit the output:
docker logs --tail 100 <container>
But don't treat docker logs as your complete production logging strategy.
Docker's default json-file logging driver can grow over time and consume host disk space if log rotation isn't configured.
Production environments should consider log rotation using options such as:
max-size
max-file
For high-volume applications, a non-blocking logging mode can also help prevent logging from affecting application performance.
Larger environments may also send logs to a centralized logging system for:
- Log retention
- Search and filtering
- Centralized access
- Alerting
Logs are your first witness. Treat them like evidence, not decoration.
They tell you what happened. But what if you want to know what is happening right now?
6. Monitoring – Know Before Users Tell You
Logs tell you what happened.
Metrics help you understand what is happening.
At minimum, monitor things such as:
- CPU usage
- Memory usage
- Network activity
- Container restarts
- Disk usage
- Application response time
- Error rates
Docker provides a simple starting point:
docker stats
This gives you a live view of container resource consumption.
But production monitoring usually goes further.
You want to know:
Is the application healthy before customers start reporting that it is broken?
That's where metrics, dashboards, and alerts become important.
But even with monitoring, failures will happen.
The next skill is knowing how to investigate them.
7. Troubleshooting – Don't Just Restart Everything
When a container isn't working, don't randomly restart everything.
Use a systematic approach.
Step 1: Check the container status
docker ps -a
Look for:
- Exited containers
- Restarting containers
- Unexpectedly stopped services
Step 2: Check the logs
docker logs <container>
Look for:
- Application errors
- Configuration problems
- Connection failures
- Permission issues
Step 3: Inspect the container
docker inspect <container>
Check:
- Environment variables
- Mounts
- Networks
- Restart policies
- Health status
Step 4: Check resource usage
docker stats
Look for:
- High CPU
- High memory
- Unusual resource consumption
Step 5: Check networking
If the application cannot reach another service, verify:
- Network configuration
- Service/container name
- Ports
- DNS resolution
- Connectivity between containers
Step 6: Check the image
Sometimes the problem isn't the container.
It's the image.
Check:
- Image version
- Recent changes
- Application dependencies
- Base image updates
The goal is to move from:
“The container isn't working.”
to:
“This specific component is failing for this specific reason.”
8. Image Versions – Know What You're Running
Consider:
FROM nginx:latest
It looks convenient.
But latest can change over time.
The same Dockerfile may produce different results later because the underlying image changed.
Using a known version gives you more predictable deployments:
FROM nginx:1.29
Production environments can go even further by using carefully controlled image versions or immutable image references.
The principle is simple:
Know exactly what you're deploying.
9. Smaller Images – Reduce What You Ship
Production images should contain only what the application needs.
Smaller images can provide:
- Faster image pulls
- Faster deployments
- Smaller attack surface
- Less unnecessary software
Multi-stage builds can help.
For example:
FROM node:22 AS build
WORKDIR /app
COPY . .
RUN npm ci && npm run build
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
The build environment doesn't need to be included in the final runtime image.
This separates:
Build environment
from
Runtime environment
10. Make Containers Replaceable
Here's another important production mindset:
Containers should be replaceable, not precious.
Don't rely on manually changing files inside a running container as a permanent fix.
For example:
docker exec -it <container> bash
can be useful for troubleshooting.
But manually editing application files inside the container creates a change that disappears when the container is replaced.
Instead:
- Change the configuration or code
- Build a new image
- Test it
- Deploy the new version
- Replace the old container
This makes deployments predictable and repeatable.
And this raises another important question:
What happens to data when the container disappears?
11. Separate Application Lifecycle From Data Lifecycle
Containers are usually treated as disposable.
Application data may not be.
For example:
- Database data
- Uploaded files
- Application-generated persistent data
That's where Docker volumes or external storage come in.
The container can be replaced while the data remains.
This separation is important:
Application lifecycle ≠ Data lifecycle
The application can change.
The container can disappear.
The data should survive when it needs to.
12. Security Still Matters
Production reliability doesn't replace security.
The security principles from the previous article still apply:
- Don't run applications as root when unnecessary
- Avoid
--privileged - Use appropriate capabilities
- Keep images updated
- Use seccomp and other security controls
- Scan images
- Limit container resources
A production container isn't secure simply because it is running.
Reliability, security, and observability have to work together.
13. A Practical Production Checklist
Before running a container in production, ask:
- [ ] Is the image version controlled?
- [ ] Is the container running as a non-root user where possible?
- [ ] Are CPU and memory limits defined?
- [ ] Is a health check configured?
- [ ] Is an appropriate restart policy configured?
- [ ] Is log rotation configured?
- [ ] Are important metrics being monitored?
- [ ] Are alerts configured for critical failures?
- [ ] Is persistent data stored outside the container filesystem?
- [ ] Can the container be safely replaced?
- [ ] Is the image regularly updated and scanned?
- [ ] Is there a documented troubleshooting process?
You don't need every advanced platform feature on day one.
But you should know what happens when something goes wrong.
Summary
Running Docker in production isn't simply:
docker run
It's about designing for what happens after the container starts.
You need to think about:
- Resources → How much can the container consume?
- Health → Is the application actually working?
- Recovery → What happens when it crashes?
- Logs → Where is the evidence?
- Monitoring → How do we know something is wrong?
- Troubleshooting → How do we find the cause?
- Images → Do we know exactly what we're deploying?
- Data → What survives when the container disappears?
- Security → What privileges does the workload actually need?
A container that runs successfully is only the beginning.
Production readiness starts when you ask what happens when things go wrong.
Question for You
What's the first thing you check when a Docker container fails in production — logs, resources, health status, or something else?
Next Topic
Rootless Docker & Advanced Security: Running Containers With Fewer Privileges
Top comments (0)