Container Documentation
Docker Deployment Guide
This guide covers containerizing applications with Docker: writing Dockerfiles, building images, running containers, and production deployment patterns.
Prerequisites
- Docker Engine 20.10+ installed
- Docker Compose v2 (optional, for multi-container setups)
- Basic familiarity with command-line operations
Quick Start
Pull and run the official image:
# Pull the latest image
docker pull example/app:latest
# Run with required environment variables
docker run -d \
--name my-app \
-p 8080:8080 \
-e DATABASE_URL="postgres://..." \
-e API_KEY="your-key" \
example/app:latest
Verify the container is running:
docker ps
docker logs my-app
Writing a Dockerfile
A well-structured Dockerfile for a Node.js application:
# Use specific version for reproducibility
FROM node:20-alpine AS builder
# Set working directory
WORKDIR /app
# Copy dependency files first (better layer caching)
COPY package*.json ./
# Install dependencies
RUN npm ci --only=production
# Copy application code
COPY . .
# Build the application
RUN npm run build
# Production stage - smaller final image
FROM node:20-alpine AS production
WORKDIR /app
# Create non-root user for security
RUN addgroup -g 1001 -S appgroup && \
adduser -u 1001 -S appuser -G appgroup
# Copy only production artifacts
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
# Switch to non-root user
USER appuser
# Expose the application port
EXPOSE 8080
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
# Start the application
CMD ["node", "dist/server.js"]
Dockerfile Best Practices
- Use specific base image tags — Avoid
:latest; pin to:20-alpineor a SHA digest. - Multi-stage builds — Keep build tools out of production images.
- Layer caching — Copy dependency files before source code.
- Non-root user — Never run as root in production.
- Health checks — Enable orchestrators to detect unhealthy containers.
- .dockerignore — Exclude node_modules, .git, and test files.
Building Images
# Build with a tag
docker build -t my-app:1.0.0 .
# Build with build arguments
docker build \
--build-arg NODE_ENV=production \
--build-arg VERSION=1.0.0 \
-t my-app:1.0.0 .
# Build for multiple platforms
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t my-app:1.0.0 \
--push .
Running Containers
Basic Run
docker run -d \
--name my-app \
-p 8080:8080 \
my-app:1.0.0
With Environment Variables
# From command line
docker run -d \
-e DATABASE_URL="postgres://user:pass@host:5432/db" \
-e LOG_LEVEL="info" \
my-app:1.0.0
# From env file
docker run -d \
--env-file .env.production \
my-app:1.0.0
With Volumes
# Named volume (persistent data)
docker run -d \
-v app-data:/app/data \
my-app:1.0.0
# Bind mount (development)
docker run -d \
-v $(pwd)/config:/app/config:ro \
my-app:1.0.0
Resource Limits
docker run -d \
--memory="512m" \
--cpus="1.0" \
--restart=unless-stopped \
my-app:1.0.0
Docker Compose
For multi-container applications:
# docker-compose.yml
version: "3.8"
services:
app:
image: my-app:1.0.0
ports:
- "8080:8080"
environment:
- DATABASE_URL=postgres://postgres:password@db:5432/app
- REDIS_URL=redis://cache:6379
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"]
interval: 30s
timeout: 3s
retries: 3
db:
image: postgres:15-alpine
volumes:
- postgres-data:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=password
- POSTGRES_DB=app
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
cache:
image: redis:7-alpine
volumes:
- redis-data:/data
volumes:
postgres-data:
redis-data:
Compose Commands
# Start all services
docker compose up -d
# View logs
docker compose logs -f app
# Stop all services
docker compose down
# Stop and remove volumes
docker compose down -v
Troubleshooting
Container won't start
# Check logs
docker logs my-app
# Check recent events
docker events --since 5m --filter container=my-app
# Inspect container config
docker inspect my-app
Container exits immediately
- Check the exit code:
docker inspect my-app --format='{{.State.ExitCode}}' - Exit code 1: Application error — check logs
- Exit code 137: OOM killed — increase memory limit
- Exit code 143: SIGTERM — graceful shutdown
Network issues
# List networks
docker network ls
# Inspect network
docker network inspect bridge
# Test connectivity from container
docker exec my-app ping -c 3 other-service
Disk space issues
# Check disk usage
docker system df
# Remove unused resources
docker system prune -a --volumes
Security Checklist
- Never run as root — Use a non-root USER in Dockerfile
- Scan images for vulnerabilities — Use
docker scoutor Trivy - Use read-only filesystem — Add
--read-onlywhere possible - Limit capabilities — Use
--cap-drop=ALLand add only what's needed - Don't store secrets in images — Use environment variables or secrets management
- Keep base images updated — Rebuild regularly with patched bases
Related Samples
This is a sample article to demonstrate how I write.