CI/CD 与发布工程¶
资深工程师如何设计可扩展、可审计的 CI/CD 流水线?¶
技术说明
CI/CD 流水线1按快速反馈与信任提升分层:格式/静态检查、单元测试、构建、组件/契约测试、安全扫描、集成测试、发布候选、环境部署和验证。每阶段输入输出使用不可变摘要,失败快速终止;耗时高的任务可并行,但发布所依赖的结果必须完整聚合。模板复用要版本化并固定引用,不能让中心模板无审查地改变所有仓库行为。
控制平面2记录提交、评审、流水线版本、依赖、制品3摘要、签名、部署身份和环境结果,形成从源码到运行实例的可追溯链。权限按阶段分离:PR4 代码不能直接获得生产凭证,构建者与批准者职责适度分离。流水线自身也要有 SLO5、队列、失败分类、缓存命中和成本指标,避免把“CI 慢”当不可治理的常态。
实践经验
复合场景中,单体流水线串行 70 分钟,团队频繁跳过测试做紧急发布。团队先并行无依赖检查、按变更路径选择测试并保留全量夜测;长期构建一次、跨环境晋级同一制品,质量门禁有风险分级和 break-glass6 审计。路径选择可能漏掉隐式依赖,因此用依赖图和定期全量测试监测假阴性。
面试回答要点
阶段按反馈速度和信任提升组织,而非工具列表。
流水线按快速反馈与信任提升分层:格式/静态检查、单元测试、构建、组件/契约测试、安全扫描、集成测试、发布候选、环境部署和验证。团队先并行无依赖检查、按变更路径选择测试并保留全量夜测;长期构建一次、跨环境晋级同一制品,质量门禁有风险分级和 break-glass 审计。
每步输入输出不可变、可追溯且模板版本固定。
每阶段输入输出使用不可变摘要,失败快速终止;耗时高的任务可并行,但发布所依赖的结果必须完整聚合。路径选择可能漏掉隐式依赖,因此用依赖图和定期全量测试监测假阴性。
PR、构建、批准、部署权限分离。
权限按阶段分离:PR 代码不能直接获得生产凭证,构建者与批准者职责适度分离。团队先并行无依赖检查、按变更路径选择测试并保留全量夜测;长期构建一次、跨环境晋级同一制品,质量门禁有风险分级和 break-glass 审计。
衡量等待时间、失败原因、可靠性和成本。
流水线自身也要有 SLO、队列、失败分类、缓存命中和成本指标,避免把“CI慢”当不可治理的常态。路径选择可能漏掉隐式依赖,因此用依赖图和定期全量测试监测假阴性。
什么是可重现构建,如何减少“同一提交产物不同”?¶
技术说明
可重现构建的严格定义是:给定相同源码、构建环境和构建指令,任何一方都能重新生成逐字节相同、可由摘要验证的指定制品;仅“语义等价”是更宽松的重复构建目标,不能不加限定地称为 reproducible build。实现上要固定编译器/基础镜像摘要、锁定直接和传递依赖、规范 locale/timezone、排序输入、去除或固定时间戳与随机源,并避免从网络获取未固定的“latest”。构建上下文还要排除工作区未跟踪文件,源码状态与子模块版本显式记录。
构建在隔离、临时环境执行,依赖代理/镜像有内容寻址和完整性校验。生成 SBOM7 与 provenance8 并不自动使构建可重现,它们提供可审计证据;可用第二独立 builder 重建并比较摘要发现供应链或环境漂移。若签名或压缩元数据引入差异,应把规范化步骤纳入可审查的构建过程,或明确指定比较签名前的规范制品;若最终只能做语义比较,就应如实标为较弱目标,避免虚假承诺。
实践经验
复合场景中,同一 Git SHA 在重跑后镜像摘要变化,调查发现 Dockerfile 使用浮动基础 tag,包仓库也更新了传递依赖。团队冻结发布、恢复已验证摘要;长期所有输入按 digest/lockfile固定,构建元数据记录工具链,关键制品做双构建比对。固定依赖会延迟安全更新,因此由自动 PR 定期升级并重新验证,而非永不更新。
面试回答要点
枚举源码之外的工具链、依赖、时间和环境输入。
实现上要固定编译器/基础镜像摘要、锁定直接和传递依赖、规范 locale/timezone、排序输入、去除或固定时间戳与随机源,并避免从网络获取未固定的“latest”。团队冻结发布、恢复已验证摘要;长期所有输入按 digest/lockfile固定,构建元数据记录工具链,关键制品做双构建比对。
固定 digest/lockfile,构建环境临时隔离。
构建在隔离、临时环境执行,依赖代理/镜像有内容寻址和完整性校验。团队冻结发布、恢复已验证摘要;长期所有输入按 digest/lockfile固定,构建元数据记录工具链,关键制品做双构建比对。
用独立重建比较而非仅相信元数据。
生成 SBOM 与 provenance 并不自动使构建可重现,它们提供可审计证据;可用第二独立 builder 重建并比较摘要发现供应链或环境漂移。团队冻结发布、恢复已验证摘要;长期所有输入按 digest/lockfile固定,构建元数据记录工具链,关键制品做双构建比对。
依赖固定与安全更新通过自动升级流程平衡。
实现上要固定编译器/基础镜像摘要、锁定直接和传递依赖、规范 locale/timezone、排序输入、去除或固定时间戳与随机源,并避免从网络获取未固定的“latest”。固定依赖会延迟安全更新,因此由自动 PR 定期升级并重新验证,而非永不更新。
为什么必须“构建一次,多环境晋级”,而不是每环境重建?¶
技术说明
每个环境重建会让测试对象与生产对象不一致,即使源码相同,基础镜像、依赖仓库和时间都可能变化。正确模式是 CI 产生不可变制品,以内容摘要标识;测试、预发和生产只改变部署配置并引用同一摘要。晋级是增加环境验证/签名或元数据,不是复制后改内容。回滚也应选择已知摘要,而非重新构建旧 commit。
环境差异通过运行时配置、秘密引用和资源策略表达,不能在镜像内写入环境地址。若确需地区特定静态资产,要把它作为独立版本化输入并形成新的制品身份。部署记录源码 SHA、镜像/包 digest、配置版本和迁级证据;tag 只是易读别名且可移动,生产策略应解析并固定 digest。
实践经验
复合场景中,预发和生产分别 npm install 构建,生产恰逢上游包更新,出现预发未见回归。团队回退到预发验证过的镜像摘要;长期在受控 builder 构建一次,注册表中按摘要晋级,环境只注入配置。集中制品仓库故障会阻塞发布,因此跨区复制并定期做恢复演练。
面试回答要点
同一源码不等于同一制品,生产必须部署已测试摘要。
正确模式是 CI 产生不可变制品,以内容摘要标识;测试、预发和生产只改变部署配置并引用同一摘要。团队回退到预发验证过的镜像摘要;长期在受控 builder 构建一次,注册表中按摘要晋级,环境只注入配置。
环境配置与二进制/镜像内容分离。
环境差异通过运行时配置、秘密引用和资源策略表达,不能在镜像内写入环境地址。团队回退到预发验证过的镜像摘要;长期在受控 builder 构建一次,注册表中按摘要晋级,环境只注入配置。
晋级附加证据,不修改制品内容。
晋级是增加环境验证/签名或元数据,不是复制后改内容。团队回退到预发验证过的镜像摘要;长期在受控 builder 构建一次,注册表中按摘要晋级,环境只注入配置。
回滚选择已验证摘要,不现场重建历史版本。
回滚也应选择已知摘要,而非重新构建旧 commit。团队回退到预发验证过的镜像摘要;长期在受控 builder 构建一次,注册表中按摘要晋级,环境只注入配置。
制品仓库的保留、签名与灾备怎样设计?¶
技术说明
制品仓库保存内容寻址的镜像/包、元数据、SBOM、签名和 provenance,并对 push、tag 移动、删除实行细粒度权限。生产引用摘要,发布 tag 可设不可变;签名验证需要受信身份、签发策略与吊销/轮换,不能只检查“存在任意签名”。保留策略按已部署、可回滚、合规留存和临时 PR 制品分层,GC 前构建引用图。
仓库是发布关键依赖,要有跨区复制、备份与恢复测试;复制延迟需纳入跨区发布门禁。缓存代理提升可用性,但上游删除、tag 漂移和签名元数据一致性要处理。删除必须软删除/延迟回收并审计,避免仍运行节点重拉失败。容量指标同时看 blob、manifest、上传失败、复制水位和恢复时间。
实践经验
复合场景中,按“30天未下载”GC 删除了仍在生产但节点长期未重拉的镜像,扩容时 ImagePull 失败。团队暂停 GC、从副本恢复摘要并冻结扩容策略;长期从集群清单和发布记录标记保护集,保留 N 个已知良好版本,删除先报告后延迟执行。保留增加存储成本,按风险等级和去重收益量化。
面试回答要点
生产用 digest,tag 不作为唯一身份。
生产引用摘要,发布 tag 可设不可变;签名验证需要受信身份、签发策略与吊销/轮换,不能只检查“存在任意签名”。复合场景中,按“30天未下载”GC 删除了仍在生产但节点长期未重拉的镜像,扩容时 ImagePull 失败。
签名验证要绑定受信发行者和策略。
生产引用摘要,发布 tag 可设不可变;签名验证需要受信身份、签发策略与吊销/轮换,不能只检查“存在任意签名”。团队暂停 GC、从副本恢复摘要并冻结扩容策略;长期从集群清单和发布记录标记保护集,保留 N 个已知良好版本,删除先报告后延迟执行。
GC 从部署/回滚引用图出发,并有延迟恢复窗。
保留策略按已部署、可回滚、合规留存和临时 PR 制品分层,GC 前构建引用图。团队暂停 GC、从副本恢复摘要并冻结扩容策略;长期从集群清单和发布记录标记保护集,保留 N 个已知良好版本,删除先报告后延迟执行。
跨区复制与实际恢复测试属于发布能力。
仓库是发布关键依赖,要有跨区复制、备份与恢复测试;复制延迟需纳入跨区发布门禁。团队暂停 GC、从副本恢复摘要并冻结扩容策略;长期从集群清单和发布记录标记保护集,保留 N 个已知良好版本,删除先报告后延迟执行。
安全、高效的容器镜像构建应遵循哪些原则?¶
技术说明
使用最小且受维护的基础镜像并固定 digest,多阶段构建只把运行所需文件复制到最终层;以非 root 用户运行,避免携带编译器、包缓存、SSH key 和构建秘密。BuildKit secret/SSH mount 等机制可让凭证不进入层或构建参数,仍需检查日志。.dockerignore 限制上下文,依赖锁定并校验,镜像生成 SBOM、漏洞报告和来源证明。
层缓存按指令与输入计算,先复制依赖清单可提高命中,但不能让缓存绕过更新/扫描。扫描结果需按可利用性、运行路径、修复可用性和 SLA治理,不能以“零 CVE”作为不现实门槛。镜像大小只是一个指标:过度使用缺乏 shell/CA 的极简镜像会增加诊断或 TLS 兼容成本,可用 debug sidecar/临时容器补足。
实践经验
复合场景中,构建参数传入仓库 token,镜像历史与 CI 日志都可见该值。团队立即吊销 token、审计拉取记录并重建镜像;长期改用短期 secret mount、隔离构建网络和扫描历史层。去掉所有调试工具后排障困难,因此生产镜像保持最小,另有同源受控 debug 镜像并限制使用。
面试回答要点
固定基础摘要、多阶段、非 root、最小运行内容。
使用最小且受维护的基础镜像并固定 digest,多阶段构建只把运行所需文件复制到最终层;以非 root 用户运行,避免携带编译器、包缓存、SSH key 和构建秘密。去掉所有调试工具后排障困难,因此生产镜像保持最小,另有同源受控 debug 镜像并限制使用。
秘密不通过 ARG/COPY 进入层或日志。
BuildKit secret/SSH mount 等机制可让凭证不进入层或构建参数,仍需检查日志。复合场景中,构建参数传入仓库 token,镜像历史与 CI 日志都可见该值。
SBOM、漏洞与 provenance 是持续治理链路。
.dockerignore 限制上下文,依赖锁定并校验,镜像生成 SBOM、漏洞报告和来源证明。复合场景中,构建参数传入仓库 token,镜像历史与 CI 日志都可见该值。
缓存、镜像大小、安全和可诊断性需平衡。
镜像大小只是一个指标:过度使用缺乏 shell/CA 的极简镜像会增加诊断或 TLS 兼容成本,可用 debug sidecar/临时容器补足。复合场景中,构建参数传入仓库 token,镜像历史与 CI 日志都可见该值。
镜像晋级如何保证“所测即所发”并支持跨区域发布?¶
技术说明
构建完成后以 digest 创建候选记录,依次附加测试、扫描、签名和批准证明;晋级只更新环境期望状态对该 digest 的引用,不重新 tag 后重建。准入策略验证 registry、digest、受信构建身份、源码仓库/分支和必要证明。若使用环境 tag,应把它当指针并审计移动,部署清单最终仍解析为 digest。
跨区域先复制 blob、manifest、签名与证明,确认目标仓库可读且摘要一致,再允许当地控制面部署。多架构 manifest list 还要验证每个平台子摘要,不可只测 amd64。撤销某制品时区分阻止新部署和是否强制替换运行实例,后者可能造成紧急容量风险;回滚清单要保留最近兼容版本。
实践经验
复合场景中,prod tag 在区域 A 更新后区域 B 复制延迟,两个区域同 tag 指向不同摘要。团队暂停后续波次、按摘要核对并等待复制水位;长期部署 API 只收 digest,区域发布前验证 manifest/签名均可用。复制门禁增加发布时间,但避免区域间不可解释漂移,紧急时仍有本地已验证回滚摘要。
面试回答要点
候选身份是内容 digest,不是可移动 tag。
构建完成后以 digest 创建候选记录,依次附加测试、扫描、签名和批准证明;晋级只更新环境期望状态对该 digest 的引用,不重新 tag 后重建。团队暂停后续波次、按摘要核对并等待复制水位;长期部署 API 只收 digest,区域发布前验证 manifest/签名均可用。
晋级增加证明和环境引用,不重建内容。
构建完成后以 digest 创建候选记录,依次附加测试、扫描、签名和批准证明;晋级只更新环境期望状态对该 digest 的引用,不重新 tag 后重建。复制门禁增加发布时间,但避免区域间不可解释漂移,紧急时仍有本地已验证回滚摘要。
跨区验证 blob、manifest、签名及复制水位。
跨区域先复制 blob、manifest、签名与证明,确认目标仓库可读且摘要一致,再允许当地控制面部署。团队暂停后续波次、按摘要核对并等待复制水位;长期部署 API 只收 digest,区域发布前验证 manifest/签名均可用。
多架构逐平台验证,并保留兼容回滚集合。
多架构 manifest list 还要验证每个平台子摘要,不可只测 amd64。复制门禁增加发布时间,但避免区域间不可解释漂移,紧急时仍有本地已验证回滚摘要。
主干开发、发布分支和环境分支应如何选择?¶
技术说明
主干开发强调短寿命分支、频繁集成和始终可发布,通过 feature flag 隔离未完成功能;它降低长期合并冲突,但要求快速可靠 CI。发布分支适合需要同时维护多个版本或严格冻结窗口的产品,代价是修复需回写多个分支、漂移风险上升。把每个环境做长期 Git 分支常导致 cherry-pick 漂移,环境差异更适合声明式配置和明确晋级记录。
策略取决于发布频率、法规、版本支持和测试能力。无论模型,都要定义变更如何进入主线、热修如何反向合并、版本如何标记、谁能绕过门禁。分支名不是部署身份;tag/commit 与制品摘要才构成追溯。大功能用 branch by abstraction 和 flag 渐进切换,避免数月分支。
实践经验
复合场景中,dev/stage/prod 三条环境分支人工 cherry-pick,某安全修复只进了 stage。团队盘点差异并把生产恢复到含修复的不可变版本;长期代码单主干,环境仓库存配置引用 digest,晋级由 PR 更新。迁移期需要冻结和对账,且配置 PR 增多,平台提供自动生成与差异视图降低负担。
面试回答要点
分支模型服务版本支持和集成节奏,不等同环境模型。
策略取决于发布频率、法规、版本支持和测试能力。团队盘点差异并把生产恢复到含修复的不可变版本;长期代码单主干,环境仓库存配置引用 digest,晋级由 PR 更新。
长寿命环境分支容易产生不可见漂移。
把每个环境做长期 Git 分支常导致 cherry-pick 漂移,环境差异更适合声明式配置和明确晋级记录。团队盘点差异并把生产恢复到含修复的不可变版本;长期代码单主干,环境仓库存配置引用 digest,晋级由 PR 更新。
热修必须回写主干和所有受支持版本。
发布分支适合需要同时维护多个版本或严格冻结窗口的产品,代价是修复需回写多个分支、漂移风险上升。团队盘点差异并把生产恢复到含修复的不可变版本;长期代码单主干,环境仓库存配置引用 digest,晋级由 PR 更新。
以 commit、tag、digest 和配置版本追溯发布。
主干开发强调短寿命分支、频繁集成和始终可发布,通过 feature flag 隔离未完成功能;它降低长期合并冲突,但要求快速可靠 CI。团队盘点差异并把生产恢复到含修复的不可变版本;长期代码单主干,环境仓库存配置引用 digest,晋级由 PR 更新。
CI 缓存如何提速而不引入污染和供应链风险?¶
技术说明
缓存 key 应包含操作系统/架构、工具链、锁文件哈希和影响输出的构建参数;restore key 可提供低精度回退,但恢复后仍需由构建工具校验。依赖缓存与构建产物不同,不能把未验证的可执行产物跨信任边界复用。来自 fork/不可信 PR 的 job 不应有写入主干缓存的权限,否则可投毒后续受信构建。
缓存是优化,不是正确性来源:删除缓存后构建仍应成功,产物发布前进行完整校验/签名。设置容量、TTL 和并发写策略,监控命中、下载时间、解压 CPU、错误与产出差异;缓存过大可能比重新下载更慢。禁止缓存秘密、带长期凭证的配置和含环境特定绝对路径的脆弱状态。
实践经验
复合场景中,外部 PR 写入共享编译缓存,主干随后链接了被替换对象文件。团队禁用该缓存、重建并轮换可能暴露的凭证;长期按仓库、分支和信任级别分区,PR 只读公开依赖缓存,主干写入前校验。隔离降低命中率,使用内容寻址和受信预热任务补偿性能。
面试回答要点
key 覆盖所有影响输出的输入与工具链。
缓存 key 应包含操作系统/架构、工具链、锁文件哈希和影响输出的构建参数;restore key 可提供低精度回退,但恢复后仍需由构建工具校验。复合场景中,外部 PR 写入共享编译缓存,主干随后链接了被替换对象文件。
不可信 PR 不能污染受信缓存。
来自 fork/不可信 PR 的 job 不应有写入主干缓存的权限,否则可投毒后续受信构建。团队禁用该缓存、重建并轮换可能暴露的凭证;长期按仓库、分支和信任级别分区,PR 只读公开依赖缓存,主干写入前校验。
冷缓存构建必须正确,发布产物再独立验证。
缓存是优化,不是正确性来源:删除缓存后构建仍应成功,产物发布前进行完整校验/签名。团队禁用该缓存、重建并轮换可能暴露的凭证;长期按仓库、分支和信任级别分区,PR 只读公开依赖缓存,主干写入前校验。
用命中收益、传输成本和差异检测评估缓存。
设置容量、TTL 和并发写策略,监控命中、下载时间、解压 CPU、错误与产出差异;缓存过大可能比重新下载更慢。团队禁用该缓存、重建并轮换可能暴露的凭证;长期按仓库、分支和信任级别分区,PR 只读公开依赖缓存,主干写入前校验。
测试与安全门禁如何既可靠又不把交付完全堵死?¶
技术说明
门禁按风险与反馈速度分层:确定性静态/单测阻断 PR,集成/契约在合并前或候选阶段,长时性能/混沌可按变更路径或定期运行。安全发现按严重性、可利用性、暴露面、修复可用性和资产级别决定阻断;建立有期限、有责任人的例外,而不是永久 allowlist。flaky 测试必须有指标、隔离和修复 SLA,不能无限重跑直到绿色。
门禁本身版本化并可审计,外部扫描器故障需区分“发现问题”和“无法完成检查”。fail-closed 保护高风险发布,但全局依赖中断可能阻塞紧急修复;可设计缓存的已验证证据和双人 break-glass,事后补检。每项门禁跟踪缺陷逃逸率、误报、耗时和维护成本,以证据调整。
实践经验
复合场景中,一个不稳定端到端测试失败率 8%,团队形成“重跑三次”习惯,真实回归也被放过。团队先将该测试移出自动重跑、由稳定契约测试补关键路径;长期给 flaky 所有者和 SLA,连续失败阻止扩大发布。隔离期间覆盖下降被明确记录,并用小流量金丝雀和快速回滚补偿。
面试回答要点
门禁风险分级,明确阻断、告警和限时例外。
门禁按风险与反馈速度分层:确定性静态/单测阻断 PR,集成/契约在合并前或候选阶段,长时性能/混沌可按变更路径或定期运行。隔离期间覆盖下降被明确记录,并用小流量金丝雀和快速回滚补偿。
flaky 不能靠无限重跑,应归责和修复。
flaky 测试必须有指标、隔离和修复 SLA,不能无限重跑直到绿色。团队先将该测试移出自动重跑、由稳定契约测试补关键路径;长期给 flaky 所有者和 SLA,连续失败阻止扩大发布。
检查服务不可用与检查发现失败要分开处理。
门禁本身版本化并可审计,外部扫描器故障需区分“发现问题”和“无法完成检查”。复合场景中,一个不稳定端到端测试失败率 8%,团队形成“重跑三次”习惯,真实回归也被放过。
用逃逸率、误报、耗时衡量门禁价值。
每项门禁跟踪缺陷逃逸率、误报、耗时和维护成本,以证据调整。隔离期间覆盖下降被明确记录,并用小流量金丝雀和快速回滚补偿。
CD 控制器如何保证部署幂等、并发安全和可回滚?¶
技术说明
CD 应以期望状态与实际状态持续 reconcile,每次部署由唯一 release ID、制品 digest、配置版本和目标集合定义。更新使用资源版本/CAS或单环境租约,避免两条流水线互相覆盖;controller 崩溃后从持久状态继续。apply 成功只是控制面接受,必须等待 rollout 条件、健康和业务验证,记录每个目标的最终状态。
回滚是提交新的期望版本,不是删除历史;先检查 schema、feature flag 和外部副作用兼容。部署超时可能结果未知,控制器应查询实际状态再决定,而非盲目再次创建。高可用控制器用 leader election,但底层写仍需版本保护。人工改动作为 drift 处理:紧急变更记录并尽快回写声明源。
实践经验
复合场景中,两次生产部署相隔一分钟,较慢的旧任务最后写回,把环境降到旧版本。团队暂停队列、按运行实例摘要恢复正确版本;长期每环境串行化,部署写入携带期望 generation,旧 generation 被拒。串行降低同环境吞吐,但发布通常应合并或取消旧版本,而非并发争抢。
面试回答要点
部署是带 generation 的状态协调,不是命令串。
部署超时可能结果未知,控制器应查询实际状态再决定,而非盲目再次创建。团队暂停队列、按运行实例摘要恢复正确版本;长期每环境串行化,部署写入携带期望 generation,旧 generation 被拒。
CAS/租约防止旧任务覆盖新期望。
更新使用资源版本/CAS或单环境租约,避免两条流水线互相覆盖;controller 崩溃后从持久状态继续。复合场景中,两次生产部署相隔一分钟,较慢的旧任务最后写回,把环境降到旧版本。
控制面成功后仍验证 rollout 与业务 SLO。
apply 成功只是控制面接受,必须等待 rollout 条件、健康和业务验证,记录每个目标的最终状态。复合场景中,两次生产部署相隔一分钟,较慢的旧任务最后写回,把环境降到旧版本。
回滚需检查数据、配置和外部副作用兼容性。
回滚是提交新的期望版本,不是删除历史;先检查 schema、feature flag 和外部副作用兼容。复合场景中,两次生产部署相隔一分钟,较慢的旧任务最后写回,把环境降到旧版本。
滚动发布怎样设置批次、容量与排空,避免边发边故障?¶
技术说明
滚动发布逐批替换实例,核心参数是最大不可用、最大额外实例、最小就绪时间和进度期限。容量需覆盖旧实例排空、新实例启动/预热和故障实例重叠;readiness 只在真正可处理流量后成功,启动探针保护慢启动。终止时先摘流量、等待 LB/服务发现传播与在途请求完成,再关闭进程。
滚动期间新旧版本同时存在,API、消息和数据库 schema 必须双向兼容;若版本不可共存,不应强行滚动。发布验证不能只看 Pod ready,要看错误、延迟、饱和、业务转化和依赖压力,并设置自动暂停而非每个尖峰立即回滚。PDB 保护维护时可用性,但过严可能阻塞节点修复,要与容量设计一致。
实践经验
复合场景中,配置最大不可用 50%,新版本启动需缓存预热但 readiness 过早成功,流量集中到冷实例,P99暴涨。团队暂停 rollout、回滚批次并临时降低流量;长期 readiness 纳入预热完成,批次改 5%→20%→全量并设置最小观察窗。更慢发布增加变更交付时间,但显著缩小爆炸半径。
面试回答要点
批次由可用容量和允许爆炸半径决定。
容量需覆盖旧实例排空、新实例启动/预热和故障实例重叠;readiness 只在真正可处理流量后成功,启动探针保护慢启动。更慢发布增加变更交付时间,但显著缩小爆炸半径。
readiness、预热、排空和服务发现传播完整配合。
终止时先摘流量、等待 LB/服务发现传播与在途请求完成,再关闭进程。复合场景中,配置最大不可用 50%,新版本启动需缓存预热但 readiness 过早成功,流量集中到冷实例,P99暴涨。
新旧版本在滚动窗口必须协议与数据兼容。
滚动期间新旧版本同时存在,API、消息和数据库 schema 必须双向兼容;若版本不可共存,不应强行滚动。复合场景中,配置最大不可用 50%,新版本启动需缓存预热但 readiness 过早成功,流量集中到冷实例,P99暴涨。
用业务/资源指标暂停推进,不能只看实例状态。
发布验证不能只看 Pod ready,要看错误、延迟、饱和、业务转化和依赖压力,并设置自动暂停而非每个尖峰立即回滚。复合场景中,配置最大不可用 50%,新版本启动需缓存预热但 readiness 过早成功,流量集中到冷实例,P99暴涨。
金丝雀发布如何选择样本、指标和自动判定?¶
技术说明
金丝雀把一小部分代表性流量送到候选版本,与同时段、同环境基线比较。流量可按随机百分比、用户/租户一致哈希、地域或请求类型分组;必须避免候选只收到健康流量或样本过少。分析指标包括错误、延迟分位数、饱和、关键业务结果和依赖调用,设最小样本量、观察窗、绝对阈值与相对差异。
自动分析要处理低流量、季节性、多重指标与监控缺失。监控无数据不能默认通过;候选故障时先停止扩量,回滚或隔离要依据副作用可逆性。带写入的候选可能已改变数据,路由回去并不等于回滚。每个波次保持 soak time,防止内存泄漏、证书刷新等慢问题逃逸。
实践经验
复合场景中,1%随机金丝雀总体错误正常,但新版本只对大租户请求失败,样本中大租户不足。团队停止扩量、按租户回退;长期分层采样确保高价值/高成本请求覆盖,技术指标外增加订单完成率。分层路由复杂且可能导致租户粘性,故记录分桶算法并设置流量再平衡上限。
面试回答要点
金丝雀样本要代表风险维度,不只随机百分比。
流量可按随机百分比、用户/租户一致哈希、地域或请求类型分组;必须避免候选只收到健康流量或样本过少。复合场景中,1%随机金丝雀总体错误正常,但新版本只对大租户请求失败,样本中大租户不足。
最小样本、观察窗、绝对和相对阈值都要定义。
分析指标包括错误、延迟分位数、饱和、关键业务结果和依赖调用,设最小样本量、观察窗、绝对阈值与相对差异。复合场景中,1%随机金丝雀总体错误正常,但新版本只对大租户请求失败,样本中大租户不足。
无监控数据是不可判定,不应自动通过。
监控无数据不能默认通过;候选故障时先停止扩量,回滚或隔离要依据副作用可逆性。复合场景中,1%随机金丝雀总体错误正常,但新版本只对大租户请求失败,样本中大租户不足。
有状态副作用需单独设计兼容与补偿。
监控无数据不能默认通过;候选故障时先停止扩量,回滚或隔离要依据副作用可逆性。团队停止扩量、按租户回退;长期分层采样确保高价值/高成本请求覆盖,技术指标外增加订单完成率。
蓝绿发布的切换、数据兼容与成本边界是什么?¶
技术说明
蓝绿同时维护当前与候选两套完整环境,在验证后通过 LB、路由或服务发现切换。优点是切换和回退快、环境隔离清晰;代价是近双倍容量、配置漂移和切换瞬间连接行为。切换前预热缓存、验证依赖/证书/配额,切换时对长连接与 DNS 缓存有明确策略,旧环境保留到观察窗结束而非立刻销毁。
数据库通常仍共享,故代码必须兼容同一 schema;若两套数据库,双写、复制延迟和最终切换会显著复杂化。写流量切回旧环境前确认新版本未产生旧版本不能理解的数据。队列消费者也不能仅靠入口切换,需要暂停、分组或版本化事件。蓝绿适合可复制且切换点清晰的服务,不是所有大状态系统的默认答案。
实践经验
复合场景中,Web 蓝绿切换秒级完成,但后台消费者绿环境仍在处理消息,回切后同一任务重复执行。团队暂停两组消费者、以幂等键对账;长期将消费者组所有权纳入切换状态机,明确入口、定时任务、队列和写入四类流量。双环境成本高,稳定观察后按自动审批缩容旧环境但保留快速重建能力。
面试回答要点
切换对象不只是 HTTP,还包括队列、定时和写路径。
队列消费者也不能仅靠入口切换,需要暂停、分组或版本化事件。团队暂停两组消费者、以幂等键对账;长期将消费者组所有权纳入切换状态机,明确入口、定时任务、队列和写入四类流量。
旧环境需保留观察窗并能真正重新接管。
切换前预热缓存、验证依赖/证书/配额,切换时对长连接与 DNS 缓存有明确策略,旧环境保留到观察窗结束而非立刻销毁。双环境成本高,稳定观察后按自动审批缩容旧环境但保留快速重建能力。
共享数据必须保持 N/N-1 兼容。
数据库通常仍共享,故代码必须兼容同一 schema;若两套数据库,双写、复制延迟和最终切换会显著复杂化。双环境成本高,稳定观察后按自动审批缩容旧环境但保留快速重建能力。
用容量成本换快速切回,状态系统需额外方案。
蓝绿适合可复制且切换点清晰的服务,不是所有大状态系统的默认答案。双环境成本高,稳定观察后按自动审批缩容旧环境但保留快速重建能力。
Feature flag 如何避免成为永久配置债务或安全绕过?¶
技术说明
flag 可分发布、实验、运维和权限类,各自生命周期不同。评估通常按主体稳定哈希,以保证用户分桶稳定;服务端给出安全默认值,在控制面不可用时明确 fail-open/closed。flag 配置需版本、审核、审计、环境隔离和缓存,不能在热路径每次同步远端读取。权限控制不能只靠客户端 UI flag,服务端仍必须执行授权。
每个临时 flag 定义 owner、创建原因、到期日和清理条件,代码同时支持新旧路径期间要测试组合爆炸。紧急 kill switch 要演练,作用范围与副作用可见;数据迁移型 flag 需按双读/双写状态机推进,不是单布尔。flag 状态应随 trace/log记录但避免高基数或泄露用户属性。
实践经验
复合场景中,旧实验 flag 两年未清理,新重构只测试默认分支,某大客户仍命中旧路径并故障。团队关闭实验、回滚受影响租户;长期建立 flag 目录与到期阻断,发布 flag 完成后自动创建删除任务。强制到期可能打断长期商业配置,因此将永久配置与临时发布 flag 分开建模。
面试回答要点
flag 类型、owner、默认行为和生命周期必须明确。
flag 可分发布、实验、运维和权限类,各自生命周期不同。复合场景中,旧实验 flag 两年未清理,新重构只测试默认分支,某大客户仍命中旧路径并故障。
分桶稳定、控制面故障行为和审计要设计。
评估通常按主体稳定哈希,以保证用户分桶稳定;服务端给出安全默认值,在控制面不可用时明确 fail-open/closed。复合场景中,旧实验 flag 两年未清理,新重构只测试默认分支,某大客户仍命中旧路径并故障。
服务端授权不能被客户端 flag 替代。
权限控制不能只靠客户端 UI flag,服务端仍必须执行授权。复合场景中,旧实验 flag 两年未清理,新重构只测试默认分支,某大客户仍命中旧路径并故障。
状态迁移用多阶段 flag,临时 flag 按期删代码。
紧急 kill switch 要演练,作用范围与副作用可见;数据迁移型 flag 需按双读/双写状态机推进,不是单布尔。强制到期可能打断长期商业配置,因此将永久配置与临时发布 flag 分开建模。
数据库 schema 变更为何要采用 expand/contract?¶
技术说明
滚动发布中旧代码与新代码共存,直接 rename/drop 列会破坏其中一方。expand 阶段先做向后兼容的新增(可空列、表、索引),部署能理解新旧 schema 的代码;迁移/回填并验证后切换读取,停止旧写,最后 contract 删除旧结构。每一步独立发布、可暂停,且至少兼容当前与上一版本。
DDL 风险取决于数据库版本、表规模和具体操作,可能锁表、重写数据或产生复制延迟。上线前在生产规模副本测锁和时长,设置 lock/statement timeout,监控事务、lag 和磁盘。CREATE INDEX CONCURRENTLY 等在线能力也有失败残留和额外负载,必须按数据库官方语义处理,不能把“在线”理解为无影响。
实践经验
复合场景中,发布直接把 name 重命名为 display_name,一半旧 Pod 继续查询旧列而报错。团队恢复兼容视图并暂停滚动;长期先加新列双写、回填对账、切读、确认旧版本下线后再删旧列。双写增加延迟和不一致窗口,因此用数据库触发/应用 outbox择一,并有差异检测。
面试回答要点
新旧版本并存决定 schema 必须向前后兼容。
expand 阶段先做向后兼容的新增(可空列、表、索引),部署能理解新旧 schema 的代码;迁移/回填并验证后切换读取,停止旧写,最后 contract 删除旧结构。团队恢复兼容视图并暂停滚动;长期先加新列双写、回填对账、切读、确认旧版本下线后再删旧列。
expand、迁移、切读、停旧写、contract 分步执行。
expand 阶段先做向后兼容的新增(可空列、表、索引),部署能理解新旧 schema 的代码;迁移/回填并验证后切换读取,停止旧写,最后 contract 删除旧结构。双写增加延迟和不一致窗口,因此用数据库触发/应用 outbox择一,并有差异检测。
DDL 在真实规模验证锁、复制和磁盘副作用。
DDL 风险取决于数据库版本、表规模和具体操作,可能锁表、重写数据或产生复制延迟。双写增加延迟和不一致窗口,因此用数据库触发/应用 outbox择一,并有差异检测。
双写期间必须有对账与明确事实来源。
CREATE INDEX CONCURRENTLY 等在线能力也有失败残留和额外负载,必须按数据库官方语义处理,不能把“在线”理解为无影响。团队恢复兼容视图并暂停滚动;长期先加新列双写、回填对账、切读、确认旧版本下线后再删旧列。
大表回填与数据迁移如何限速、校验和恢复?¶
技术说明
回填按稳定主键或时间水位分小批执行,每批短事务提交并保存检查点;避免大事务持锁、膨胀 WAL/undo 和拖慢复制。并发与批大小根据数据库 CPU、I/O、锁等待和 replica lag 自适应,设置暂停阈值。查询必须命中合适索引,扫描边界用“上次最大键”而非大 offset;更新带条件,避免覆盖在线新写。
迁移期间明确事实来源和双写顺序,使用版本/时间戳解决并发。校验包括行数、空值、分桶 checksum、业务不变量与抽样,修复任务同样幂等。回滚通常是停止切读而非逆向删除新数据;旧列/表保持到观察期与备份确认后才 contract。进度、剩余时间、失败分类和重试量必须可见。
实践经验
复合场景中,回填用 OFFSET 全表分页并每批十万行,越跑越慢且复制延迟达 20 分钟。团队暂停任务、等待副本追平;长期改主键游标和一千行短事务,lag 超阈自动降速,按哈希桶对账。迁移时间从数小时变两天,但在线 SLO和灾备 RPO 保持稳定。
面试回答要点
稳定游标、小事务、幂等条件写与持久检查点。
回填按稳定主键或时间水位分小批执行,每批短事务提交并保存检查点;避免大事务持锁、膨胀 WAL/undo 和拖慢复制。团队暂停任务、等待副本追平;长期改主键游标和一千行短事务,lag 超阈自动降速,按哈希桶对账。
用主库负载、锁和 replica lag 做闭环限速。
并发与批大小根据数据库 CPU、I/O、锁等待和 replica lag 自适应,设置暂停阈值。团队暂停任务、等待副本追平;长期改主键游标和一千行短事务,lag 超阈自动降速,按哈希桶对账。
校验业务不变量,不只比较总行数。
校验包括行数、空值、分桶 checksum、业务不变量与抽样,修复任务同样幂等。迁移时间从数小时变两天,但在线 SLO和灾备 RPO 保持稳定。
回滚优先切回旧读路径,延迟删除旧结构。
回滚通常是停止切读而非逆向删除新数据;旧列/表保持到观察期与备份确认后才 contract。复合场景中,回填用 OFFSET 全表分页并每批十万行,越跑越慢且复制延迟达 20 分钟。
CI runner 为什么是高风险资产,如何隔离不可信构建?¶
技术说明
runner9 执行仓库代码,可能接触源码、缓存、制品、网络与凭证,是供应链高价值入口。不可信 fork PR 与受信主干/发布任务必须使用不同 runner 池、身份和网络;优先一次性临时 runner,任务后销毁,禁止挂载宿主 Docker socket或共享可写工作区。构建容器不是充分边界,还需虚拟机/沙箱、最小 capability、seccomp 和出站限制。
凭证按 job 短期签发且只在受保护事件可得,日志自动遮蔽不能替代不传秘密。缓存按信任域隔离,产物从不可信阶段进入受信阶段前重新验证。runner 镜像打补丁、固定工具版本并生成自身清单;审计包括任务来源、镜像、网络目的地、凭证签发和产物摘要。自托管 runner 需防任务残留和持久化后门。
实践经验
复合场景中,公开 PR 在共享自托管 runner 读取上一个发布任务遗留的云凭证。团队立即隔离 runner、吊销凭证并审计云调用;长期 PR 使用无秘密的一次性沙箱,发布池独立子网且通过 OIDC 获得短期身份。临时 runner 冷启动变慢,使用预热但未分配的干净镜像池降低等待。
面试回答要点
把仓库代码视为不可信输入,runner 等同执行边界。
runner 执行仓库代码,可能接触源码、缓存、制品、网络与凭证,是供应链高价值入口。临时 runner 冷启动变慢,使用预热但未分配的干净镜像池降低等待。
fork、主干、发布按信任域隔离身份与网络。
不可信 fork PR 与受信主干/发布任务必须使用不同 runner 池、身份和网络;优先一次性临时 runner,任务后销毁,禁止挂载宿主 Docker socket或共享可写工作区。团队立即隔离 runner、吊销凭证并审计云调用;长期 PR 使用无秘密的一次性沙箱,发布池独立子网且通过 OIDC 获得短期身份。
runner 临时化,禁止宿主 socket 和跨任务残留。
不可信 fork PR 与受信主干/发布任务必须使用不同 runner 池、身份和网络;优先一次性临时 runner,任务后销毁,禁止挂载宿主 Docker socket或共享可写工作区。复合场景中,公开 PR 在共享自托管 runner 读取上一个发布任务遗留的云凭证。
缓存、制品和凭证也必须跨域重新建立信任。
缓存按信任域隔离,产物从不可信阶段进入受信阶段前重新验证。团队立即隔离 runner、吊销凭证并审计云调用;长期 PR 使用无秘密的一次性沙箱,发布池独立子网且通过 OIDC 获得短期身份。
CI/CD 使用 OIDC 联邦身份为何优于长期云密钥?¶
技术说明
CI 平台为具体 job 签发短期 OIDC10 token,云端信任配置验证 issuer、audience、subject 及仓库/分支/环境等 claims,再交换成短期云会话。这样无需在 CI 保存长期 access key,泄露窗口更短,且每次会话可关联具体 job。关键是信任策略必须收紧,不能只验证 issuer 后允许任意仓库或 fork 获取生产角色。
角色按环境和动作最小权限,生产角色只允许受保护分支/环境及已批准 workflow;限制 session duration,审计记录 token subject、run ID 和角色。工作流文件本身是权限边界,应受 CODEOWNERS/审核和固定第三方 action 版本保护。OIDC 不能防止已获授权 job 中的恶意代码,所以 runner 隔离、审批和制品验证仍需存在。
实践经验
复合场景中,云信任条件使用宽泛 subject 通配符,任意分支都能承担生产角色。审计发现后团队立即收紧 trust policy、撤销旧长期 key;长期按 repo+受保护环境绑定角色,部署前独立批准并记录 run ID。严格条件使分支改名或复用 workflow 更麻烦,故用集中模块生成并做策略测试。
面试回答要点
OIDC 把具体 job 身份换成短期云会话。
CI 平台为具体 job 签发短期 OIDC token,云端信任配置验证 issuer、audience、subject 及仓库/分支/环境等 claims,再交换成短期云会话。复合场景中,云信任条件使用宽泛 subject 通配符,任意分支都能承担生产角色。
同时限制 issuer、audience、subject、仓库与环境 claims。
CI 平台为具体 job 签发短期 OIDC token,云端信任配置验证 issuer、audience、subject 及仓库/分支/环境等 claims,再交换成短期云会话。审计发现后团队立即收紧 trust policy、撤销旧长期 key;长期按 repo+受保护环境绑定角色,部署前独立批准并记录 run ID。
云角色和工作流修改权都遵循最小权限。
角色按环境和动作最小权限,生产角色只允许受保护分支/环境及已批准 workflow;限制 session duration,审计记录 token subject、run ID 和角色。复合场景中,云信任条件使用宽泛 subject 通配符,任意分支都能承担生产角色。
联邦身份缩短泄露窗口,但不替代 runner 与代码信任。
这样无需在 CI 保存长期 access key,泄露窗口更短,且每次会话可关联具体 job。复合场景中,云信任条件使用宽泛 subject 通配符,任意分支都能承担生产角色。
CI/CD 中的 secret、第三方 action 和供应链依赖如何治理?¶
技术说明
secret 按环境、仓库和 job 最小授权,优先动态短期凭证;只有实际需要的 step 才注入,避免通过环境继承给整个任务。遮蔽只处理已知字符串,编码、分片或派生值仍可能泄露,因此不在日志回显、不把秘密放命令行和制品。轮换要有使用清单、自动验证与审计,发现泄露先吊销再清理历史。
第三方 action/plugin 等同执行代码,固定不可变 commit SHA,审查来源、权限和更新;tag 可被移动。依赖经受控代理、哈希校验、SBOM 与漏洞治理,构建出站网络按需限制。流水线变更由 code owner审核,签名/provenance把产物绑定受信 builder。自动依赖更新需通过测试和分批,不因固定版本而永久滞后。
实践经验
复合场景中,流水线引用第三方 action 的浮动主分支,上游被入侵后尝试读取环境 secret。出站策略阻断外传但仍触发事件响应;团队固定已审计 SHA、轮换凭证并重建制品。长期建立允许列表和自动更新 PR,发布 job 不加载非必要 action。严格允许列表降低插件便利性,平台提供内部封装补偿。
面试回答要点
secret 最小作用域、短期化,不依赖日志遮蔽兜底。
secret 按环境、仓库和 job 最小授权,优先动态短期凭证;只有实际需要的 step 才注入,避免通过环境继承给整个任务。复合场景中,流水线引用第三方 action 的浮动主分支,上游被入侵后尝试读取环境 secret。
第三方 action 固定不可变 SHA 并审查权限。
第三方 action/plugin 等同执行代码,固定不可变 commit SHA,审查来源、权限和更新;tag 可被移动。复合场景中,流水线引用第三方 action 的浮动主分支,上游被入侵后尝试读取环境 secret。
限制构建出站,生成 SBOM/provenance 并验证。
依赖经受控代理、哈希校验、SBOM 与漏洞治理,构建出站网络按需限制。出站策略阻断外传但仍触发事件响应;团队固定已审计 SHA、轮换凭证并重建制品。
固定依赖同时要有持续、安全的更新通道。
自动依赖更新需通过测试和分批,不因固定版本而永久滞后。长期建立允许列表和自动更新 PR,发布 job 不加载非必要 action。
如何建立发布治理、变更风险评分与 DORA 指标闭环?¶
技术说明
发布治理从风险而非审批数量出发:依据影响范围、变更类型、可逆性、测试证据、时间窗口和依赖状态决定自动发布、分批、人工批准或冻结。标准变更走自助模板,高风险变更要求演练和双人;紧急 break-glass 只缩短流程,不跳过身份、记录、验证与事后复盘。变更日历避免共享关键依赖同时大改,但永久冻结会积累更大批次。
DORA 当前的软件交付绩效模型包含五项:变更前置时间、部署频率、失败部署恢复时间、变更失败率和部署返工率;用于看系统趋势而非个人绩效排名。口径需定义生产、失败、恢复、回滚与非计划修复,按服务风险分组;同时看发布批量、排队时间、SLO和用户影响,防止刷指标。每次事故把逃逸原因反馈到模板、测试、金丝雀和平台护栏。
实践经验
复合场景中,团队为提高部署频率把配置微改拆成大量无意义发布,事故率反升。治理组停止个人排名,改看服务级趋势、批量与SLO,并用风险评分决定波次和观察窗;长期把失败分类回写控制项。更严格高风险门禁增加 lead time,但低风险自动化更快,总体交付反而稳定。
面试回答要点
风险分级决定控制强度,标准变更尽量自动化。
发布治理从风险而非审批数量出发:依据影响范围、变更类型、可逆性、测试证据、时间窗口和依赖状态决定自动发布、分批、人工批准或冻结。治理组停止个人排名,改看服务级趋势、批量与SLO,并用风险评分决定波次和观察窗;长期把失败分类回写控制项。
break-glass 仍需可追溯、验证和事后复盘。
标准变更走自助模板,高风险变更要求演练和双人;紧急 break-glass 只缩短流程,不跳过身份、记录、验证与事后复盘。治理组停止个人排名,改看服务级趋势、批量与SLO,并用风险评分决定波次和观察窗;长期把失败分类回写控制项。
DORA 衡量系统改进,不用于个人绩效竞赛。
DORA 当前的软件交付绩效模型包含五项:变更前置时间、部署频率、失败部署恢复时间、变更失败率和部署返工率;用于看系统趋势而非个人绩效排名。治理组停止个人排名,改看服务级趋势、批量与SLO,并用风险评分决定波次和观察窗;长期把失败分类回写控制项。
指标口径、服务分组与用户影响共同解释趋势。
口径需定义生产、失败、恢复、回滚与非计划修复,按服务风险分组;同时看发布批量、排队时间、SLO和用户影响,防止刷指标。治理组停止个人排名,改看服务级趋势、批量与SLO,并用风险评分决定波次和观察窗;长期把失败分类回写控制项。
-
CI/CD 是 Continuous Integration / Continuous Delivery(或 Deployment)的缩写,即持续集成与持续交付(或持续部署),用于自动完成代码验证、构建和发布。 ↩
-
控制平面负责保存期望状态、策略和调度决策;它通常不直接承载实际业务请求或构建数据。 ↩
-
制品是构建产生并可被存储、验证和部署的版本化输出,例如容器镜像、软件包或二进制文件。 ↩
-
PR 是 Pull Request(拉取请求)的缩写,表示请求将一组代码变更合并到目标分支的评审流程。 ↩
-
SLO 是 Service Level Objective(服务等级目标)的缩写,用可量化目标描述服务期望达到的可靠性水平。 ↩
-
break-glass 指紧急情况下受控绕过常规流程的机制;仍须限定权限、完整审计并在事后复盘。 ↩
-
SBOM 是 Software Bill of Materials(软件物料清单),列出制品包含的软件组件及版本。可参考 CISA 的 SBOM 说明。 ↩
-
provenance(来源证明)记录制品由什么源码、依赖和构建过程产生,用于验证供应链来源与完整性。 ↩
-
CI runner 是实际领取并执行流水线任务的计算环境,因此会直接运行仓库中的代码并接触相应凭证和网络。 ↩
-
OIDC 是 OpenID Connect,一种建立在 OAuth 2.0 之上的身份协议,可让 CI 任务以可验证身份换取短期云凭证。参见 OpenID Connect 官方说明。 ↩