Docker Containers as Background Services: Detached Mode and Production Patterns
Use the -d flag to run a container in the background and return terminal control immediately:
docker run -d --name my-service my-image
The container starts as a daemon process. Verify it’s running and check output:
docker ps
docker logs my-service
Essential Configuration for Production Daemons
A single -d flag isn’t enough for real workloads. Here’s a practical example with resource limits, restart policy, and networking:
docker run -d \
--name postgres-db \
--restart unless-stopped \
-e POSTGRES_PASSWORD=secret \
-v pgdata:/var/lib/postgresql/data \
-p 5432:5432 \
--cpus 1.5 \
--memory 512m \
--network app-net \
postgres:16
Key flags for daemon containers:
--restart unless-stopped: Automatically restart on crash or reboot. Options:no,always,unless-stopped,on-failure[:max-retries]-e KEY=VALUE: Set environment variables-v source:dest: Mount volumes for persistent data-p host:container: Expose ports--network name: Connect to a custom bridge network--cpus N: Limit CPU usage (fractional cores allowed)--memory Nm: Limit memory (e.g.,512m,2g)-u username: Run as a specific user instead of root--log-driver json-file --log-opt max-size=10m --log-opt max-file=3: Rotate logs to prevent disk bloat
Docker Compose for Multi-Container Daemons
For anything beyond a single container, Docker Compose is the practical approach. Define your stack once in compose.yaml:
services:
web:
image: nginx:latest
container_name: web-server
restart: unless-stopped
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html:ro
networks:
- app-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
db:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
networks:
- app-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
networks:
app-network:
driver: bridge
volumes:
pgdata:
Start the stack in detached mode:
docker compose up -d
Manage with these commands:
docker compose ps # View container status
docker compose logs -f web # Follow web service logs in real-time
docker compose logs --tail 50 db # Last 50 lines from db service
docker compose exec db psql -U postgres # Run command inside container
docker compose stop # Stop all containers gracefully
docker compose down # Stop and remove containers
docker compose down -v # Also remove volumes (careful!)
The restart: unless-stopped policy ensures daemons survive reboots and crashes unless explicitly stopped with docker compose stop or docker compose down.
Health Checks for Reliability
Define health checks so Docker can automatically restart unhealthy containers:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
Docker runs the test command every 30 seconds. After 3 consecutive failures, the container is marked unhealthy. The start_period delays checks while the application initializes—useful for slow-starting services.
For shell-based checks:
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
Or run a custom script:
healthcheck:
test: ["CMD", "/usr/local/bin/health-check.sh"]
Monitoring and Managing Detached Containers
View logs with timestamps and filtering:
docker logs -f my-service # Real-time follow
docker logs --tail 100 my-service # Last 100 lines
docker logs --since 10m my-service # Last 10 minutes
docker logs --timestamps my-service # Include timestamps
docker logs --until 2h ago my-service # Before 2 hours ago
Stop and restart:
docker stop my-service # Graceful stop (SIGTERM, 10s timeout)
docker stop -t 30 my-service # Wait 30 seconds before SIGKILL
docker kill my-service # Immediate shutdown (SIGKILL)
docker restart my-service # Restart the container
Inspect resource usage:
docker inspect my-service # Full container configuration
docker stats my-service # Live CPU, memory, network stats
docker stats --no-stream # Single snapshot instead of streaming
Running as Non-Root with Podman
Docker requires root by default. Podman runs rootless containers with identical syntax:
podman run -d --name my-service my-image
podman compose up -d
podman logs -f my-service
podman stats my-service
Podman has no daemon process—it directly manages containers. It’s ideal for multi-tenant systems, development machines, and environments where privilege escalation is forbidden. Rootless mode has limitations with certain network configurations and privileged operations, so test your specific use case.
Scaling Beyond Single Hosts
Docker Compose works well for single-host setups. For complex deployments across multiple machines, use Kubernetes or K3s (lightweight Kubernetes). They handle:
- Daemon management across a cluster
- Automatic resource scheduling
- Self-healing and automatic restarts
- Load balancing
- Rolling updates
- Persistent storage orchestration
Start with Docker Compose locally, but plan for Kubernetes when you need multi-host resilience or dynamic scaling.
