| name | docker-helper |
| description | Docker operations including Dockerfile authoring, image builds, container lifecycle, networking, volumes, multi-stage builds, buildx, security hardening, and debugging. Use when asked to "build image", "run container", "write dockerfile", "docker compose", "optimize image", "debug container", "multi-platform build", "docker network", "docker volume", "scan image", "prune docker", or any container-related task. |
Docker Helper
Dockerfile Best Practices
Layer Caching and .dockerignore
Order instructions from least to most frequently changing. Copy dependency manifests before source code.
FROM node:20-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY . .
CMD ["node", "server.js"]
Always include a .dockerignore to reduce build context and prevent secret leaks:
node_modules
.git
.env
*.log
dist
__pycache__
.venv
Health Checks
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget -qO- http://localhost:3000/health || exit 1
Image Management
docker build -t myapp:latest .
docker build -t myapp:v1.2 -f Dockerfile.prod --build-arg NODE_ENV=production .
docker build --no-cache -t myapp:latest .
docker tag myapp:latest registry.example.com/myapp:v1.2
docker push registry.example.com/myapp:v1.2
docker pull registry.example.com/myapp:v1.2
docker images
docker images --filter "dangling=true"
docker image ls --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
docker history myapp:latest
docker rmi myapp:latest
docker image prune -a
Container Lifecycle
docker run -d --name myapp -p 8080:80 nginx
docker run -it --rm ubuntu bash
docker run -d --restart unless-stopped myapp
docker start myapp
docker stop myapp
docker restart myapp
docker rm myapp
docker rm -f myapp
docker ps
docker ps -a
docker logs myapp
docker logs -f --tail 200 myapp
docker logs --since 10m myapp
docker exec -it myapp bash
docker exec -it myapp sh
docker exec myapp cat /etc/os-release
Networking
docker network ls
docker network create mynet
docker run -d --name api --network mynet myapi:latest
docker run -d --name db --network mynet postgres:16
docker network connect mynet myapp
docker network disconnect mynet myapp
docker network inspect mynet
docker run -d -p 8080:80 nginx
docker run -d -p 127.0.0.1:8080:80 nginx
docker run -d -P nginx
docker run -d --network host nginx
Volumes and Bind Mounts
docker volume create mydata
docker run -d -v mydata:/var/lib/data myapp
docker run -d -v $(pwd)/src:/app/src myapp
docker run -d -v $(pwd)/config.yaml:/app/config.yaml:ro myapp
docker run -d --tmpfs /tmp:rw,size=64m myapp
docker volume ls
docker volume inspect mydata
docker volume rm mydata
docker cp myapp:/app/data.json ./
docker cp ./config.yaml myapp:/app/
Environment Variables and Secrets
docker run -e DATABASE_URL=postgres://user:pass@db:5432/app myapp
docker run --env-file .env myapp
BuildKit secrets (never stored in image layers):
docker build --secret id=npmrc,src=$HOME/.npmrc -t myapp .
# syntax=docker/dockerfile:1
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci
Multi-Stage Build Patterns
Go (scratch)
FROM golang:1.22-alpine AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /app .
FROM scratch
COPY --from=builder /app /app
ENTRYPOINT ["/app"]
Python
FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN python -m venv /opt/venv && /opt/venv/bin/pip install --no-cache-dir -r requirements.txt
FROM python:3.12-slim
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
WORKDIR /app
COPY . .
USER nobody
CMD ["python", "main.py"]
Node.js
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build && npm prune --omit=dev
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY package.json ./
RUN addgroup -g 1001 appgroup && adduser -S -u 1001 -G appgroup appuser
USER appuser
EXPOSE 3000
CMD ["node", "dist/server.js"]
Java
FROM eclipse-temurin:21-jdk AS builder
WORKDIR /app
COPY build.gradle settings.gradle gradlew ./
COPY gradle ./gradle
RUN ./gradlew dependencies --no-daemon
COPY src ./src
RUN ./gradlew bootJar --no-daemon
FROM eclipse-temurin:21-jre
COPY --from=builder /app/build/libs/*.jar app.jar
USER 1000
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]
Debugging Containers
docker inspect myapp
docker inspect --format '{{.State.Status}}' myapp
docker inspect --format '{{.State.ExitCode}}' myapp
docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' myapp
docker stats
docker stats myapp --no-stream
docker top myapp
docker diff myapp
docker events --filter container=myapp
docker run -it --rm --pid=container:myapp --network=container:myapp nicolaka/netshoot
Docker Buildx (Multi-Platform)
docker buildx create --name multibuilder --use
docker buildx build --platform linux/amd64,linux/arm64 -t myapp:latest --push .
docker buildx build --platform linux/amd64 -t myapp:latest --load .
docker buildx ls
docker buildx rm multibuilder
Image Optimization
| Base Image | Size | Shell | Use Case |
|---|
| ubuntu:22.04 | ~77 MB | Yes | General purpose |
| debian:bookworm-slim | ~52 MB | Yes | Smaller general purpose |
| alpine:3.19 | ~7 MB | Yes | Small images with shell |
| gcr.io/distroless/base | ~20 MB | No | Minimal attack surface |
| scratch | 0 MB | No | Static binaries (Go, Rust) |
- Combine RUN statements:
RUN apt-get update && apt-get install -y pkg && rm -rf /var/lib/apt/lists/*
- Remove caches in the same layer they are created.
- Use
docker history and dive to find large layers.
Security
# Non-root user
RUN addgroup -g 1001 appgroup && adduser -S -u 1001 -G appgroup appuser
USER appuser
docker run --read-only --tmpfs /tmp myapp
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE myapp
docker run --security-opt no-new-privileges myapp
docker run --memory 512m --cpus 1.0 myapp
Never use COPY or ENV for secrets. Use BuildKit secret mounts or runtime env vars.
Scanning with Trivy
trivy image myapp:latest
trivy image --severity HIGH,CRITICAL --exit-code 1 myapp:latest
trivy config Dockerfile
Cleanup Commands
docker container prune
docker image prune -a
docker volume prune
docker network prune
docker system prune -a --volumes
docker system df
Troubleshooting
Container Exits Immediately
docker logs myapp
docker inspect --format '{{.State.ExitCode}}' myapp
Port Conflicts
lsof -i :8080
docker run -d -p 9090:80 nginx
Permission Issues
COPY --chown=appuser:appgroup . /app
docker run -u $(id -u):$(id -g) -v $(pwd):/app myapp
Container Cannot Resolve Other Containers
Default bridge does not support DNS. Use a user-defined network:
docker network create mynet
docker run -d --name api --network mynet myapi
docker run -d --name db --network mynet postgres:16
Build Context Too Large
Add paths to .dockerignore, or specify a smaller context directory:
docker build -t myapp -f Dockerfile ./src