Dockerfile 编写最佳实践

Dockerfile 编写最佳实践

参考:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

1 基本结构

# 指定基础镜像 FROM debian:bookworm # 元信息 LABEL maintainer="ops@example.com" # 设置环境变量 ENV APP_HOME=/usr/local/app \ APP_ENV=production # 切到工作目录 WORKDIR $APP_HOME # 拷贝文件(先拷贝依赖清单,再拷贝源码,最大化利用缓存) COPY requirements.txt . # 执行安装命令(把多个命令合并到单层) RUN apt-get update && apt-get install -y --no-install-recommends \ gcc \ libpq-dev \ && rm -rf /var/lib/apt/lists/* # 复制应用代码 COPY . . # 声明运行时监听端口(仅文档性质,不真正端口映射) EXPOSE 8080 # 容器启动命令 CMD ["python", "app.py"]

2 核心实践

2.1 镜像分层与缓存

Dockerfile 的每条指令都生成一层镜像,docker build 会基于层做缓存。把不变的内容放前面、易变的内容放后面,可最大化缓存命中:

COPY requirements.txt ./ RUN pip install --no-cache-dir -r requirements.txt # 依赖层:requirements.txt 不变则命中缓存 COPY . ./ # 代码层:最后拷贝

2.2 使用多阶段构建

单个 FROM 无法在最终镜像中剔除编译工具,多阶段构建可显著减小体积:

# 阶段一:构建 FROM golang:1.22 AS builder WORKDIR /app COPY . . RUN CGO_ENABLED=0 go build -o app . # 阶段二:运行 FROM alpine:3.20 COPY --from=builder /app/app /usr/local/bin/app EXPOSE 8080 ENTRYPOINT ["app"]

2.3 优先使用官方镜像与固定版本

  • 尽量选用基于 alpine 的镜像(node:22-alpine、python:3.12-slim 等),减少体积与攻击面。
  • 不要使用 latest 等可变标签,锁定具体版本号。

2.4 清理不需要的文件

RUN apt-get update && apt-get install -y --no-install-recommends <pkg> \ && rm -rf /var/lib/apt/lists/* # 清理 apt 索引

2.5 ENTRYPOINT 与 CMD 的配合

  • ENTRYPOINT:固定入口,不宜被参数覆盖;
  • CMD:默认参数,可以被 docker run 的命令行参数替换。
ENTRYPOINT ["gunicorn"] CMD ["-w", "4", "app:app"]

2.6 使用 .dockerignore

构建上下文里排除无关文件,加快传输并避免把敏感文件送进镜像:

.git
.gitignore
*.md
node_modules/
**/__pycache__/
*.log

3 常见问题

  • 层过多、镜像过大:把多个 RUN 合并,或在多阶段构建中仅拷贝产物。
  • 敏感信息入镜像:禁止把密码/密钥写进 Dockerfile 或 ENV,改用 --secret、构建 secret 或运行期环境变量注入。
  • 挂载文件权限问题:容器默认 root 或无权限用户,如需写入宿主机挂载卷,明确 USER 与文件权限。
  • docker commit 不可复制:任何需要长期维护的镜像都应该用 Dockerfile 管理。

4 快速检查镜像体积与分层

docker history <image> # 查看每一层大小 docker inspect <image> # 查看镜像元数据 docker system df # 全局占用情况
阅读 — · 全站 —
🎸 我的歌单 0 首