Dockerfile 编写最佳实践指南
编写高质量的 Dockerfile 是构建高效、安全 Docker 镜像的基础。一个优秀的 Dockerfile 不仅能减小镜像体积、加快构建速度,还能提高容器的安全性。本文将系统性地介绍 Dockerfile 编写的最佳实践,帮助你在搬瓦工 VPS 上构建出生产级别的 Docker 镜像。
一、选择合适的基础镜像
基础镜像的选择直接影响最终镜像的大小和安全性:
# 不推荐:使用完整的操作系统镜像(约 200MB+)
FROM ubuntu:22.04
# 推荐:使用精简版本(约 80MB)
FROM debian:bookworm-slim
# 更推荐:使用 Alpine 镜像(约 5MB)
FROM alpine:3.19
# 最佳:使用特定语言的官方精简镜像
FROM python:3.12-slim
FROM node:20-alpine
FROM golang:1.22-alpine
选择原则:
- 优先使用带有
-slim或-alpine后缀的官方镜像。 - 固定版本标签而非使用
latest,确保构建的可重复性。 - 选择活跃维护的镜像,及时获得安全补丁。
二、优化镜像层
2.1 合并 RUN 指令
每个 RUN 指令都会创建一个新的镜像层,应该合并相关操作:
# 不推荐:多个 RUN 指令创建多个层
FROM debian:bookworm-slim
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y nginx
RUN apt-get clean
# 推荐:合并为一个 RUN 指令
FROM debian:bookworm-slim
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
nginx && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
关键点:安装完成后立即清理缓存,否则清理命令只是在新层中标记删除,并不会减小镜像体积。
2.2 利用构建缓存
Docker 按顺序执行 Dockerfile 中的指令,如果某一层没有变化则使用缓存。应该将不经常变化的指令放在前面:
# 推荐的指令顺序
FROM node:20-alpine
# 1. 系统依赖(很少变化)
RUN apk add --no-cache tini
# 2. 应用依赖(偶尔变化)
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --production
# 3. 应用代码(经常变化)
COPY . .
# 4. 启动命令
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "server.js"]
三、使用 .dockerignore
创建 .dockerignore 文件排除不需要的文件,减小构建上下文:
cat > .dockerignore <<'EOF'
.git
.gitignore
node_modules
npm-debug.log
Dockerfile
docker-compose.yml
.dockerignore
.env
*.md
.vscode
.idea
__pycache__
*.pyc
.pytest_cache
EOF
四、安全加固
4.1 使用非 root 用户
FROM node:20-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --chown=appuser:appgroup . .
RUN npm ci --production
USER appuser
CMD ["node", "server.js"]
4.2 避免在镜像中存储敏感信息
# 错误:将密钥硬编码在镜像中
ENV API_KEY=sk-xxxxx
# 正确:通过运行时环境变量传入
# docker run -e API_KEY=sk-xxxxx myimage
# 构建时需要的密钥使用 BuildKit secrets
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci
4.3 使用只读文件系统
# 运行时以只读模式启动容器
# docker run --read-only --tmpfs /tmp myimage
五、COPY 和 ADD 的选择
# 推荐:使用 COPY(行为明确)
COPY requirements.txt /app/
COPY src/ /app/src/
# 仅在需要自动解压时使用 ADD
ADD archive.tar.gz /app/
# 不推荐:使用 ADD 下载文件(用 RUN curl 替代)
# ADD https://example.com/file.tar.gz /tmp/
RUN curl -fsSL https://example.com/file.tar.gz | tar xz -C /app/
六、ENTRYPOINT 和 CMD
# 使用 exec 格式(推荐),信号可以正确传递给进程
ENTRYPOINT ["python"]
CMD ["app.py"]
# 避免使用 shell 格式,会导致进程成为 /bin/sh 的子进程
# ENTRYPOINT python app.py
# 最佳实践:使用 tini 作为 PID 1 进程
FROM python:3.12-slim
RUN pip install --no-cache-dir tini
ENTRYPOINT ["tini", "--"]
CMD ["python", "app.py"]
七、健康检查
FROM nginx:alpine
COPY nginx.conf /etc/nginx/nginx.conf
COPY html/ /usr/share/nginx/html/
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD curl -f http://localhost/ || exit 1
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
八、标签与元数据
FROM python:3.12-slim
LABEL maintainer="admin@example.com"
LABEL version="1.0"
LABEL description="My Python Application"
LABEL org.opencontainers.image.source="https://github.com/user/repo"
九、完整示例:Python Web 应用
FROM python:3.12-slim AS base
# 设置环境变量
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1
# 安装系统依赖
RUN apt-get update && \
apt-get install -y --no-install-recommends \
tini \
curl && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# 创建非 root 用户
RUN groupadd -r appuser && useradd -r -g appuser appuser
# 设置工作目录
WORKDIR /app
# 安装 Python 依赖(利用缓存)
COPY requirements.txt .
RUN pip install -r requirements.txt
# 复制应用代码
COPY --chown=appuser:appuser . .
# 切换用户
USER appuser
# 健康检查
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
# 暴露端口
EXPOSE 8000
# 启动命令
ENTRYPOINT ["tini", "--"]
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:create_app()"]
十、常用检查工具
使用工具自动检查 Dockerfile 质量:
# 使用 Hadolint 检查 Dockerfile
docker run --rm -i hadolint/hadolint < Dockerfile
# 使用 Dive 分析构建后的镜像层
docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock wagoodman/dive myimage:latest
更多信息请参考 Hadolint 语法检查教程 和 Dive 镜像分析教程。
总结
编写高质量的 Dockerfile 需要兼顾镜像大小、构建速度和运行安全。在搬瓦工 VPS 有限的资源下,优化镜像体积尤为重要。建议结合 多阶段构建 进一步优化,使用 Trivy 进行安全扫描。选购搬瓦工 VPS 请访问 bwh81.net,购买时使用优惠码 NODESEEK2026 可享受 6.77% 的折扣。