AgentSkillsCN

docker-dockerfile

Dockerfile 模式:结构设计、基础镜像、多阶段构建、层优化、安全性与健康检查

SKILL.md
--- frontmatter
name: docker-dockerfile
description: "Dockerfile patterns: structure, base images, multi-stage builds, layer optimization, security, and health checks"

Dockerfile Patterns

Best practices and patterns for writing production-ready Dockerfiles based on official Docker documentation and industry standards.

Sources: This guide is based on Docker Official Documentation, Docker Multi-stage Builds, and current security best practices as of 2025.


Dockerfile Structure Template

dockerfile
# syntax=docker/dockerfile:1

# Build stage
FROM node:20.11.0-alpine AS builder

# Metadata
LABEL maintainer="team@example.com"
LABEL version="1.0"

# Set working directory
WORKDIR /app

# Install dependencies first (better caching)
COPY package*.json ./
RUN npm ci

# Copy application code
COPY . .

# Build application
RUN npm run build

# Production stage
FROM node:20.11.0-alpine AS production

# Install security updates
RUN apk update && apk upgrade && rm -rf /var/cache/apk/*

# Create non-root user (UID > 10000 for security)
RUN addgroup -g 10001 -S nodejs && \
    adduser -S nodejs -u 10001

WORKDIR /app

# Copy built assets from builder
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules
COPY --chown=nodejs:nodejs package*.json ./

# Switch to non-root user
USER nodejs

# Expose port
EXPOSE 3000

# Health check (production-necessary, not optional)
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
  CMD node healthcheck.js || exit 1

# Start application
CMD ["node", "dist/server.js"]

Base Image Selection

Choose from Trusted Sources

Docker recommends using images from:

  • Docker Official Images: Curated collection with clear documentation
  • Verified Publisher images: Authenticated by Docker
  • Docker-Sponsored Open Source: Maintained projects

Source: Docker Best Practices - Base Images

Alpine Linux (Minimal)

Alpine is recommended as a minimal starting point, currently under 6 MB while providing a full Linux distribution.

dockerfile
# Smallest size, minimal attack surface
FROM node:20.11.0-alpine
FROM python:3.12-alpine
FROM ruby:3.3-alpine

# Install common dependencies on Alpine
RUN apk add --no-cache \
    bash \
    curl \
    git \
    postgresql-dev

Pin to Specific Digests for Supply Chain Security

dockerfile
# Pin to specific digest for guaranteed immutability
FROM node:20.11.0-alpine@sha256:c0a3badbd8a0a760de903e00cedbca94588e609299820557e72cba2a53dbaa2c

# Note: Requires active maintenance for security updates
# Use Docker Scout for automated remediation workflows

Source: Docker Best Practices - Supply Chain Security

Debian Slim (Balanced)

dockerfile
# Good balance of size and compatibility
FROM node:20-slim
FROM python:3.12-slim
FROM ruby:3.3-slim

# CRITICAL: Always combine apt-get update with install
# Prevents cache issues that could install outdated packages
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
      curl \
      git \
      postgresql-client && \
    rm -rf /var/lib/apt/lists/*

Distroless (Maximum Security)

dockerfile
# Google's distroless images - no shell, minimal attack surface
FROM gcr.io/distroless/nodejs20-debian12
FROM gcr.io/distroless/python3-debian12
FROM gcr.io/distroless/java17-debian12

# Note: No shell available, debugging is harder
# Best for production security

Multi-Stage Builds (Security Critical)

Multi-stage builds are foundational for production security. They allow you to "selectively copy artifacts from one stage to another, leaving behind everything you don't want in the final image."

Security Benefits

  1. Reduced Attack Surface: Excludes build tools, compilers, and development dependencies
  2. Smaller Image Size: Final image contains only runtime necessities
  3. No Build Tools in Production: Eliminates unnecessary security risks

Source: Docker Multi-stage Builds Official Documentation

Basic Multi-Stage Pattern

dockerfile
# Build stage
FROM golang:1.24 AS build

WORKDIR /app
COPY . .
RUN go build -o /bin/hello ./main.go

# Production stage - minimal runtime
FROM scratch
COPY --from=build /bin/hello /bin/hello
CMD ["/bin/hello"]

Copy from External Images

dockerfile
# Copy from any image, not just previous stages
COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf

Named Stages for Maintainability

dockerfile
FROM node:20-alpine AS dependencies
RUN npm ci --only=production

FROM node:20-alpine AS builder
COPY --from=dependencies /app/node_modules ./node_modules
RUN npm run build

FROM node:20-alpine AS production
COPY --from=builder /app/dist ./dist

Use AS <NAME> to reference stages by name rather than numeric index—improves maintainability when reordering instructions.


Layer Optimization

Order by Change Frequency (Critical for Caching)

dockerfile
# ❌ BAD - Changes frequently, invalidates cache
COPY . .
RUN npm install

# ✅ GOOD - Dependencies change less often
COPY package*.json ./
RUN npm ci
COPY . .

Understanding cache invalidation is critical for efficient builds.

Combine RUN Commands

dockerfile
# ❌ BAD - Creates multiple layers
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y git
RUN rm -rf /var/lib/apt/lists/*

# ✅ GOOD - Single layer, smaller image
# CRITICAL: Combine apt-get update with install in same RUN
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
      curl \
      git && \
    rm -rf /var/lib/apt/lists/*

Sort arguments alphanumerically for maintainability.

Use Pipefail for Error Detection

dockerfile
# IMPORTANT: Prepend set -o pipefail to catch errors at any stage
RUN set -o pipefail && \
    curl -sL https://example.com/install.sh | bash

Without pipefail, errors in piped commands may be silently ignored.

Source: Docker Best Practices - RUN Instructions

Use .dockerignore (Essential)

Including unnecessary files like .git, node_modules, and .env increases image size and exposes secrets. The .dockerignore file excludes files and directories from the build context.

dockerignore
# .dockerignore
node_modules
npm-debug.log
.git
.env
.env.local
.env.*.local
*.md
.DS_Store
coverage
.next
dist
build
*.log
.vscode
.idea
Dockerfile
docker-compose*.yml

Source: Docker Best Practices - Build Context


Security Best Practices

Run as Non-Root User (Critical)

By default, Docker containers run as UID 0 (root). If the container is compromised, the attacker will have host-level root access to all resources allocated to the container.

UIDs below 10,000 are a security risk on several systems. If someone manages to escalate privileges outside the Docker container, their Docker container UID may overlap with a more privileged system user's UID, granting them additional permissions.

Best Practice: Always run processes as a UID above 10,000.

dockerfile
# Alpine - Use UID > 10000 for security
RUN addgroup -g 10001 -S appuser && \
    adduser -S appuser -u 10001

# Debian/Ubuntu - Use UID > 10000
RUN useradd -m -u 10001 appuser

# Switch to non-root user
USER appuser

# Set proper ownership when copying
COPY --chown=appuser:appuser . .

Source: Docker USER Instruction Best Practices

Scan for Vulnerabilities

dockerfile
# Use specific versions, never :latest
FROM node:20.11.0-alpine

# Keep base image updated
RUN apk update && apk upgrade && rm -rf /var/cache/apk/*

Scan images regularly:

bash
docker scout cves my-image:latest
# or
trivy image my-image:latest

Secrets Management

dockerfile
# ❌ BAD - Never hardcode secrets
ENV API_KEY=secret123

# ✅ GOOD - Use build args with cleanup
ARG NPM_TOKEN
RUN echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc && \
    npm install && \
    rm -f .npmrc

# ✅ BETTER - Pass at runtime
# docker run -e API_KEY=$API_KEY my-image

Health Checks (Production-Necessary)

According to Docker best practices, "adding a HEALTHCHECK to your Dockerfile is not a nice-to-have—it's a production necessity." Without health checks, Docker cannot detect if a containerized service is unhealthy, preventing automatic restarts or recovery.

HEALTHCHECK Syntax

dockerfile
HEALTHCHECK [OPTIONS] CMD command

Options:

  • --interval=DURATION (default: 30s)
  • --timeout=DURATION (default: 30s)
  • --start-period=DURATION (default: 0s) - Grace period for slow-starting apps
  • --start-interval=DURATION (default: 5s)
  • --retries=N (default: 3)

Exit Codes:

  • 0: success - container is healthy
  • 1: unhealthy - container isn't working correctly

Examples

dockerfile
# Web server check
HEALTHCHECK --interval=5m --timeout=3s \
  CMD curl -f http://localhost/ || exit 1

# Database check
HEALTHCHECK --interval=10s --timeout=5s --retries=5 \
  CMD pg_isready -U postgres || exit 1

# With start-period for slow-starting apps
HEALTHCHECK --interval=30s --timeout=10s --start-period=120s --retries=3 \
  CMD node healthcheck.js || exit 1

Best Practices

  1. Use appropriate health checks - Don't use shallow checks (e.g., ping when you need connection tests)
  2. Use start-period for slow apps - Gives containers grace period before failures count
  3. Verify tool availability - Tools like curl may not be in slim/alpine images
  4. Lightweight checks - Use wget --spider or native commands when possible

Source: Docker HEALTHCHECK Reference