Docker Advanced: Security, Limits and Production
Resource Limits, Logging and Restarts
In this lesson you will
- Set memory and CPU limits
- Choose a restart policy
- Handle logs and graceful shutdown correctly
Introduction
By default, a container can use as much CPU and memory as the host allows. One runaway process can slow down or crash everything on the machine. Production containers need limits, a plan for failure, and sensible logging.
Resource limits
Terminal
docker run -d --memory=512m --cpus=1.5 my-app:1.4.2--memory=512mcaps memory at 512 MB. If the container goes over, the kernel may kill it (an out-of-memory kill) instead of harming other processes.--cpus=1.5limits it to the equivalent of one and a half CPU cores.
In Compose files, limits go under the service's configuration, using the syntax your Compose version supports. Check the current docs.
Watch usage live:
Terminal
docker statsSet limits using measured numbers: run under realistic load, note the peak, then add headroom.
Quick quiz
What can happen when a container exceeds its memory limit?
Restart policies
Decide what happens when a container exits:
| Policy | Behaviour |
|---|---|
no | Never restart (default) |
on-failure | Restart only if it exits with an error |
always | Always restart, also when Docker starts |
unless-stopped | Like always, but not after you stopped it manually |
Terminal
docker run -d --restart unless-stopped my-app:1.4.2Restarting hides crashes if nobody looks at them. Pair it with monitoring and alerts, and fix the cause of repeated restarts.
Logs
Containers should write logs to standard output and standard error, not to files inside the container. Docker collects them:
Terminal
docker logs -f --tail 100 my-appBy default logs can grow without limit and fill the disk. Set a size limit and rotation:
Terminal
docker run -d \
--log-driver json-file \
--log-opt max-size=10m --log-opt max-file=3 \
my-app:1.4.2In larger systems, send logs to a central service so you can search them across containers. Never log secrets or personal data.
Graceful shutdown
When you stop a container, Docker sends the main process a SIGTERM signal and, after a grace period (10 seconds by default), a forced SIGKILL. Your app should handle SIGTERM: finish current requests, close connections and exit cleanly.
Two common pitfalls:
- If your
CMDis written in shell form (CMD node server.js), a shell may sit in front of your program and not pass the signal on. Use the exec form:CMD ["node", "server.js"]. - A program that ignores SIGTERM is killed abruptly after the grace period, risking lost work. Test shutdown.
Health checks in the image
A HEALTHCHECK lets Docker know if the app inside is really working:
Dockerfile
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1The tool you call, such as curl, must exist in the image.
Try it yourself
Run a container with a memory limit and a restart policy. Watch it with docker stats. Then run docker stop and time how long it takes. If it always takes 10 seconds, your app probably is not handling SIGTERM.
Summary
- Set memory and CPU limits from measured usage so one container cannot starve the host.
- Pick a restart policy, but monitor for crash loops.
- Log to stdout with rotation, use the exec form of CMD, and handle SIGTERM for clean shutdowns.
Lesson complete
+20 XP
Nice work. Keep going while it is fresh.
Sources and further reading