10 Expert Prompts for Docker: From Dockerfile to Multi-Stage Builds and Image Optimization
Docker has become the de facto standard for containerization in modern DevOps workflows. Whether you are building microservices, deploying machine learning models, or running development environments, knowing how to craft efficient Dockerfiles and Compose files is critical. This article provides ten ready‑to‑use prompts that cover the entire lifecycle — from writing your first Dockerfile to optimizing multi‑stage builds and orchestrating multi‑container applications with Docker Compose.
Each prompt is designed to be copy‑pasted into your terminal or CI/CD pipeline, with explanations and practical examples. By the end, you will have a toolbox of prompts that save time, reduce image sizes, and enforce best practices.
1. The Minimal Secure Dockerfile (Alpine + Non‑Root User)
Prompt:
FROM alpine:3.20
RUN adduser -D appuser
USER appuser
WORKDIR /app
COPY --chown=appuser:appuser . .
CMD ["/bin/sh"]
Explanation: This prompt creates a minimal, secure base image. Using alpine:3.20 keeps the image under 10 MB. The adduser -D appuser command creates a non‑root user, mitigating privilege escalation risks. The USER appuser directive ensures all subsequent commands run without root. WORKDIR sets the working directory, and COPY --chown transfers files with correct ownership. This pattern is recommended by Docker’s official security guidelines.
Example use case: A simple static site or a script that does not need root privileges. For instance, a Python web app can be built on top of this base.
2. Multi‑Stage Build for Go Application
Prompt:
# Stage 1: Build
FROM golang:1.22-alpine AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /app .
# Stage 2: Run
FROM alpine:3.20
RUN adduser -D appuser
USER appuser
WORKDIR /app
COPY --from=builder /app .
CMD ["./app"]
Explanation: Multi‑stage builds separate the build environment from the runtime environment. The first stage uses the full Go image to compile the binary, downloading dependencies and building the application. The second stage copies only the compiled binary into a minimal Alpine image. This reduces the final image from ~800 MB to under 20 MB. This technique is documented in the official Docker documentation under “Use multi‑stage builds.”
Example use case: Any compiled language (Rust, C, Go). The same pattern works for Java with a Maven/Gradle build stage and a JRE‑based runtime.
3. Optimized Python Dockerfile with Poetry and .dockerignore
Prompt:
FROM python:3.12-slim
WORKDIR /app
COPY pyproject.toml poetry.lock ./
RUN pip install --no-cache-dir poetry && \
poetry config virtualenvs.create false && \
poetry install --no-dev --no-interaction --no-ansi
COPY . .
CMD ["python", "main.py"]
Explanation: This prompt leverages Poetry for dependency management. Copying only pyproject.toml and poetry.lock first allows Docker to cache the dependency layer; subsequent code changes do not trigger a full reinstall. The --no-cache-dir flag reduces image size. The .dockerignore file (not shown) should exclude __pycache__, .git, and venv to avoid sending unnecessary files to the Docker daemon. According to Docker’s best practices, this layering strategy can cut build times by 50–70%.
Example use case: Python microservices, FastAPI apps, or Django projects where dependency installation is the bottleneck.
4. Docker Compose for a Web App with PostgreSQL and Redis
Prompt:
version: "3.9"
services:
web:
build: .
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/mydb
- REDIS_URL=redis://cache:6379
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 5s
timeout: 3s
retries: 3
cache:
image: redis:7-alpine
ports:
- "6379:6379"
Explanation: This Compose file defines three services: a web application built from the current directory, a PostgreSQL database, and a Redis cache. The healthcheck on db ensures the web service waits until the database is ready. Using depends_on with conditions prevents race conditions. Environment variables are passed to the web service to connect to the other containers via Docker’s internal DNS (service names). This approach is standard for local development and can be extended to production with minor changes (e.g., adding secrets).
Example use case: A typical Django/Flask application that requires a relational database and a caching layer.
5. Layer Caching Optimization: Copy Dependencies First
Prompt:
FROM node:20-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --only=production
COPY . .
CMD ["node", "server.js"]
Explanation: Docker builds images layer by layer. By copying dependency manifests (package.json, package-lock.json) before the rest of the source code, Docker can cache the npm ci layer. Only when dependencies change does this layer rebuild. For large Node.js projects, this can reduce rebuild times from minutes to seconds. The official Docker documentation recommends this pattern for interpreted languages.
Example use case: Any Node.js, Ruby, PHP, or Python project where code changes are frequent but dependencies are stable.
6. Image Size Reduction with .dockerignore
Prompt:
.git
node_modules
__pycache__
*.log
.env
.DS_Store
Explanation: The .dockerignore file tells Docker which files to exclude from the build context. Without it, the entire project directory is sent to the Docker daemon, including node_modules (often hundreds of MB), .git history, and local environment files. This prompt reduces the build context size by 90% or more, speeding up builds and reducing the chance of cache invalidation. Docker’s official documentation strongly advises always creating a .dockerignore.
Example use case: Every Docker project, regardless of language. Add this file at the root of your project.
7. Running a One‑Shot Container (Data Migration Script)
Prompt:
docker run --rm \
-v $(pwd)/migrations:/migrations \
--network=host \
myapp:latest python /migrations/run.py
Explanation: The --rm flag automatically removes the container after execution. The -v mount binds a local directory into the container, allowing the migration script to access files. --network=host gives the container direct access to the host’s network stack, useful for connecting to local databases. This pattern is ideal for one‑time tasks like database migrations, data seeding, or cron jobs.
Example use case: Running Alembic or Prisma migrations before deploying a new version of an application.
8. Health Check for a Custom Service
Prompt:
FROM nginx:1.25-alpine
COPY . /usr/share/nginx/html
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD wget -qO- http://localhost/ || exit 1
Explanation: The HEALTHCHECK instruction tells Docker how to test if the container is working. Here, it uses wget to request the root page every 30 seconds. If the request fails three times, Docker marks the container as unhealthy. This is critical for orchestration tools like Docker Swarm or Kubernetes (where it maps to liveness probes). Without health checks, a container with a hung process would still be considered “running.”
Example use case: Web servers, API gateways, or any service where you need automatic recovery.
9. Multi‑Container Logging with Docker Compose and Fluentd
Prompt:
version: "3.9"
services:
fluentd:
image: fluent/fluentd:v1.16
ports:
- "24224:24224"
- "24224:24224/udp"
volumes:
- ./fluentd.conf:/fluentd/etc/fluentd.conf
app:
build: .
logging:
driver: fluentd
options:
fluentd-address: localhost:24224
tag: app.{{.Name}}
Explanation: This Compose file sets up a centralized logging system. The fluentd service collects logs from all other containers. The app service uses the fluentd log driver, sending logs to the Fluentd aggregator. This pattern avoids writing logs to disk inside containers and allows central search (e.g., with Elasticsearch). Docker’s logging drivers are documented in the official Docker engine reference.
Example use case: Production deployments where log aggregation is required for debugging and monitoring.
10. Multi‑Stage Build for a Java Spring Boot Application
Prompt:
# Stage 1: Build with Maven
FROM maven:3.9-eclipse-temurin-21 AS build
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn package -DskipTests -B
# Stage 2: Run with JRE
FROM eclipse-temurin:21-jre-alpine
RUN adduser -D appuser
USER appuser
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]
Explanation: For Java applications, the build stage uses the full Maven JDK image to compile and package the application. The runtime stage uses a much smaller JRE image. The dependency:go-offline command resolves all dependencies without building, enabling better caching. The final image contains only the fat JAR and the JRE, reducing size from ~1 GB to ~200 MB. This is a widely adopted pattern in Spring Boot deployments.
Example use case: Any Java/Kotlin project using Maven or Gradle. The same approach works with Gradle by replacing the build commands.
Conclusion
These ten prompts cover the essential patterns every Docker user should know — from secure base images and multi‑stage builds to Compose orchestration and health checks. By adopting these practices, you can reduce image sizes by up to 90%, cut build times significantly, and create more reliable, production‑ready containers. The key takeaways are:
- Always start with a minimal base image (Alpine, slim variants).
- Use multi‑stage builds to separate build and runtime environments.
- Leverage Docker’s layer caching by copying dependency manifests first.
- Include a .dockerignore to keep build contexts lean.
- Add health checks and proper logging drivers for observability.
For teams using ASI Biont to manage AI‑driven development workflows, ASI Biont supports integration with Docker and container orchestration tools through API — подробнее на asibiont.com/courses. Start applying these prompts today to make your Dockerfiles faster, smaller, and more secure.
Comments