You are viewing a free preview of this lesson.
Subscribe to unlock all 10 lessons in this course and every other course on LearningBro.
Running containers in development is straightforward. Running them reliably in production requires careful attention to logging, health checks, restart policies, resource management, and orchestration. This lesson covers the patterns and tools that make containers production-ready.
Docker supports multiple logging drivers. The default is json-file, which stores logs as JSON on the host.
| Driver | Description |
|---|---|
json-file | Default; logs stored as JSON files on host |
syslog | Sends logs to a syslog server |
journald | Sends logs to systemd journal |
fluentd | Sends logs to Fluentd |
awslogs | Sends logs to AWS CloudWatch |
gcplogs | Sends logs to Google Cloud Logging |
none | Disables logging |
# Use the json-file driver with rotation
docker run -d \
--log-driver json-file \
--log-opt max-size=10m \
--log-opt max-file=3 \
my-app:latest
# Send logs to syslog
docker run -d \
--log-driver syslog \
--log-opt syslog-address=tcp://logserver:514 \
my-app:latest
services:
api:
image: my-api:latest
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
| Practice | Reason |
|---|---|
| Log to stdout/stderr | Docker captures and routes these |
| Use structured logging (JSON) | Easier to parse, filter, and aggregate |
| Set log rotation limits | Prevent disk exhaustion |
| Include request IDs/trace IDs | Correlate logs across services |
| Avoid logging sensitive data | Security and compliance |
Key principle: Applications in containers should log to stdout/stderr, not to files. Docker captures stdout/stderr and routes them through the configured logging driver.
Health checks let Docker (and orchestrators) know if a container is actually working, not just running.
FROM node:20-alpine
WORKDIR /app
COPY . .
RUN npm ci
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
CMD ["node", "server.js"]
services:
api:
build: .
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
start_period: 15s
retries: 3
| State | Meaning |
|---|---|
starting | Container started, within start_period |
healthy | Health check passing |
unhealthy | Health check failing (retries exceeded) |
# Check container health status
docker inspect --format='{{.State.Health.Status}}' my-container
# View health check history
docker inspect --format='{{json .State.Health}}' my-container | jq
Restart policies determine what happens when a container exits.
| Policy | Behaviour |
|---|---|
no | Never restart (default) |
always | Always restart, including on daemon startup |
unless-stopped | Like always, but not if manually stopped |
on-failure[:max] | Restart only on non-zero exit code, with max retries |
# Restart always (production services)
docker run -d --restart always my-app:latest
# Restart on failure, max 5 attempts
docker run -d --restart on-failure:5 my-app:latest
services:
api:
image: my-api:latest
restart: unless-stopped
worker:
image: my-worker:latest
restart: on-failure:5
In production, always set resource limits to prevent a single container from consuming all host resources.
# docker-compose.yml
services:
api:
image: my-api:latest
deploy:
resources:
limits:
cpus: "2.0"
memory: 1G
reservations:
cpus: "0.5"
memory: 256M
pids_limit: 200
# Real-time resource stats for all containers
docker stats
Subscribe to continue reading
Get full access to this lesson and all 10 lessons in this course.