← All skills
docker-development
Use when optimizing a Dockerfile, creating/improving docker-compose configs, implementing multi-stage builds, auditing container security, reducing image size, or asking for Docker best practices.
About this skill
Use when optimizing a Dockerfile, creating/improving docker-compose configs, implementing multi-stage builds, auditing container security, reducing image size, or asking for Docker best practices.
SKILL.md
docker-development.SKILL.mdPlace it in your Syntic skills folder. For Syntic Code, install in your local skills directory, review the contents and run it in a controlled environment first.
---
name: docker-development
description: Use when optimizing a Dockerfile, creating/improving docker-compose configs, implementing multi-stage builds, auditing container security, reducing image size, or asking for Docker best practices.
category: Engineering
version: 1.0.0
tools: []
---
# Docker Development
Turn bloated Dockerfiles into production-grade containers — smaller images, faster builds, secure containers, no guesswork. Covers Dockerfile optimization, docker-compose orchestration, multi-stage builds, and container security hardening as a set of concrete build decisions, not a tutorial.
**Use when:** optimizing a Dockerfile, creating or improving docker-compose configurations, implementing multi-stage builds, auditing container security, reducing image size, or asked for Docker best practices for a language/framework.
## Dockerfile optimization
Analyze the current Dockerfile: base image and its size, layer count (each RUN/COPY/ADD is one layer), and anti-patterns. Then apply this checklist:
**Base image** — use specific tags, never `:latest` in production; prefer slim/alpine variants over full debian/ubuntu; pin by digest (`image@sha256:...`) for CI reproducibility; match the base to actual runtime needs (don't ship `python:3.12` for a compiled binary).
**Layers** — combine related RUN commands with `&&`; order least-changing-first (dependencies before source code); clean the package-manager cache in the same RUN layer it was created in; use `.dockerignore`; separate build-time from runtime dependencies.
**Build cache** — copy dependency manifests (package.json, requirements.txt, go.mod) before source code; install dependencies in their own layer, separate from the code copy; use BuildKit cache mounts (`--mount=type=cache,target=/root/.cache`); never `COPY . .` before installing dependencies.
**Multi-stage builds** — stage 1 builds with the full SDK/build tools/dev deps; stage 2 runs on a minimal base with only production artifacts, `COPY --from=builder` only what's needed; the final image should contain no build tools, no source code, no dev dependencies.
Generate the optimized Dockerfile with inline comments explaining each decision and report the estimated size reduction.
## docker-compose configuration
Identify the services involved (application, database, cache, queue, reverse proxy), then apply:
**Services** — `depends_on` with `condition: service_healthy`; a healthcheck on every service; resource limits (`mem_limit`, `cpus`); named volumes for persistent data; pinned image versions.
**Networking** — explicit named networks instead of the default; separate frontend/backend networks; expose only ports that need external access; `internal: true` for backend-only networks.
**Environment** — `env_file` for secrets, never inline `environment:` values; `.env` gitignored, never committed; `${VAR:-default}` substitution; document every required variable.
**Dev vs. prod** — compose profiles or override files; dev uses bind mounts for hot reload with debug ports exposed; prod uses named volumes, no debug ports, `restart: unless-stopped`; keep dev-only config in `docker-compose.override.yml`.
Output the compose file with healthchecks/networks/volumes plus a `.env.example` documenting every required variable.
## Container security audit
Dockerfile-level checks:
| Check | Severity | Fix |
|---|---|---|
| Running as root | Critical | Add `USER nonroot` after creating the user |
| `:latest` tag | High | Pin to a specific version |
| Secrets in ENV/ARG | Critical | Use BuildKit secrets: `--mount=type=secret` |
| COPY with a broad glob | Medium | Specific paths + `.dockerignore` |
| Unnecessary EXPOSE | Low | Only expose ports the app actually uses |
| No HEALTHCHECK | Medium | Add one with an appropriate interval |
| Privileged instructions | High | Avoid `--privileged`, drop capabilities |
| Package cache retained | Low | Clean it in the same RUN layer |
Runtime checks: container running as root (Critical); writable root filesystem (Medium — use `read_only: true`); all capabilities retained (High — `cap_drop: [ALL]`, add back only what's needed); no resource limits (Medium); host network mode (High — use bridge/custom network); sensitive host mounts like `/etc` or `/var/run/docker.sock` (Critical — never in prod); no log driver with size limits configured (Low).
Report findings as counts by severity (Critical/High/Medium/Low) with the specific fix for each.
## Multi-stage build patterns
**Compiled language (Go/Rust/C++):** builder stage on a full SDK image (`golang:1.22-alpine`) compiles a static binary (`CGO_ENABLED=0`, stripped with `-ldflags="-s -w"`); runtime stage is `gcr.io/distroless/static-debian12`, copying only the binary and running as `nonroot`.
**Node.js/TypeScript:** a deps stage installs with `npm ci`; a build stage extends deps and runs `npm run build`; the runtime stage is a fresh `node:alpine`, copying only `dist/` and `node_modules` from the earlier stages, running as a non-root `appuser`.
**Python:** a builder stage installs requirements into a prefix directory (`pip install --prefix=/install`); the runtime stage is `python:3.12-slim`, copying only `/install` and the app code, running as a dedicated `appuser`.
## Base image decision tree
Compiled binary (Go/Rust/C) → `distroless/static` or `scratch`. Otherwise: need a shell for debugging → an alpine variant; need glibc (not musl) → a slim variant; need many OS packages → debian-slim; need only a few → alpine + `apk add`.
## Proactive triggers
Flag unprompted: `:latest` in use → suggest pinning; no `.dockerignore` → create one (`.git`, `node_modules`, `__pycache__`, `.env` at minimum); `COPY . .` before dependency install → cache-bust, reorder; running as root → add USER, no production exceptions; secrets in ENV/ARG → move to BuildKit secret mounts; image over 1GB → multi-stage build required; no healthcheck → add one for orchestrator lifecycle management; `apt-get` without cleanup in the same layer → add `rm -rf /var/lib/apt/lists/*` to that RUN.
**Cross-references:** broader CI/CD pipeline and infrastructure work belongs to a DevOps skill; application-level security threats belong to an application-security skill; this skill covers only the container layer.
Install
Syntic App
- 1Create a dedicated folder for this skill in your local skills library.
- 2Place SKILL.md into that folder.
- 3Restart Syntic and invoke this skill on matching tasks.
Syntic Code (CLI)
- 1Save SKILL.md in your local Syntic Code skills directory.
- 2Keep related files in the same skill folder.
- 3Run in a safe environment and validate outputs.