container-plugin/skills/container-development/SKILL.md
Container development — Docker, multi-stage builds, Skaffold, non-root users, Alpine/slim images, security hardening. Use when working with Docker, Dockerfiles, docker-compose, or container security.
npx skillsauth add laurigates/claude-plugins container-developmentInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Expert knowledge for containerization and orchestration with focus on security-first, lean container images and 12-factor app methodology.
| Use this skill when... | Use a language-specific sibling (go-containers, nodejs-containers, python-containers) instead when... |
|---|---|
| Writing or optimizing language-agnostic Dockerfiles | Optimizing Go static binaries, Node.js Alpine builds, or Python slim images |
| Authoring multi-stage build patterns or 12-factor configuration | The image-size goal is dominated by language runtime choices (scratch, distroless, musl/glibc) |
| Hardening containers (non-root, minimal base, secrets) | Running Skaffold sync (skaffold-filesync) or OrbStack networking (skaffold-orbstack) |
| Composing services with Docker Compose | The work is purely a Skaffold pre-deploy test (skaffold-testing) |
Non-Root is MANDATORY: ALL production containers MUST run as non-root users. This is not optional.
Minimal Base Images: Use Alpine (~5MB) for Node.js/Go/Rust. Use slim (~50MB) for Python (musl compatibility issues with Alpine).
Multi-Stage Builds Required: Separate build and runtime environments. Build tools should NOT be in production images.
Container Image Construction
Container Orchestration
.dockerignore file1. Multi-Stage Builds (MANDATORY):
2. Minimal Base Images:
3. Non-Root Users (MANDATORY):
4. .dockerignore (MANDATORY):
.git, node_modules, __pycache__5. Layer Optimization:
&&CRITICAL: Before using base images, verify latest versions:
Use WebSearch or WebFetch to verify current versions.
For detailed language-specific optimization patterns, see the dedicated skills:
| Language | Skill | Key Optimization | Typical Reduction |
|----------|-------|------------------|-------------------|
| Go | go-containers | Static binaries, scratch/distroless | 846MB → 2.5MB (99.7%) |
| Node.js | nodejs-containers | Alpine, multi-stage, npm/yarn/pnpm | 900MB → 100MB (89%) |
| Python | python-containers | Slim (NOT Alpine), uv, venv | 1GB → 100MB (90%) |
Choose the right base image:
scratch or distroless/static (2-5MB)node:XX-alpine (50-150MB)python:XX-slim (80-120MB) - Never use Alpine for Python!nginx:XX-alpine (20-40MB)scratch or nginx:alpine (minimal)# Build stage - includes all build tools
FROM <language>:<version> AS builder
WORKDIR /app
# Copy dependency manifests first (better caching)
COPY package.json package-lock.json ./ # or go.mod, requirements.txt, etc.
# Install dependencies
RUN <install-command>
# Copy source code
COPY . .
# Build application
RUN <build-command>
# Runtime stage - minimal
FROM <minimal-base>
WORKDIR /app
# Create non-root user
RUN addgroup --gid 1001 appgroup && \
adduser --uid 1001 --gid 1001 --disabled-password appuser
# Copy only what's needed from builder
COPY --from=builder --chown=appuser:appuser /app/dist ./dist
USER appuser
EXPOSE <port>
HEALTHCHECK --interval=30s CMD <health-check-command>
CMD [<start-command>]
Security Requirements (Mandatory)
node:20.10-alpine), never latestTypical Impact of Full Optimization:
12-Factor App Principles
Container labels provide metadata for image discovery, linking, and documentation. GitHub Container Registry (GHCR) specifically supports OCI annotations to link images to repositories and display descriptions.
| Label | Purpose | Example |
|-------|---------|---------|
| org.opencontainers.image.source | Links image to repository (enables GHCR features) | https://github.com/owner/repo |
| org.opencontainers.image.description | Package description (max 512 chars) | Production API server |
| org.opencontainers.image.licenses | SPDX license identifier (max 256 chars) | MIT, Apache-2.0 |
| Label | Purpose | Example |
|-------|---------|---------|
| org.opencontainers.image.version | Semantic version | 1.2.3 |
| org.opencontainers.image.revision | Git commit SHA | abc1234 |
| org.opencontainers.image.created | Build timestamp (RFC 3339) | 2025-01-19T12:00:00Z |
| org.opencontainers.image.title | Human-readable name | My Application |
| org.opencontainers.image.vendor | Organization name | Forum Virium Helsinki |
| org.opencontainers.image.url | Project homepage | https://example.com |
| org.opencontainers.image.documentation | Documentation URL | https://docs.example.com |
# Static labels (set at build time)
LABEL org.opencontainers.image.source="https://github.com/owner/repo" \
org.opencontainers.image.description="Production API server" \
org.opencontainers.image.licenses="MIT" \
org.opencontainers.image.vendor="Forum Virium Helsinki"
# Dynamic labels (via build args)
ARG VERSION=dev
ARG BUILD_DATE
ARG VCS_REF
LABEL org.opencontainers.image.version="${VERSION}" \
org.opencontainers.image.created="${BUILD_DATE}" \
org.opencontainers.image.revision="${VCS_REF}"
docker build \
--label "org.opencontainers.image.source=https://github.com/owner/repo" \
--label "org.opencontainers.image.description=My container image" \
--label "org.opencontainers.image.licenses=MIT" \
--build-arg VERSION=1.2.3 \
--build-arg BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
--build-arg VCS_REF=$(git rev-parse --short HEAD) \
-t myapp:1.2.3 .
The docker/metadata-action automatically generates OCI labels from repository metadata:
- id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
labels: |
org.opencontainers.image.title=My Application
org.opencontainers.image.description=Production API server
org.opencontainers.image.vendor=Forum Virium Helsinki
- uses: docker/build-push-action@v6
with:
labels: ${{ steps.meta.outputs.labels }}
Auto-generated labels by metadata-action:
org.opencontainers.image.source (from repository URL)org.opencontainers.image.revision (from commit SHA)org.opencontainers.image.created (build timestamp)org.opencontainers.image.version (from tags/refs)Skaffold Preference
When building and testing containers, use these optimizations for faster feedback:
| Context | Command | Purpose |
|---------|---------|---------|
| Quick build | DOCKER_BUILDKIT=1 docker build --progress=plain -t app . | BuildKit with plain output |
| Build with cache | docker build --cache-from app:latest -t app:new . | Reuse layers from previous builds |
| Security scan | docker scout cves app:latest \| head -50 | Quick vulnerability check |
| Size analysis | docker images app --format "{{.Size}}" | Check image size |
| Layer inspection | docker history app:latest --human --no-trunc | Analyze layer sizes |
| Build without cache | docker build --no-cache --progress=plain -t app . | Force clean build |
| Test container | docker run --rm -it app:latest /bin/sh | Interactive testing |
| Quick health check | docker run --rm app:latest timeout 5 /health | Verify startup |
Build optimization flags:
--target=<stage>: Build specific stage only (faster iteration)--build-arg BUILDKIT_INLINE_CACHE=1: Enable inline cache--secret id=key,src=file: Mount secrets without including in imageFor detailed Dockerfile optimization techniques, orchestration patterns, security hardening, and Skaffold configuration, see REFERENCE.md.
Language-Specific Container Optimization:
go-containers - Go static binaries, scratch/distroless (846MB → 2.5MB)nodejs-containers - Node.js Alpine patterns, npm/yarn/pnpm (900MB → 100MB)python-containers - Python slim (NOT Alpine), uv/poetry (1GB → 100MB)/configure:container - Comprehensive container infrastructure validation/configure:dockerfile - Dockerfile-specific configuration/configure:workflows - GitHub Actions including container builds/configure:skaffold - Kubernetes development configurationtesting
Verify accumulated bug claims at upstream HEAD and dedup against trackers before filing issues. Use when filing upstream reports from backlogs, audit docs, or git-history findings.
documentation
Gate outward-bound text (upstream issues, docs, PR bodies) through isolated haiku fresh-reader critique before publishing. Use when an artifact must survive a reader with zero project context.
tools
Suggest improvements to SKILL.md content, descriptions, or tool config from eval results. Use when raising pass rates, fixing triggering, or iterating on a skill after evaluation.
tools
deadbranch CLI for stale-branch cleanup — dry-run preview, TUI or non-interactive delete, protects main/develop/WIP. Use when asked to clean up branches, prune branches, or remove stale branches.