可重复交付
可重复交付让已验证的同一产物逐级进入生产。本文负责 Docker 镜像、CI/CD 晋升和交付证据。
1. 面试核心
先记住这几条,再读正文- 产物标识。 镜像 digest 标识内容,tag 可以被重新指向。卡 · 综合题
- 构建与运行分离。 多阶段构建将编译环境与最终运行环境分离。
- 同一产物晋升。 CD 晋升同一个 digest,环境配置在部署时注入。
- 构建凭据。 BuildKit secret mount 将构建凭据临时提供给指定步骤。卡 · 构建缓存与凭据
- 终止信号。 用 exec 形式的
ENTRYPOINT直接启动应用,应用才能直接接收终止信号。若入口是脚本,脚本需通过exec启动应用。卡 · 容器终止信号
2. 镜像与 digest
镜像由文件系统层和配置元数据组成。RUN、COPY 等指令可产生文件系统变化。CMD、LABEL 等指令主要修改元数据。
tag 便于阅读,digest 用于精确引用产物。部署记录同时保存源码提交与镜像摘要。基础镜像也按 digest 固定,并定期更新后重测。
.dockerignore 缩小构建上下文。密钥、Git 历史和本地缓存应排除。后续层删除文件仍会保留旧层中的内容。
3. 多阶段构建
构建阶段使用 JDK、Maven 等工具生成 jar。运行阶段只复制必要产物和运行时。
运行镜像采用非 root 用户,并收紧文件系统权限。临时文件使用明确的可写目录。镜像还需具备应用所需的证书与诊断能力。
4. CI
流水线从固定提交和工具链开始。执行顺序可以如下:
- 校验依赖,完成编译与单元测试。
- 执行静态检查、集成测试和契约测试。
- 构建镜像,生成 SBOM 与构建来源记录。
- 对实际镜像执行冒烟测试和漏洞检查。
- 签名并发布通过门槛的 digest。
部署端还需校验签名身份与来源策略。生成签名本身只是交付证据的一部分。生产凭据只授予部署阶段。
5. CD 晋升
测试、预发与生产使用同一个 digest。配置、Secret 和资源声明在部署时注入。
生产前重新打包会产生另一份二进制。晋升直接使用已验证产物,并记录配置版本。不同环境的集成行为仍需各自验证。
6. 无损替换
新实例就绪后接流量,旧实例按协议排空。探针与端点传播细节见服务发现。
交付验收还需确认进程正确响应 SIGTERM。任务在宽限期内完成,或保存可恢复检查点。
7. 数据库变更
镜像回退与数据库变更分开管理。兼容扩展和收缩见架构迁移。
流水线记录迁移版本、执行锁和检查点。重型 DDL 使用独立任务,避免多实例启动时并发执行。
8. 发布策略
发布策略需绑定业务指标与停止条件。分阶段判断见灰度发布。
回退记录镜像 digest、配置版本与数据兼容状态。失败样本保留日志和 Trace,用于后续定位。
9. 流水线故障演练
演练仓库不可用、拉取失败和探针持续失败。也要验证数据库已升级后的镜像回退。
失败时流水线停止晋升,保留实际部署状态。从提交、构建、配置到实例的关系应可查询。
10. 构建缓存与凭据
缓存重用已完成步骤,但构建输入仍需固定。远程下载使用浮动内容时,同一 Dockerfile 会产生不同结果。
BuildKit 用 --secret 提供凭据。Dockerfile 中的步骤可使用 RUN --mount=type=secret。挂载只在该步骤执行时可见。构建命令还需避免复制凭据或打印其内容。
ARG 与 ENV 会暴露在镜像或构建元数据中,不适合传密钥。密钥内容变化本身不会使构建缓存失效。确需重跑时,可使用非敏感版本参数或禁用该阶段缓存。
11. 容器终止信号
exec 形式直接启动应用:
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
Java 作为容器主进程接收终止信号。应用关闭钩子停止领任务,并等待在途工作结束。
shell 形式会增加 /bin/sh -c 中间进程。该 shell 无义务自动转发应用需要的信号。包装脚本可以用 exec java ... 交出进程位置。排空超过宽限期后,平台会强制终止容器。
12. 常见问题
12.1 latest 与部署记录
latest 可指向不同内容。回滚清单应使用明确 digest。易读 tag 可保留作检索辅助。
12.2 镜像体积与安全性
较少组件能减少需维护的软件数量。安全性还取决于更新来源、漏洞与运行权限。运行所需能力应随镜像一同验证。
13 · 面试题卡片
13.1 如何设计从提交到生产的可重复交付流水线
出现公司:Shopee
题型:综合题
考察重点
- 理解不可变镜像 digest、多阶段构建和构建输入。
- 理解同产物晋升、签名、SBOM 与审计。
- 理解readiness、排空、数据兼容和回滚边界。
相关内容:镜像与 digest至流水线故障演练。
参考回答
流水线构建一次镜像,再晋升经过验证的同一 digest。
CI 固定提交与工具链,完成测试和镜像检查。产物附带 SBOM、构建来源与签名。CD 注入环境配置,并校验来源策略。
发布需验证就绪、信号处理和连接排空。数据变更保持兼容,镜像回退单独验证。部署记录连接源码、digest、配置和运行实例。
13.2 构建私有依赖时怎样传密钥,轮换后缓存会失效吗?
出现公司:暂无已核验的公开来源(本站自测)
考察重点:临时挂载、镜像层与缓存输入。
相关内容:构建缓存与凭据。
参考回答
使用 BuildKit 的 --secret 与 secret mount 传入凭据。
构建过程避免把内容写进产物或日志。密钥内容变化本身不会触发缓存失效。需要重新执行时,使用非敏感缓存版本参数。
13.3 容器收到 SIGTERM 后,Java 应用为何仍被强制结束?
出现公司:暂无已核验的公开来源(本站自测)
考察重点:PID 1、信号转发与排空时限。
相关内容:容器终止信号。
参考回答
应检查 Java 是否收到信号,以及排空是否超时。
shell 形式入口会增加中间进程。exec 形式 ENTRYPOINT 可让 Java 直接接收信号。关闭钩子还需在宽限期内完成工作,否则平台会强制结束。