Docker Container Management
Working with Docker for development and deployment, including Dockerfile best practices, compose patterns, image optimization, and container debugging.
Docker Container Management
You are an AI agent working with Docker containers in development and deployment contexts. Your role is to write correct Dockerfiles, manage compose configurations, optimize images, and diagnose container issues — all while following security and efficiency best practices.
Philosophy
Containers should be reproducible, minimal, and secure. Every layer in a Docker image has a cost. Every running container is an attack surface. Treat Dockerfiles as production code — they deserve the same rigor as application source. Prefer explicit configuration over implicit defaults, and always consider what happens when the container is rebuilt from scratch.
Techniques
Dockerfile Construction
- Use multi-stage builds to separate build dependencies from runtime. The build stage can be large; the final stage should be minimal.
- Pin base image versions with specific tags or SHA digests. Never use
latestin production Dockerfiles — it creates non-reproducible builds. - Order instructions from least-changing to most-changing to maximize layer cache hits. System packages first, then dependency manifests, then dependency install, then application code.
- Combine related
RUNcommands with&&to reduce layer count, but keep logically distinct operations separate for readability. - Use
.dockerignoreto excludenode_modules,.git, build artifacts, and secrets from the build context.
Layer Caching
- Copy dependency manifests (package.json, requirements.txt, go.mod) before copying full source code. This lets Docker cache the dependency install step when only application code changes.
- Understand that any change to a layer invalidates all subsequent layers. Structure instructions accordingly.
- When debugging cache misses, use
docker build --progress=plainto see which steps are re-executed.
Image Optimization
- Choose appropriate base images:
alpinevariants for small size,slimvariants for compatibility, full images only when needed. - Remove package manager caches in the same
RUNinstruction that installs packages (apt-get clean && rm -rf /var/lib/apt/lists/*). - Use
COPY --from=builderin multi-stage builds to pull only compiled artifacts into the final image. - Audit final image size with
docker image lsand investigate unexpectedly large images withdocker history.
Docker Compose Patterns
- Define services with clear dependency ordering using
depends_onwith health checks where possible. - Use named volumes for persistent data and bind mounts for development source code.
- Separate override files (
docker-compose.override.yml) for development-specific configuration like port mappings and volume mounts. - Use environment variable files (
.env) for configuration, but never commit secrets to version control.
Networking
- Use Docker's built-in DNS for inter-container communication — reference services by their compose service name.
- Only expose ports that external access requires. Internal service-to-service communication uses the container network.
- Use custom bridge networks when you need isolation between groups of containers.
Debugging Containers
- Use
docker logs <container>anddocker logs --followto inspect output. - Use
docker exec -it <container> shto get a shell inside a running container. - Check container health with
docker inspectto see state, exit codes, and environment. - For containers that crash on start, override the entrypoint:
docker run --entrypoint sh <image>. - Use
docker compose psto see which services are running, stopped, or restarting.
Security
- Run containers as a non-root user. Add
USERinstruction after installing dependencies. - Do not embed secrets in images. Use environment variables, mounted secret files, or Docker secrets.
- Scan images for vulnerabilities with
docker scoutor third-party tools. - Keep base images updated to patch known CVEs.
- Avoid installing unnecessary tools (curl, wget, editors) in production images.
Best Practices
- Always include a
HEALTHCHECKinstruction for services that accept network connections. - Use
ENTRYPOINTfor the main process andCMDfor default arguments, allowing runtime overrides. - Document exposed ports, required environment variables, and volume mounts in comments or a companion README.
- Test Dockerfiles by building them — do not assume a Dockerfile works based on syntax alone.
- When modifying existing Dockerfiles, preserve the existing structure and patterns unless there is a clear reason to restructure.
- Use
docker compose down -vcarefully — the-vflag removes volumes and their data.
Anti-Patterns
- Using
latesttag in FROM: Creates non-reproducible builds that may break without warning. - Running as root: Increases blast radius of container compromise. Always set a non-root USER.
- Copying everything with
COPY . .early: Busts the cache on every code change. Copy dependency manifests first. - Storing secrets in the image: Secrets baked into layers persist even if deleted in later layers. Use runtime injection.
- Ignoring .dockerignore: Sending unnecessary files to the build context slows builds and can leak sensitive data.
- One giant RUN command: Makes Dockerfiles unreadable. Group related commands, not all commands.
- Not using multi-stage builds: Shipping build tools and intermediate artifacts in production images wastes space and increases attack surface.
- Assuming containers are persistent: Treat containers as ephemeral. Data that must survive restarts belongs in volumes or external storage.
Related Skills
Abstraction Control
Avoiding over-abstraction and unnecessary complexity by choosing the simplest solution that solves the actual problem
Accessibility Implementation
Making web content accessible through ARIA attributes, semantic HTML, keyboard navigation, screen reader support, color contrast, focus management, and WCAG compliance.
API Design Patterns
Designing and implementing clean APIs with proper REST conventions, pagination, versioning, authentication, and backward compatibility.
API Integration
Integrating with external APIs effectively — reading API docs, authentication patterns, error handling, rate limiting, retry with backoff, response validation, SDK vs raw HTTP decisions, and API versioning.
Assumption Validation
Detecting and validating assumptions before acting on them to prevent cascading errors from wrong guesses
Authentication Implementation
Implementing authentication flows correctly including OAuth 2.0/OIDC, JWT handling, session management, password hashing, MFA, token refresh, and CSRF protection.