Create Dockerfile

SkillCloud & infra

Create general-purpose Dockerfiles for Node.js, Python, Go, Rust, and Java projects. Covers base image selection, dependency installation, user permissions, COPY patterns, ENTRYPOINT vs CMD, and .dockerignore. Use when containerizing an application for the first time, creating a consistent build/runtime environment, preparing an app for cloud deployment or Docker Compose, or when no existing Dockerfile is present in the project.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Create Dockerfile skill

What this skill tells your AI

The instructions your AI receives, as published by pjt222/agent-almanac in skills/create-dockerfile/SKILL.md and read by ahel’s review.

Write a production-ready Dockerfile for general-purpose application projects.

When to Use

  • Containerizing a Node.js, Python, Go, Rust, or Java application
  • Creating a consistent build/runtime environment
  • Preparing an application for cloud deployment or Docker Compose
  • No existing Dockerfile in the project

Inputs

  • Required: Project language and entry point (e.g., npm start, python app.py)
  • Required: Dependency manifest (package.json, requirements.txt, go.mod, Cargo.toml, pom.xml)
  • Optional: Target environment (development or production)
  • Optional: Exposed ports

Procedure

Step 1: Choose Base Image

LanguageDev ImageProd ImageSize
Node.jsnode:22-bookwormnode:22-bookworm-slim~200MB
Pythonpython:3.12-bookwormpython:3.12-slim-bookworm~150MB
Gogolang:1.23-bookwormgcr.io/distroless/static~2MB
Rustrust:1.82-bookwormdebian:bookworm-slim~80MB
Javaeclipse-temurin:21-jdkeclipse-temurin:21-jre~200MB

Expected: Select the slim/distroless variant for production images.

Step 2: Write Dockerfile (by language)

Node.js
FROM node:22-bookworm-slim

RUN groupadd -r appuser && useradd -r -g appuser -m appuser

WORKDIR /app

COPY package.json package-lock.json ./
RUN npm ci --omit=dev

COPY . .

USER appuser
EXPOSE 3000
CMD ["node", "src/index.js"]
Python
FROM python:3.12-slim-bookworm

RUN groupadd -r appuser && useradd -r -g appuser -m appuser

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

USER appuser
EXPOSE 8000
CMD ["python", "app.py"]
Go
FROM golang:1.23-bookworm AS builder

WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /app/server ./cmd/server

FROM gcr.io/distroless/static
COPY --from=builder /app/server /server
EXPOSE 8080
ENTRYPOINT ["/server"]
Rust
FROM rust:1.82-bookworm AS builder

WORKDIR /src
COPY Cargo.toml Cargo.lock ./
RUN mkdir src && echo "fn main() {}" > src/main.rs && cargo build --release && rm -rf src

COPY . .
RUN touch src/main.rs && cargo build --release

FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /src/target/release/myapp /usr/local/bin/myapp
EXPOSE 8080
ENTRYPOINT ["myapp"]
Java (Maven)
FROM eclipse-temurin:21-jdk AS builder

WORKDIR /src
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn package -DskipTests

FROM eclipse-temurin:21-jre
COPY --from=builder /src/target/*.jar /app/app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app/app.jar"]

Expected: docker build -t myapp . completes without errors.

On failure: Check base image availability and dependency installation commands.

Step 3: ENTRYPOINT vs CMD

DirectivePurposeOverride
ENTRYPOINTFixed executableOverride with --entrypoint
CMDDefault argumentsOverride with trailing args
BothENTRYPOINT + default args via CMDArgs override CMD only

Use ENTRYPOINT for compiled binaries with a single purpose. Use CMD for interpreted languages where you might want docker run myapp bash.

Step 4: Create .dockerignore

.git
.gitignore
node_modules
__pycache__
*.pyc
target/
.env
.env.*
*.md
!README.md
.vscode
.idea
Dockerfile
docker-compose*.yml

Expected: Build context excludes development artifacts.

Step 5: Add Non-Root User

Always run as non-root in production:

RUN groupadd -r appuser && useradd -r -g appuser -m appuser
USER appuser

For distroless images, use the built-in nonroot user:

FROM gcr.io/distroless/static:nonroot
USER nonroot

Step 6: Build and Verify

docker build -t myapp:latest .
docker run --rm myapp:latest
docker image inspect myapp:latest --format '{{.Size}}'

Expected: Container starts, responds on the expected port, runs as non-root.

On failure: Check logs with docker logs. Verify WORKDIR, COPY paths, and exposed ports.

Validation

  • docker build completes without errors
  • Container starts and application responds
  • .dockerignore excludes unnecessary files
  • Application runs as non-root user
  • Dependencies are copied before source code (cache efficiency)
  • No secrets or .env files baked into the image

Common Pitfalls

  • COPY before dependency install: Invalidates the dependency cache on every code change. Always copy the manifest file first.
  • Running as root: Default Docker user is root. Always add a non-root user for production.
  • Missing .dockerignore: Sending node_modules or .git into the build context wastes time and disk.
  • Using latest tag for base images: Pin to specific versions (e.g., node:22.11.0) for reproducibility.
  • Forgetting --no-cache-dir: Python pip caches packages by default, bloating the image.
  • ADD vs COPY: Use COPY unless you need URL download or tar extraction (ADD auto-extracts).

Related Skills

  • create-r-dockerfile - R-specific Dockerfile using rocker images
  • create-multistage-dockerfile - multi-stage patterns for minimal production images
  • optimize-docker-build-cache - advanced caching strategies
  • setup-compose-stack - orchestrate the containerized app with other services

Signals

GitHub stars
32
Forks
4
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
create-dockerfile
Source
github.com/pjt222/agent-almanac