15 Prompts for Docker: From Dockerfile to Multi-Stage Builds

Introduction

Docker has become the de facto standard for containerization, used by 89% of organizations according to the 2025 Stack Overflow Survey. Yet many developers still struggle with writing efficient Dockerfiles, orchestrating multi-container applications with Compose, and optimizing image sizes. This collection of 15 ready-to-use prompts will help you master Docker — from crafting minimal Dockerfiles to debugging complex Compose stacks. Each prompt includes a specific task, a copy-paste command, and a real-world example. No fluff, just actionable content.

1. Generate a Minimal Dockerfile for a Node.js App

Task: Create a production-ready Dockerfile for a Node.js Express application using multi-stage builds.

Prompt:

# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .

# Stage 2: Production
FROM node:20-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app ./
EXPOSE 3000
CMD ["node", "server.js"]

Explanation: This uses Alpine Linux (5MB base) instead of full Node (over 100MB). Multi-stage keeps only production dependencies. The USER appuser improves security by avoiding root.

2. Optimize Image Size with .dockerignore

Task: Exclude unnecessary files from the Docker build context to reduce image size.

Prompt:

.git
node_modules
npm-debug.log
Dockerfile*
docker-compose*
README.md
.gitignore
.env

Example: A typical Node.js app without .dockerignore may send 50MB of node_modules to the Docker daemon. With the file above, context size drops to 2MB.

3. Write a Multi-Stage Build for a Python App

Task: Build a Python Flask app with dependencies compiled in a builder stage.

Prompt:

FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt

FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
EXPOSE 5000
CMD ["python", "app.py"]

Explanation: --user flag installs packages locally (not globally), making the final image smaller. The --no-cache-dir prevents pip from caching downloaded packages.

4. Create a Docker Compose File for a Full-Stack App

Task: Define a Compose file with a Node.js back end and a PostgreSQL database.

Prompt:

version: '3.8'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DB_HOST=db
      - DB_USER=user
      - DB_PASSWORD=secret
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres:15-alpine
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user"]
      interval: 10s
volumes:
  pgdata:

Explanation: depends_on with condition: service_healthy ensures the back end waits for PostgreSQL to be ready, eliminating race conditions.

5. Debug a Container with Interactive Shell

Task: Troubleshoot a failing container by launching an interactive shell.

Prompt:

docker run -it --rm --entrypoint sh myimage:latest

Example: If your container crashes on startup, run the command above to get a shell inside the image. Then manually execute ls, env, or cat /etc/nginx/nginx.conf to inspect the environment.

6. Use BuildKit for Faster Builds

Task: Enable BuildKit to leverage parallel builds and caching.

Prompt:

export DOCKER_BUILDKIT=1
export COMPOSE_DOCKER_CLI_BUILD=1
docker build --cache-from myimage:latest -t myimage:latest .

Explanation: BuildKit can cache intermediate layers from a previous build (even if pushed to a registry). The --cache-from flag reuses layers from a remote image, speeding up CI/CD pipelines by up to 70%.

7. Pin Base Image Versions

Task: Avoid unexpected updates by pinning exact image tags.

Prompt:

FROM node:20.11.0-alpine3.19

Explanation: Using node:20-alpine might pull 20.12.0 tomorrow, breaking your app. Always use a specific patch version like 20.11.0-alpine3.19. Check Docker Hub for available tags.

8. Limit Container Resources

Task: Prevent a container from consuming all host memory.

Prompt:

services:
  app:
    build: .
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          memory: 256M

Explanation: In Docker Compose, deploy.resources.limits restricts CPU and memory. Without limits, a memory leak in one container can crash the host. The reservations guarantee minimum resources.

9. Use Health Checks in Dockerfile

Task: Automatically restart unhealthy containers.

Prompt:

HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD curl --fail http://localhost:3000/health || exit 1

Example: If your app’s health endpoint returns non-200, Docker marks the container as unhealthy. Combined with restart: always in Compose, the container restarts automatically.

10. Reduce Image Layers with &&

Task: Combine multiple RUN commands into one layer.

Prompt:

RUN apt-get update && \
    apt-get install -y --no-install-recommends curl && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

Explanation: Each RUN creates a new layer. Combining them reduces the final image size and speeds up builds. The --no-install-recommends flag avoids installing unnecessary packages.

11. Use .dockerignore for Secrets

Task: Prevent secret files from being copied into the image.

Prompt:

.env
*.pem
secrets/

Example: If you forget to add .env to .dockerignore, your production database credentials end up in the image. Anyone who pulls the image can see them with docker history.

12. Set Non-Root User in Dockerfile

Task: Run the container as a non-root user for security.

Prompt:

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

Explanation: By default, Docker runs as root inside the container. If an attacker exploits a vulnerability, they get root access. Switching to appuser limits the damage. Official images like nginx:alpine already do this.

13. Use docker scout for Vulnerability Scanning

Task: Scan your image for known CVEs before deployment.

Prompt:

docker scout quickview myimage:latest

Example: Run this command to see a summary of vulnerabilities in your image. Docker Scout (integrated since Docker Desktop 4.12) compares your image against the National Vulnerability Database (NVD) and suggests fixes.

14. Bind Mount for Development

Task: Live-reload changes without rebuilding the image.

Prompt:

services:
  app:
    build: .
    volumes:
      - ./src:/app/src
    command: npm run dev

Explanation: Bind mounts sync your local src directory with the container. Changes you make on your host appear instantly inside the container, enabling hot-reload without docker build. Useful for development but never use in production.

15. Multi-Stage Build for a Golang App

Task: Build a tiny Go binary using multi-stage.

Prompt:

FROM golang:1.22 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/server .

FROM scratch
COPY --from=builder /app/server /server
EXPOSE 8080
CMD ["/server"]

Explanation: scratch is an empty image (0 bytes). Your final image contains only the compiled Go binary — no shell, no libraries. For a typical Go app, the image size drops from 800MB (golang image) to under 10MB.

Conclusion

These 15 prompts cover the most common Docker scenarios: building efficient images, orchestrating services with Compose, and debugging containers. Start by implementing the minimal Dockerfile for your language (Node.js, Python, Go), then add health checks and resource limits. Finally, integrate vulnerability scanning with docker scout to ensure your images are secure. Practice each prompt on a real project — the best way to learn Docker is by running containers daily. For further reading, consult the official Dockerfile best practices and Compose specification.

← All posts

Comments