From devops-skills
Generates optimized multi-stage Dockerfiles, .dockerignore, for Node.js, Python, Go, Java apps with security hardening, layer caching, validation, and error fixes.
npx claudepluginhub akin-ozer/cc-devops-skills --plugin devops-skillsThis skill uses the workspace's default tool permissions.
This skill provides a comprehensive workflow for generating production-ready Dockerfiles with security, optimization, and best practices built-in. Generates multi-stage builds, security-hardened configurations, and optimized layer structures with automatic validation and iterative error fixing.
examples/example.dockerignoreexamples/golang-distroless.Dockerfileexamples/java-springboot.Dockerfileexamples/nextjs-production.Dockerfileexamples/nodejs-multistage.Dockerfileexamples/python-fastapi.Dockerfilereferences/language_specific_guides.mdreferences/multistage_builds.mdreferences/optimization_patterns.mdreferences/security_best_practices.mdscripts/generate_dockerignore.shscripts/generate_golang.shscripts/generate_java.shscripts/generate_nodejs.shscripts/generate_python.shscripts/test_generator.shSearches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
This skill provides a comprehensive workflow for generating production-ready Dockerfiles with security, optimization, and best practices built-in. Generates multi-stage builds, security-hardened configurations, and optimized layer structures with automatic validation and iterative error fixing.
Key Features:
dockerfile-validator for validationInvoke this skill when:
Use this skill immediately when the request contains phrasing like:
dockerfile-validator instead)Run these stages in order, and do not skip a stage unless the skip reason is reported in the final output.
.dockerignore.dockerfile-validator or fallback local tools.Stop conditions for stage 5:
Consult these files directly by path as needed:
references/security_best_practices.md for non-root users, secret handling, base image hardening, vulnerability scanning.references/optimization_patterns.md for multi-stage strategy, cache optimization, layer reduction, BuildKit cache mounts.references/language_specific_guides.md for language/framework runtime and package-manager patterns.references/multistage_builds.md for advanced stage-splitting and artifact-copy patterns.Follow this workflow when generating Dockerfiles. Adapt based on user needs:
Objective: Understand what needs to be containerized and gather all necessary information.
Information to Collect:
Application Details:
Dependencies:
Application Configuration:
Build Requirements:
Production Requirements:
Use AskUserQuestion if information is missing or unclear.
Example Questions:
- What programming language and version is your application using?
- What is the main entry point to run your application?
- Does your application expose any ports? If so, which ones?
- Do you need any system dependencies beyond the base language runtime?
- Does your application need a health check endpoint?
Objective: Research framework-specific containerization patterns and best practices.
When to Perform This Stage:
Research Process (strict fallback chain):
Read local references first (required):
references/security_best_practices.mdreferences/optimization_patterns.mdreferences/language_specific_guides.mdUse Context7 docs lookup when local references are insufficient (preferred external source):
Use mcp__context7__resolve-library-id with the framework name
Then use mcp__context7__query-docs with query:
"docker deployment production build"
Use web search only if Context7 is unavailable or missing needed details:
"<framework>" "<version>" dockerfile production deployment best practices
If external lookup is unavailable (offline/tooling limits):
Extract only actionable data:
Objective: Create a production-ready, multi-stage Dockerfile following best practices.
Core Principles:
Multi-Stage Builds (REQUIRED for compiled languages, RECOMMENDED for all):
Security Hardening (REQUIRED):
Layer Optimization (REQUIRED):
Production Readiness (REQUIRED):
Language-Specific Templates:
Build-stage dependency rule: If the application has a build step (TypeScript, Vite, Webpack, etc.), install all dependencies in the builder stage (omit
--only=production) and prune dev deps after the build. Using--only=productionbefore a build step will causenpm run buildto fail because dev tools are not installed.
# syntax=docker/dockerfile:1
# Build stage — installs all deps so build tools (tsc, vite, etc.) are available,
# then prunes dev deps so the production stage only ships what is needed at runtime.
FROM node:20-alpine AS builder
WORKDIR /app
# Copy dependency files for caching
COPY package*.json ./
# Install ALL dependencies (including devDependencies required by the build step)
RUN npm ci && \
npm cache clean --force
# Copy application code
COPY . .
# Build application and prune dev dependencies
RUN npm run build && \
npm prune --production
# Production stage
FROM node:20-alpine AS production
WORKDIR /app
# Set production environment
ENV NODE_ENV=production
# Create non-root user
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
# Copy pruned node_modules and built application from builder
COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nodejs:nodejs /app .
# Switch to non-root user
USER nodejs
# Expose port
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node -e "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
# Start application
CMD ["node", "index.js"]
Simple app (no build step): If there is no compilation or bundling, install only production deps in the builder stage and copy source from the host context:
RUN npm ci --only=production && npm cache clean --force ... COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules COPY --chown=nodejs:nodejs . .
# syntax=docker/dockerfile:1
# Build stage
FROM python:3.12-slim AS builder
WORKDIR /app
# Install build dependencies
# hadolint ignore=DL3008
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
&& rm -rf /var/lib/apt/lists/*
# Copy dependency files
COPY requirements.txt .
# Install Python dependencies
RUN pip install --no-cache-dir --user -r requirements.txt
# Production stage
FROM python:3.12-slim AS production
WORKDIR /app
# Create non-root user
RUN useradd -m -u 1001 appuser
# Copy dependencies from builder
COPY --from=builder /root/.local /home/appuser/.local
# Copy application code
COPY --chown=appuser:appuser . .
# Update PATH and set Python production env vars
# PYTHONUNBUFFERED=1 ensures stdout/stderr are flushed immediately (essential for container logs)
# PYTHONDONTWRITEBYTECODE=1 prevents writing .pyc files to disk
ENV PATH=/home/appuser/.local/bin:$PATH \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1
# Switch to non-root user
USER appuser
# Expose port
EXPOSE 8000
# Health check (adjust endpoint as needed)
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health').read()" || exit 1
# Start application
CMD ["python", "app.py"]
# syntax=docker/dockerfile:1
# Build stage
FROM golang:1.21-alpine AS builder
WORKDIR /app
# Copy go mod files
COPY go.mod go.sum ./
RUN go mod download
# Copy source code
COPY . .
# Build the application
RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags="-s -w" -o main .
# Production stage (using distroless for minimal image)
# gcr.io/distroless/static-debian12 IS a specific tag; hadolint DL3006 is a
# false positive for non-Docker-Hub registries.
# hadolint ignore=DL3006
FROM gcr.io/distroless/static-debian12 AS production
WORKDIR /
# Copy binary from builder
COPY --from=builder /app/main /main
# Expose port
EXPOSE 8080
# HEALTHCHECK is not supported in distroless images (no shell available)
# Switch to non-root user (distroless runs as nonroot by default)
USER nonroot:nonroot
# Start application
ENTRYPOINT ["/main"]
# syntax=docker/dockerfile:1
# Build stage
FROM eclipse-temurin:21-jdk-jammy AS builder
WORKDIR /app
# Copy Maven wrapper and pom.xml
COPY mvnw pom.xml ./
COPY .mvn .mvn
# Download dependencies (cached layer)
RUN ./mvnw dependency:go-offline
# Copy source code
COPY src ./src
# Build application
RUN ./mvnw clean package -DskipTests && \
mv target/*.jar target/app.jar
# Production stage (using JRE instead of JDK)
FROM eclipse-temurin:21-jre-jammy AS production
WORKDIR /app
# Install healthcheck dependency and create non-root user
# hadolint ignore=DL3008
RUN apt-get update && apt-get install -y --no-install-recommends curl && \
rm -rf /var/lib/apt/lists/* && \
useradd -m -u 1001 appuser
# Copy JAR from builder
COPY --from=builder --chown=appuser:appuser /app/target/app.jar ./app.jar
# Switch to non-root user
USER appuser
# Expose port
EXPOSE 8080
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
CMD curl -f http://localhost:8080/actuator/health || exit 1
# Start application
ENTRYPOINT ["java", "-jar", "app.jar"]
Selection Logic:
Always Include:
# syntax=docker/dockerfile:1Objective: Create comprehensive .dockerignore to reduce build context and prevent secret leaks.
Always create .dockerignore with generated Dockerfile.
Standard .dockerignore Template:
# Git
.git
.gitignore
.gitattributes
# CI/CD
.github
.gitlab-ci.yml
.travis.yml
.circleci
# Documentation
README.md
CHANGELOG.md
CONTRIBUTING.md
LICENSE
*.md
docs/
# Docker
Dockerfile*
docker-compose*.yml
.dockerignore
# Environment
.env
.env.*
*.local
# Logs
logs/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Dependencies (language-specific - add as needed)
node_modules/
__pycache__/
*.pyc
*.pyo
*.pyd
.Python
venv/
.venv/
target/
*.class
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store
# Testing
coverage/
.coverage
*.cover
.pytest_cache/
.tox/
test-results/
# Build artifacts
dist/
build/
*.egg-info/
Customize based on language:
node_modules/, npm-debug.log, yarn-error.log__pycache__/, *.pyc, .venv/, .pytest_cache/vendor/, *.exe, *.testtarget/, *.class, *.jar (except final artifact)dockerfile-validatorObjective: Ensure generated Dockerfile follows best practices and has no unresolved critical findings.
REQUIRED: Always run validation after generation.
Primary path (preferred):
dockerfile-validator.error, warning, info).Fallback path (if skill invocation is unavailable):
bash ../dockerfile-validator/scripts/dockerfile-validate.sh Dockerfile
hadolint Dockerfile
checkov -f Dockerfile --framework dockerfile
Expected validator stages:
[1/4] Syntax Validation (hadolint)
[2/4] Security Scan (Checkov)
[3/4] Best Practices Validation
[4/4] Optimization Analysis
Objective: Apply deterministic fix loops with auditable iteration records.
Loop rules (required):
error exists, apply fixes and re-run validation.error remains, orwarning, either fix it or mark it as intentional deviation with justification.Iteration log format (required):
| Iteration | Command/Path Used | Errors | Warnings | Fixes Applied | Result |
|---|---|---|---|---|---|
| 1 | dockerfile-validator or fallback command | N | N | short summary | pass/fail |
| 2 | ... | N | N | short summary | pass/fail |
| 3 | ... | N | N | short summary | pass/fail |
Common fixes:
ADD with COPY where archive/url behavior is not neededObjective: Deliver runnable artifacts plus an auditable report.
Deliverables (required):
.dockerignore (comprehensive)Intentional deviation report (required when any finding is not fixed):
| ID | Rule/Check | Severity | Decision | Justification | Risk | Mitigation | Expiry/Review Date |
|---|---|---|---|---|---|---|---|
| DEV-001 | e.g., DL3059 | warning | accepted | build step readability requirement | minor layer overhead | revisit after refactor | YYYY-MM-DD |
Usage instructions template:
# Build image
docker build -t myapp:1.0 .
# Run container
docker run -p 3000:3000 myapp:1.0
# Probe health endpoint (if exposed)
curl http://localhost:3000/health
Optimization metrics (required):
## Optimization Metrics
| Metric | Estimate |
|--------|----------|
| Image Size | ~150MB (vs ~500MB without multi-stage, 70% reduction) |
| Build Cache | Layer caching enabled for dependencies |
| Security | Non-root user, minimal base image, no secrets |
Language-specific size estimates:
Next steps (required):
## Next Steps
- [ ] Test the build locally: `docker build -t myapp:1.0 .`
- [ ] Run and verify the container works as expected
- [ ] Update CI/CD pipeline to use the new Dockerfile
- [ ] Consider BuildKit cache mounts for faster builds (see references/optimization_patterns.md)
- [ ] Set up automated vulnerability scanning with `docker scout` or `trivy`
- [ ] Push to registry and deploy
The scripts/ directory contains standalone bash scripts for manual Dockerfile generation outside of this skill:
generate_nodejs.sh - CLI tool for Node.js Dockerfilesgenerate_python.sh - CLI tool for Python Dockerfilesgenerate_golang.sh - CLI tool for Go Dockerfilesgenerate_java.sh - CLI tool for Java Dockerfilesgenerate_dockerignore.sh - CLI tool for .dockerignore generationPurpose: These scripts are reference implementations and manual tools for users who want to generate Dockerfiles via command line without using skill invocation. They demonstrate the same best practices embedded in this skill.
When using this skill: Codex generates Dockerfiles directly using the templates and patterns documented in this SKILL.md, rather than invoking these scripts. The templates in this document are the authoritative source.
Script usage example:
# Manual Dockerfile generation
cd devops-skills-plugin/skills/dockerfile-generator/scripts
./generate_nodejs.sh --version 20 --port 3000 --output Dockerfile
Node/Python entrypoint flags (script mode):
| Flag | Purpose | Notes |
|---|---|---|
--entry | Legacy shorthand entrypoint | Simple whitespace split only. Quoted values are rejected. |
--entry-cmd | Preferred command/executable | Use with repeated --entry-arg for exact argv control. |
--entry-arg | Preferred argument value | Repeat for each argument; spaces are preserved per arg. |
# Recommended for arguments containing spaces
./generate_nodejs.sh \
--entry-cmd node \
--entry-arg server.js \
--entry-arg --message \
--entry-arg "hello world"
Use Specific Tags:
# Bad
FROM node:alpine
# Good
FROM node:20-alpine
# Better (with digest for reproducibility)
FROM node:20-alpine@sha256:abc123...
Run as Non-Root:
# Create user
RUN addgroup -g 1001 -S appgroup && \
adduser -S appuser -u 1001 -G appgroup
# Switch to user before CMD
USER appuser
Use Minimal Base Images:
Never Hardcode Secrets:
# Bad
ENV API_KEY=secret123
# Good - use build secrets
# docker build --secret id=api_key,src=.env
RUN --mount=type=secret,id=api_key \
API_KEY=$(cat /run/secrets/api_key) ./configure
Layer Caching:
# Copy dependency files first
COPY package.json package-lock.json ./
RUN npm ci
# Copy application code last
COPY . .
Combine RUN Commands:
# Bad (creates 3 layers)
RUN apt-get update
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*
# Good (creates 1 layer)
RUN apt-get update && \
apt-get install -y --no-install-recommends curl && \
rm -rf /var/lib/apt/lists/*
Multi-Stage Builds:
# Build stage - can be large
FROM node:20 AS builder
WORKDIR /app
COPY . .
RUN npm install && npm run build
# Production stage - minimal
FROM node:20-alpine
COPY --from=builder /app/dist ./dist
CMD ["node", "dist/index.js"]
Health Checks:
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
Proper Signals:
# Use exec form for proper signal handling
CMD ["node", "server.js"] # Good
CMD node server.js # Bad (no signal forwarding)
Metadata:
LABEL maintainer="team@example.com" \
version="1.0.0" \
description="My application"
# syntax=docker/dockerfile:1
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
USER nextjs
EXPOSE 3000
CMD ["npm", "start"]
# syntax=docker/dockerfile:1
FROM python:3.12-slim AS builder
WORKDIR /app
# hadolint ignore=DL3008
RUN apt-get update && apt-get install -y --no-install-recommends gcc && \
rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
FROM python:3.12-slim
WORKDIR /app
RUN useradd -m -u 1001 appuser
COPY --from=builder /root/.local /home/appuser/.local
COPY --chown=appuser:appuser . .
ENV PATH=/home/appuser/.local/bin:$PATH \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1
USER appuser
EXPOSE 8000
HEALTHCHECK CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')" || exit 1
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
# syntax=docker/dockerfile:1
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o /bin/app
FROM scratch
COPY --from=builder /bin/app /app
ENTRYPOINT ["/app"]
Use Case: Build images that work on both AMD64 and ARM64 architectures (e.g., x86 servers and Apple Silicon Macs).
Enable BuildX:
# BuildX is included in Docker Desktop by default
# For Linux, ensure BuildX is installed
docker buildx version
Create Multi-Platform Images:
# Build for multiple platforms
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t myapp:latest \
--push \
.
# Build and load for current platform (testing)
docker buildx build \
--platform linux/amd64 \
-t myapp:latest \
--load \
.
Dockerfile Considerations:
# Most Dockerfiles work across platforms automatically
# Use platform-specific base images when needed
FROM --platform=$BUILDPLATFORM node:20-alpine AS builder
# Access build arguments for platform info
ARG TARGETPLATFORM
ARG BUILDPLATFORM
RUN echo "Building on $BUILDPLATFORM for $TARGETPLATFORM"
When to Use:
Use Case: Generate SBOM for supply chain security and compliance (increasingly required in 2025).
Generate SBOM During Build:
# Generate SBOM with BuildKit (Docker 24.0+)
docker buildx build \
--sbom=true \
-t myapp:latest \
.
# SBOM is attached as attestation to the image
# View SBOM
docker buildx imagetools inspect myapp:latest --format "{{ json .SBOM }}"
Generate SBOM from Existing Image:
# Using Syft
syft myapp:latest -o json > sbom.json
# Using Docker Scout
docker scout sbom myapp:latest
SBOM Benefits:
Integration with CI/CD:
# GitHub Actions example
- name: Build with SBOM
run: |
docker buildx build \
--sbom=true \
--provenance=true \
-t myapp:latest \
--push \
.
Use Case: Dramatically faster builds by persisting package manager caches across builds.
Already covered in detail in references/optimization_patterns.md.
Quick reference:
# syntax=docker/dockerfile:1
# NPM cache mount (30-50% faster builds)
RUN --mount=type=cache,target=/root/.npm \
npm ci
# Go module cache
RUN --mount=type=cache,target=/go/pkg/mod \
go mod download
# Pip cache
RUN --mount=type=cache,target=/root/.cache/pip \
pip install -r requirements.txt
Missing dependency files:
Unknown framework:
Validation failures:
This skill works well in combination with:
dockerfile-validator (or explicit fallback checks)Mark the task done only when all items below are true:
.dockerignore are generated.dockerfile-validator or documented fallback commands.error findings.warning has either a fix or an intentional-deviation report row.This skill is based on comprehensive research from authoritative sources:
Official Docker Documentation:
Security Guidelines:
Optimization Resources: