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% 的折扣。

关于本站

搬瓦工VPS中文网(bwgvps.com)是非官方中文信息站,整理搬瓦工的方案、优惠和教程。我们不销售主机,不提供技术服务。

新手必读
搬瓦工优惠码

NODESEEK2026(优惠 6.77%)

购买时填入即可抵扣。