Docker KubernetesNotes

第 04 章:Dockerfile

zjc 于 2026-01-04 发布

这是《Docker 与 Kubernetes 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 Dockerfile 决定镜像是否可复现、是否安全、是否够小、是否能稳定运行。生产镜像从 Dockerfile 设计开始。

4.1 基础示例

FROM eclipse-temurin:17-jre-alpine

WORKDIR /app
COPY target/order-service.jar app.jar

RUN addgroup -S app && adduser -S app -G app
USER app

ENV JAVA_OPTS="-XX:MaxRAMPercentage=70" \
    TZ=Asia/Shanghai

EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD wget -qO- http://127.0.0.1:8080/actuator/health || exit 1

ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /app/app.jar"]

4.2 指令解析

指令 作用
FROM 基础镜像
RUN 构建期执行命令
COPY 复制上下文文件
ADD 复制并支持自动解压,慎用
ENV 环境变量
ARG 构建参数
WORKDIR 工作目录
USER 运行用户
EXPOSE 声明端口
HEALTHCHECK 容器健康检查
ENTRYPOINT 主命令
CMD 默认参数

4.3 层缓存

低频变化放前,高频变化放后:

COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests

多阶段构建:

FROM maven:3.9-eclipse-temurin-17 AS build
WORKDIR /src
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests

FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY --from=build /src/target/app.jar app.jar
USER app
ENTRYPOINT ["java", "-jar", "/app/app.jar"]

4.4 ENTRYPOINT 与 CMD

ENTRYPOINT ["java", "-jar", "app.jar"]
CMD ["--spring.profiles.active=prod"]

区别:

指令 覆盖方式
ENTRYPOINT 需要 --entrypoint 覆盖
CMD docker run image args 直接覆盖

应用容器应保证 PID 1 能转发 SIGTERM。Shell 形式可能不会转发信号,exec 形式更常用。

4.5 镜像安全

原则:

  1. 固定基础镜像版本;
  2. 使用官方或可信镜像;
  3. 非 root 运行;
  4. 不把 Secret 写入镜像;
  5. 清理包缓存和测试文件;
  6. 使用镜像扫描;
  7. 启用内容信任;
  8. 最小化安装包。

扫描:

trivy image shop/order-service:v1.2.0

4.6 构建变量与 Secret

普通构建参数:

ARG APP_VERSION=dev
ENV APP_VERSION=${APP_VERSION}

构建命令:

docker build --build-arg APP_VERSION=1.2.0 -t order-service:1.2.0 .

不要用 ARG 传密码。敏感值应通过运行时 Secret、构建挂载或 CI 密钥管理注入。

4.7 常见反模式

反模式 问题
使用 latest 不可复现
root 运行 安全风险
一个镜像包含多个服务 边界混乱
日志写容器层 数据丢失
只写 CMD 不处理信号 优雅停机失败
ADD url 下载依赖 不可控
把数据库密码写入 ENV 泄露
依赖交互式初始化 容器无法自愈

本章小结

好的 Dockerfile 应固定版本、多阶段构建、非 root 运行、按缓存优化层顺序、处理信号和健康检查,并把 Secret 留在运行时注入。

思考题

  1. 为什么依赖文件先 COPY?
  2. ENTRYPOINT 和 CMD 如何配合?
  3. 多阶段构建解决什么问题?
  4. 为什么 Shell 形式可能影响优雅停机?
  5. 镜像漏洞治理流程是什么?