跳转至

IaC、配置管理与 GitOps

Terraform/OpenTofu state 的作用、内容与一致性边界是什么?

技术说明

Terraform/OpenTofu1 的 state2 保存配置资源地址到远端对象 ID 的映射、已知属性、依赖与元数据,使工具能比较配置、先前状态和 provider3 读取的真实对象并生成 plan。它不是云资源本身,也不是配置的完整替代;即使配置未变,refresh 仍可能发现外部变化。state 中可能包含敏感属性,即便 CLI 标记 sensitive 只隐藏显示,也不保证底层 state 不存明文。

一次 plan/apply4 涉及远端 API 与 state 更新,无法形成跨所有 provider 的分布式事务:资源已创建但进程在写 state 前中断,会出现“真实存在、state 不知道”。因此后端要具备持久性、访问控制、版本/备份和锁;故障后先读 state、云审计和对象 ID,再选择 import、移除幽灵项或重新 apply,禁止凭感觉手改 JSON。

实践经验

复合场景中,流水线创建数据库后网络中断,state 未记录,重跑计划尝试再建同名实例。云活动日志证明首个创建成功。止血是冻结 apply,核对配置地址与资源 ID 后 import,并重新 plan 确认 no-op;长期使用可靠远端后端、保存 apply 日志和自动中断恢复 runbook。import 只修映射,不证明所有参数一致,后续计划仍需审阅可能的替换。

面试回答要点

state 是资源地址与真实对象的映射及已知属性,不是事实世界本身。

state 保存配置资源地址到远端对象 ID 的映射、已知属性、依赖与元数据,使工具能比较配置、先前状态和 provider 读取的真实对象并生成 plan。止血是冻结 apply,核对配置地址与资源 ID 后 import,并重新 plan 确认 no-op;长期使用可靠远端后端、保存 apply 日志和自动中断恢复 runbook。

sensitive 输出不会自动加密 state。

state 中可能包含敏感属性,即便 CLI 标记 sensitive 只隐藏显示,也不保证底层 state 不存明文。止血是冻结 apply,核对配置地址与资源 ID 后 import,并重新 plan 确认 no-op;长期使用可靠远端后端、保存 apply 日志和自动中断恢复 runbook。

provider API 与 state 写入不是原子事务,要处理部分成功。

一次 apply 涉及远端 API 与 state 更新,无法形成跨所有 provider 的分布式事务:资源已创建但进程在写 state 前中断,会出现“真实存在、state 不知道”。云活动日志证明首个创建成功。

恢复基于对象 ID、审计和重新 plan,不直接编辑 state。

因此后端要具备持久性、访问控制、版本/备份和锁;故障后先读 state、云审计和对象 ID,再选择 import、移除幽灵项或重新 apply,禁止凭感觉手改 JSON。止血是冻结 apply,核对配置地址与资源 ID 后 import,并重新 plan 确认 no-op;长期使用可靠远端后端、保存 apply 日志和自动中断恢复 runbook。

远端后端与 state locking 如何防并发,锁失效时怎么办?

技术说明

远端 backend 集中保存 state,并可通过后端原生条件写/锁机制阻止多个 writer 同时 plan/apply(具体能力依后端)。锁保护的是 state 操作,不会阻止控制台、其他 state 或外部控制器修改同一云对象。CI 应为每个 state 建单写队列,锁等待有上限,apply 使用与已审 plan 对应的制品,并记录操作者与提交。

锁可能因进程崩溃留下,但 force-unlock 只有确认原持有者已停止且没有远端操作继续运行时才能做。先查流水线、锁元数据、进程与云审计;错误解锁会让两个 apply 并发覆盖 state。后端启用版本历史、强访问控制与加密,恢复时保留旧版本,并避免把 prod 和非 prod 放在同一宽权限路径。

实践经验

复合场景中,CI 超时后新任务遇到锁,值班直接 force-unlock;原任务实际仍在 provider 超时重试,两个 apply 同时修改路由。云审计时间线和两份日志证实并发。止血是取消两条流水线、冻结路由变更并从最后可信 state 对账;长期让 runner 超时先可靠终止子进程、锁解除需双人确认且检查活动 API。等待会拉长恢复,但比并发写造成未知状态安全。

面试回答要点

state lock 只序列化该状态的 writer,不锁住真实云资源。

远端 backend 集中保存 state,并可通过后端原生条件写/锁机制阻止多个 writer 同时 plan/apply(具体能力依后端)。止血是取消两条流水线、冻结路由变更并从最后可信 state 对账;长期让 runner 超时先可靠终止子进程、锁解除需双人确认且检查活动 API。

单写 CI 队列与后端锁是两道独立保护。

CI 应为每个 state 建单写队列,锁等待有上限,apply 使用与已审 plan 对应的制品,并记录操作者与提交。复合场景中,CI 超时后新任务遇到锁,值班直接 force-unlock;原任务实际仍在 provider 超时重试,两个 apply 同时修改路由。

force-unlock 前必须证明旧 writer 已死亡且远端动作结束。

锁可能因进程崩溃留下,但 force-unlock 只有确认原持有者已停止且没有远端操作继续运行时才能做。止血是取消两条流水线、冻结路由变更并从最后可信 state 对账;长期让 runner 超时先可靠终止子进程、锁解除需双人确认且检查活动 API。

开启 state 版本与审计,便于对账而非盲目回滚。

先查流水线、锁元数据、进程与云审计;错误解锁会让两个 apply 并发覆盖 state。止血是取消两条流水线、冻结路由变更并从最后可信 state 对账;长期让 runner 超时先可靠终止子进程、锁解除需双人确认且检查活动 API。

如何保护 state 中的敏感数据并设计访问边界?

技术说明

state 常含数据库口令、连接字符串、私钥片段或 provider 返回的敏感属性。sensitive = true 只抑制终端/UI展示,不能从 state 删除值。后端应启用传输与静态加密、独立密钥、版本保护、最小读写权限、访问日志和私网入口;CI 以短期身份访问,开发者通常只需受控 plan 能力,不应默认下载生产 state。

从源头减少 secret 进入 state:让 Terraform 创建 secret 的容器/引用而非读取明文,使用云工作负载身份,或由专门 secret 流程在资源创建后注入。provider 和 debug 日志也可能泄露敏感值,事故采集前要脱敏。状态备份、复制和本地 .terraform 缓存同样纳入数据分类和销毁策略。

实践经验

复合场景中,工程师为排障把 prod state 附到工单,导致数据库密码扩散到多人可见系统。下载日志确认暴露范围。止血是删除附件、轮换全部可推导凭证并审计访问;长期限制 state 下载、提供脱敏查询工具,数据库改由外部 secret manager 生成和轮换。减少明文输出会让调试更困难,应提供按审批临时访问的审计通道。

面试回答要点

sensitive 是显示控制,不是存储加密。

后端应启用传输与静态加密、独立密钥、版本保护、最小读写权限、访问日志和私网入口;CI 以短期身份访问,开发者通常只需受控 plan 能力,不应默认下载生产 state。止血是删除附件、轮换全部可推导凭证并审计访问;长期限制 state 下载、提供脱敏查询工具,数据库改由外部 secret manager 生成和轮换。

state、备份、本地缓存和日志都属于同一敏感数据面。

状态备份、复制和本地 .terraform 缓存同样纳入数据分类和销毁策略。止血是删除附件、轮换全部可推导凭证并审计访问;长期限制 state 下载、提供脱敏查询工具,数据库改由外部 secret manager 生成和轮换。

用短期身份、私网、最小权限和访问审计保护后端。

后端应启用传输与静态加密、独立密钥、版本保护、最小读写权限、访问日志和私网入口;CI 以短期身份访问,开发者通常只需受控 plan 能力,不应默认下载生产 state。减少明文输出会让调试更困难,应提供按审批临时访问的审计通道。

设计资源时尽量只在 state 保存 secret 引用而非值。

从源头减少 secret 进入 state:让 Terraform 创建 secret 的容器/引用而非读取明文,使用云工作负载身份,或由专门 secret 流程在资源创建后注入。止血是删除附件、轮换全部可推导凭证并审计访问;长期限制 state 下载、提供脱敏查询工具,数据库改由外部 secret manager 生成和轮换。

如何发现和治理 drift,什么时候不应自动纠正?

技术说明

drift5 是真实基础设施与受管理配置/state 的偏离,来源可能是控制台应急修改、其他自动化、provider 默认变化或外部服务自调节。定期只读 plan/refresh 可发现差异,但需区分配置意图变更、真实漂移和 provider 规范化噪声。ignore_changes 只适合明确由另一控制器拥有的字段,滥用会永久遮蔽风险。

自动 reconcile 适合低风险、可逆且所有权清晰的属性;安全组开放、路由、数据库参数或事故期间的临时修复不应未经评估直接覆盖。治理流程应标记资源 owner、差异严重性和变更来源,选择把应急变更反写代码、回退真实对象或转移字段所有权,并给临时例外设置到期时间。

实践经验

复合场景中,值班为恢复服务临时加一条路由,夜间 drift bot 自动 apply 删除,事故二次发生。审计与流水线记录证明两个控制面争夺同一字段。止血是暂停自动纠正、恢复路由并登记临时变更;长期 drift 只自动开单,高风险资源需审批,事故变更必须在限定时间内回写代码。降低自动修复速度会延长低风险漂移窗口,可按资源等级分层。

面试回答要点

drift 发现与 drift 自动修复是两个不同决策。

drift 是真实基础设施与受管理配置/state 的偏离,来源可能是控制台应急修改、其他自动化、provider 默认变化或外部服务自调节。止血是暂停自动纠正、恢复路由并登记临时变更;长期 drift 只自动开单,高风险资源需审批,事故变更必须在限定时间内回写代码。

先判定字段所有权和变更来源,再决定纠正方向。

治理流程应标记资源 owner、差异严重性和变更来源,选择把应急变更反写代码、回退真实对象或转移字段所有权,并给临时例外设置到期时间。止血是暂停自动纠正、恢复路由并登记临时变更;长期 drift 只自动开单,高风险资源需审批,事故变更必须在限定时间内回写代码。

ignore_changes 是所有权边界工具,不是消除噪声的万能开关。

自动 reconcile 适合低风险、可逆且所有权清晰的属性;安全组开放、路由、数据库参数或事故期间的临时修复不应未经评估直接覆盖。止血是暂停自动纠正、恢复路由并登记临时变更;长期 drift 只自动开单,高风险资源需审批,事故变更必须在限定时间内回写代码。

事故临时变更要有记录、到期和代码回写路径。

治理流程应标记资源 owner、差异严重性和变更来源,选择把应急变更反写代码、回退真实对象或转移字段所有权,并给临时例外设置到期时间。复合场景中,值班为恢复服务临时加一条路由,夜间 drift bot 自动 apply 删除,事故二次发生。

Terraform/OpenTofu 模块应如何划分接口和版本?

技术说明

模块应围绕稳定的业务/平台能力边界,而不是把每个资源包一层或构造一个包含所有云服务的巨型模块。输入只暴露调用者真正需要的决策,输出提供下游稳定契约;内部资源地址属于实现细节。变量应有类型、验证、默认值边界和文档,危险组合用 precondition/check 约束,避免数十个布尔开关形成不可测试状态空间。

模块版本应固定到可审计发布,变更按兼容性管理;resource 重命名使用 moved block 等迁移机制,重大版本给出 state 迁移与回退说明。测试至少覆盖静态校验、plan 契约和临时环境集成。共享模块不能同时掌控应用发布节奏与全局网络,blast radius 与所有权应决定 state/模块边界。

实践经验

复合场景中,网络模块新增默认开启的 NAT 变更,数十个环境升级后成本和路由同时变化。计划很长,调用方未识别隐式默认。止血是固定旧模块版本、回退受影响环境并核对流量;长期重大行为默认 opt-in、用 golden plan/集成测试与变更日志,按环境分批升级。更严格版本固定会延迟安全修复,需要自动依赖更新和升级 SLA。

面试回答要点

模块封装稳定能力和所有权,而非单纯减少代码行数。

模块应围绕稳定的业务/平台能力边界,而不是把每个资源包一层或构造一个包含所有云服务的巨型模块。止血是固定旧模块版本、回退受影响环境并核对流量;长期重大行为默认 opt-in、用 golden plan/集成测试与变更日志,按环境分批升级。

输入最小、强类型、有验证,输出作为稳定契约。

输入只暴露调用者真正需要的决策,输出提供下游稳定契约;内部资源地址属于实现细节。止血是固定旧模块版本、回退受影响环境并核对流量;长期重大行为默认 opt-in、用 golden plan/集成测试与变更日志,按环境分批升级。

版本固定与自动升级机制需同时存在。

模块版本应固定到可审计发布,变更按兼容性管理;resource 重命名使用 moved block 等迁移机制,重大版本给出 state 迁移与回退说明。更严格版本固定会延迟安全修复,需要自动依赖更新和升级 SLA。

重构资源地址必须配 state 迁移,不让调用方被动重建。

输入只暴露调用者真正需要的决策,输出提供下游稳定契约;内部资源地址属于实现细节。计划很长,调用方未识别隐式默认。

provider 与 lock file 如何管理,升级时为什么会出现意外差异?

技术说明

required providers 声明来源地址与可接受版本约束,dependency lock file 记录实际选中版本及校验和,使不同执行环境使用一致插件。根模块应提交 lock file,模块通常声明兼容范围而不替调用方锁死具体版本。provider configuration 包含区域、端点、默认标签和身份;alias 可配置多区域/多账号实例,子模块必须显式接收所需 provider,避免落到错误默认账号。

provider 升级可能改变 schema、默认值、diff 抑制和 API 行为,即使 HCL 未变也会出现 plan 差异。升级应单独 PR,阅读官方 changelog,在副本 state 或非生产环境执行 plan/apply,核对 plan JSON 中 replace 与敏感资源,并更新多平台 checksum。不要无边界使用 -upgrade,更不能把 provider 缓存当版本锁。

实践经验

复合场景中,CI 未提交 lock file,新 runner 选到新版 provider,把负载均衡器某属性从“未设置”规范化为默认值并计划替换。发布门禁发现 replace 数量异常而暂停。长期固定 provider、对 replace/destroy 设政策门禁,并将升级拆成独立变更。固定版本会错过补丁,因此机器人定期提出可测试的升级 PR,而非永久冻结。

面试回答要点

version constraint 定义范围,lock file 固定实际版本与 checksum。

required providers 声明来源地址与可接受版本约束,dependency lock file 记录实际选中版本及校验和,使不同执行环境使用一致插件。复合场景中,CI 未提交 lock file,新 runner 选到新版 provider,把负载均衡器某属性从“未设置”规范化为默认值并计划替换。

多账号/区域 provider 必须显式 alias 和传递。

provider configuration 包含区域、端点、默认标签和身份;alias 可配置多区域/多账号实例,子模块必须显式接收所需 provider,避免落到错误默认账号。复合场景中,CI 未提交 lock file,新 runner 选到新版 provider,把负载均衡器某属性从“未设置”规范化为默认值并计划替换。

provider 升级本身就是基础设施变更,要单独审阅。

升级应单独 PR,阅读官方 changelog,在副本 state 或非生产环境执行 plan/apply,核对 plan JSON 中 replace 与敏感资源,并更新多平台 checksum。长期固定 provider、对 replace/destroy 设政策门禁,并将升级拆成独立变更。

对 destroy/replace 与目标账号做机器门禁。

provider configuration 包含区域、端点、默认标签和身份;alias 可配置多区域/多账号实例,子模块必须显式接收所需 provider,避免落到错误默认账号。长期固定 provider、对 replace/destroy 设政策门禁,并将升级拆成独立变更。

lifecycle 的 create_before_destroy、prevent_destroy、ignore_changes 有哪些真实边界?

技术说明

create_before_destroy 调整替换顺序,但前提是名称、配额、唯一性和依赖允许新旧并存;它不自动切流或迁移数据。prevent_destroy 在配置存在时阻止计划删除,能挡误操作,却不能防控制台删除、移除整个资源块后的所有场景或 state 操作。ignore_changes 让更新时忽略指定属性,适合该字段由外部控制器拥有,但会隐藏真实漂移。

生命周期配置应与服务切换协议结合:新资源验证、DNS/路由切换、连接排空、旧资源延迟删除。对数据库、密钥和网络边界,单靠 lifecycle 不够,还需云端删除保护、policy-as-code 与备份。若依赖图因 create-before-destroy 扩散,应在 plan 中检查峰值资源和潜在循环。

实践经验

复合场景中,给有全局唯一名称的存储桶启用 create_before_destroy,重命名计划仍无法先建目标,流水线卡住。团队改为显式新建不同名称、复制校验数据、切换引用后再保留旧桶。长期将迁移建模为多阶段变更而非期望 lifecycle 自动完成。双资源期会增加成本且带来双写/权限不一致风险,需要清单与退出条件。

面试回答要点

lifecycle 调整图行为,不提供数据迁移或流量切换协议。

create_before_destroy 调整替换顺序,但前提是名称、配额、唯一性和依赖允许新旧并存;它不自动切流或迁移数据。团队改为显式新建不同名称、复制校验数据、切换引用后再保留旧桶。

create-before-destroy 受唯一名称、配额和并存能力限制。

create_before_destroy 调整替换顺序,但前提是名称、配额、唯一性和依赖允许新旧并存;它不自动切流或迁移数据。复合场景中,给有全局唯一名称的存储桶启用 create_before_destroy,重命名计划仍无法先建目标,流水线卡住。

prevent_destroy 不是云端删除保护。

对数据库、密钥和网络边界,单靠 lifecycle 不够,还需云端删除保护、policy-as-code 与备份。复合场景中,给有全局唯一名称的存储桶启用 create_before_destroy,重命名计划仍无法先建目标,流水线卡住。

ignore_changes 必须对应明确外部所有者并定期审计。

ignore_changes 让更新时忽略指定属性,适合该字段由外部控制器拥有,但会隐藏真实漂移。复合场景中,给有全局唯一名称的存储桶启用 create_before_destroy,重命名计划仍无法先建目标,流水线卡住。

import、moved block 与 state mv 分别用于什么场景?

技术说明

import 将已存在的远端对象绑定到配置中的资源地址,之后仍需补齐配置并运行 plan;它不会自动证明配置与对象一致。import block 可把导入意图纳入可审阅配置。moved block 声明地址从旧路径迁到新路径,适合可版本化模块重构;state mv 是直接状态操作,适合受控一次性迁移,但审计与复现性较弱。

迁移前要备份 state、冻结源/目标全部 writer、列出地址与对象 ID,并在副本上预演;迁移后必须得到预期 no-op 或仅有已解释差异。跨 state 没有原子事务,也不应把同一远端对象同时绑定到两个资源地址。推荐在全局冻结窗口内先让源 state 无销毁地停止管理(工具支持时使用 removed block 且 destroy = false,否则走受控 state rm),确认远端对象仍存在后立即在目标 import;或使用工具明确支持的直接 state 迁移。短暂“无 state 映射”窗口由全局写锁保护,优于目标先 import 造成双重所有权。state rm 本身不删除云资源,但误删源配置并正常 apply 则可能真的销毁对象。

实践经验

复合场景中,团队重构 module 路径未声明 moved,plan 显示销毁生产数据库再创建。评审门禁阻止 apply。止血是加入 moved block 并验证地址映射;长期要求模块重构附 state migration 测试和 destroy=0 证明。若确需替换,则另建迁移计划。保留 moved 声明会增加代码历史,但可支持未跨越中间版本的调用方。

面试回答要点

import 绑定现有对象,仍要完整配置与后续 plan。

import 将已存在的远端对象绑定到配置中的资源地址,之后仍需补齐配置并运行 plan;它不会自动证明配置与对象一致。复合场景中,团队重构 module 路径未声明 moved,plan 显示销毁生产数据库再创建。

moved block 是可版本化重构,优于不可追踪的手工操作。

moved block 声明地址从旧路径迁到新路径,适合可版本化模块重构;state mv 是直接状态操作,适合受控一次性迁移,但审计与复现性较弱。止血是加入 moved block 并验证地址映射;长期要求模块重构附 state migration 测试和 destroy=0 证明。

跨 state 迁移需冻结两端写入,源端无销毁地释放映射后再由目标接管。

推荐在全局冻结窗口内先让源 state 无销毁地停止管理(工具支持时使用 removed block 且 destroy = false,否则走受控 state rm),确认远端对象仍存在后立即在目标 import;或使用工具明确支持的直接 state 迁移。止血是加入 moved block 并验证地址映射;长期要求模块重构附 state migration 测试和 destroy=0 证明。

state rm 不删真实资源,却可能让它失去治理。

state rm 本身不删除云资源,但误删源配置并正常 apply 则可能真的销毁对象。止血是加入 moved block 并验证地址映射;长期要求模块重构附 state migration 测试和 destroy=0 证明。

如何设计“计划一次、审批后应用同一计划”的 IaC 流水线?

技术说明

流水线应在固定代码提交、依赖锁、变量集、身份和目标 state 上执行 init/validate/plan,输出二进制 plan 与可读摘要;政策检查解析机器可读 plan,审批记录 commit、plan hash、目标环境与过期时间。apply 消费同一已保存 plan,而不是审批后重新 plan,这能减少评审与执行之间的差异。任何代码、state 或外部条件显著变化都应让 plan 失效并重新审批。

凭证使用短期 OIDC,plan 身份最好只读或最小规划权限,apply 身份按环境隔离;生产 state 单写、环境保护和审计不可少。门禁关注 delete/replace、权限扩大、公共暴露、成本与备份状态,但 human review 不能阅读数千行噪声,因此应提供风险摘要和关键属性 diff。紧急通道仍走版本化变更并自动过期。

实践经验

复合场景中,审批看到的 plan 无删除,但 apply 阶段重新生成计划时 state 已被另一任务更新,最终删除了共享规则。证据是两个 plan hash 不同。止血是回滚规则并冻结队列;长期 apply 只接受已签名 plan artifact,state 变更导致 apply 失败并重规划。计划有效期缩短会增加重复审批,应通过减少排队时间改善体验。

面试回答要点

plan 的代码、变量、provider、state 和目标身份均要可追溯。

流水线应在固定代码提交、依赖锁、变量集、身份和目标 state 上执行 init/validate/plan,输出二进制 plan 与可读摘要;政策检查解析机器可读 plan,审批记录 commit、plan hash、目标环境与过期时间。复合场景中,审批看到的 plan 无删除,但 apply 阶段重新生成计划时 state 已被另一任务更新,最终删除了共享规则。

审批与 apply 必须绑定同一个 plan hash。

apply 消费同一已保存 plan,而不是审批后重新 plan,这能减少评审与执行之间的差异。复合场景中,审批看到的 plan 无删除,但 apply 阶段重新生成计划时 state 已被另一任务更新,最终删除了共享规则。

高风险 diff 用机器策略提炼,人审聚焦意图与权衡。

门禁关注 delete/replace、权限扩大、公共暴露、成本与备份状态,但 human review 不能阅读数千行噪声,因此应提供风险摘要和关键属性 diff。复合场景中,审批看到的 plan 无删除,但 apply 阶段重新生成计划时 state 已被另一任务更新,最终删除了共享规则。

紧急变更缩短流程但不绕过审计和代码回写。

流水线应在固定代码提交、依赖锁、变量集、身份和目标 state 上执行 init/validate/plan,输出二进制 plan 与可读摘要;政策检查解析机器可读 plan,审批记录 commit、plan hash、目标环境与过期时间。计划有效期缩短会增加重复审批,应通过减少排队时间改善体验。

Terraform/OpenTofu 依赖图、unknown value、for_each 与 count 有何影响?

技术说明

引用资源属性会建立隐式依赖,depends_on 只用于真实但无法由数据流表达的顺序;滥用会扩大 unknown、降低并行度。plan 阶段 provider 尚未创建资源,某些属性为 (known after apply),因此要求键集合在 plan 时已知的 for_each 不能依赖新资源的未知 ID。应以配置中稳定业务键作为实例地址,而不是运行时生成值。

count 用数字索引,列表中间插入/删除可能改变多个地址;for_each 用稳定 key,更适合具名对象,但 key 也不得包含敏感或不稳定信息。并行 apply 遵循依赖图而非文件顺序。若外部 API 有未声明顺序需求,应优先通过明确输出输入建模,而非靠低并行度掩盖 provider/依赖问题。

实践经验

复合场景中,防火墙规则以 count 遍历排序列表,新增首项导致大量地址重排和替换。计划门禁发现变更规模异常。团队迁移到以规则业务 ID 为 key 的 for_each,配 moved 映射保持对象。长期模块接口要求稳定键。稳定键一旦成为 state 地址就难以更名,需要设计不含可变描述的信息。

面试回答要点

依赖来自属性数据流,depends_on 只补不可见依赖。

引用资源属性会建立隐式依赖,depends_on 只用于真实但无法由数据流表达的顺序;滥用会扩大 unknown、降低并行度。稳定键一旦成为 state 地址就难以更名,需要设计不含可变描述的信息。

unknown 是 plan/apply 两阶段模型的正常结果。

plan 阶段 provider 尚未创建资源,某些属性为 (known after apply),因此要求键集合在 plan 时已知的 for_each 不能依赖新资源的未知 ID。计划门禁发现变更规模异常。

for_each key 必须在 plan 时已知且稳定。

plan 阶段 provider 尚未创建资源,某些属性为 (known after apply),因此要求键集合在 plan 时已知的 for_each 不能依赖新资源的未知 ID。团队迁移到以规则业务 ID 为 key 的 for_each,配 moved 映射保持对象。

地址稳定性直接决定重构是否产生大面积替换。

应以配置中稳定业务键作为实例地址,而不是运行时生成值。复合场景中,防火墙规则以 count 遍历排序列表,新增首项导致大量地址重排和替换。

IaC 变量、输出与 secret 应如何在 CI 中传递?

技术说明

变量来源可能是显式参数、环境、变量文件或平台变量集,优先建立单一、版本化且可审计的非敏感配置来源,避免优先级叠加造成“本地与 CI 不同”。secret 不提交仓库、不作为命令行明文出现在进程/日志,CI 通过短期身份从 secret manager 获取;provider 能用工作负载身份时,不传长期 access key。

标记 input/output sensitive 可减少常规显示,但 secret 仍可能进入 state 和 provider debug 日志。输出只暴露下游需要的稳定值,跨 state 读取会扩大耦合与权限,应考虑服务目录/参数存储作为契约。流水线关闭敏感 trace,产物脱敏,fork PR 不获得生产 secret,并为凭证使用记录 audience、环境与过期时间。

实践经验

复合场景中,CI 为调试开启详细日志,provider 请求头和变量值被保存为长期构建产物。访问审计显示多人下载。止血是撤销凭证、删除产物并检查滥用;长期默认禁用敏感 debug,使用 OIDC 临时令牌、日志过滤和受限保留。降低日志详细度会影响排障,因此提供短时、审批、自动销毁的安全诊断作业。

面试回答要点

区分配置值、secret 值和跨系统契约三类数据。

输出只暴露下游需要的稳定值,跨 state 读取会扩大耦合与权限,应考虑服务目录/参数存储作为契约。复合场景中,CI 为调试开启详细日志,provider 请求头和变量值被保存为长期构建产物。

sensitive 只是展示保护,仍需保护 state 与日志。

标记 input/output sensitive 可减少常规显示,但 secret 仍可能进入 state 和 provider debug 日志。复合场景中,CI 为调试开启详细日志,provider 请求头和变量值被保存为长期构建产物。

CI 使用短期联邦身份,PR 上下文严格隔离。

secret 不提交仓库、不作为命令行明文出现在进程/日志,CI 通过短期身份从 secret manager 获取;provider 能用工作负载身份时,不传长期 access key。复合场景中,CI 为调试开启详细日志,provider 请求头和变量值被保存为长期构建产物。

变量来源和优先级必须固定并能从执行记录重建。

变量来源可能是显式参数、环境、变量文件或平台变量集,优先建立单一、版本化且可审计的非敏感配置来源,避免优先级叠加造成“本地与 CI 不同”。复合场景中,CI 为调试开启详细日志,provider 请求头和变量值被保存为长期构建产物。

多环境应使用 workspace、目录还是独立 state/账号?

技术说明

CLI workspace 主要让同一配置选择不同 state,不会自动提供账号、凭证、审批或网络隔离;若一个误选 workspace 的命令可触达生产,边界过弱。环境差异小且同一生命周期时可用 workspace,但生产与非生产、不同区域或团队通常应使用独立账号/订阅、state 后端路径和执行身份,并以共享版本化模块复用逻辑。

复制整套目录会造成漂移,单一巨型 state 又放大锁竞争和爆炸半径。划分依据是所有权、变更频率、故障域和依赖关系;跨 state 通过稳定输出契约连接,避免循环 remote-state 依赖。环境选择必须显式显示在 plan 摘要和审批界面,并用云账号 ID/租户 ID precondition 防止打错目标。

实践经验

复合场景中,工程师本地 shell 保留 prod workspace,却使用测试变量运行 apply,险些修改生产网络;账号 ID 门禁在 plan 阶段拒绝。长期生产只允许 CI 身份,后端、账号和目录独立,workspace 仅用于短期预览环境。更多 state 增加编排复杂度,需要依赖图和变更排序服务支撑。

面试回答要点

workspace 是状态选择机制,不是强环境隔离机制。

CLI workspace 主要让同一配置选择不同 state,不会自动提供账号、凭证、审批或网络隔离;若一个误选 workspace 的命令可触达生产,边界过弱。长期生产只允许 CI 身份,后端、账号和目录独立,workspace 仅用于短期预览环境。

生产边界优先账号、身份、state 与审批隔离。

环境差异小且同一生命周期时可用 workspace,但生产与非生产、不同区域或团队通常应使用独立账号/订阅、state 后端路径和执行身份,并以共享版本化模块复用逻辑。长期生产只允许 CI 身份,后端、账号和目录独立,workspace 仅用于短期预览环境。

state 拆分按所有权和故障半径,不按资源种类机械切割。

划分依据是所有权、变更频率、故障域和依赖关系;跨 state 通过稳定输出契约连接,避免循环 remote-state 依赖。更多 state 增加编排复杂度,需要依赖图和变更排序服务支撑。

执行前机器校验目标账号/区域,避免只靠名称提示。

环境差异小且同一生命周期时可用 workspace,但生产与非生产、不同区域或团队通常应使用独立账号/订阅、state 后端路径和执行身份,并以共享版本化模块复用逻辑。复合场景中,工程师本地 shell 保留 prod workspace,却使用测试变量运行 apply,险些修改生产网络;账号 ID 门禁在 plan 阶段拒绝。

policy as code 应检查哪些 IaC 风险,怎样降低误报和绕过?

技术说明

政策可在静态配置、plan 和云端运行态不同层检查。plan 层能看到资源变化,适合禁止公共存储、过宽安全组、未加密数据、无标签、关键资源 delete/replace、跨区冗余不足等;但 unknown 属性和 provider 扩展会限制判断。政策分 deny、需审批和告警三档,并返回具体资源地址、失败字段与修复建议。

规则需有 owner、测试、版本、例外、到期和指标;先对历史 plan 回放评估误报,再渐进 enforce。不能让用户通过换资源类型、模块或手工控制台轻易绕过,所以云组织策略和检测形成第二层。break-glass 例外应绑定工单、最小 scope、短时生效并事后自动复核,而非永久白名单。

实践经验

复合场景中,一条“所有安全组不得 0.0.0.0/0”的规则阻塞了合法公网 LB,团队开始大量全局豁免。长期改为结合端口、资源类型、前置 WAF 与数据标签判定风险,并让例外只作用于资源地址和期限。误报下降后恢复强制。策略更复杂会增加维护成本,需用真实事故与高风险面优先排序。

面试回答要点

在 plan 评估意图,在云组织层阻断绕过,在运行态检测漂移。

不能让用户通过换资源类型、模块或手工控制台轻易绕过,所以云组织策略和检测形成第二层。复合场景中,一条“所有安全组不得 0.0.0.0/0”的规则阻塞了合法公网 LB,团队开始大量全局豁免。

规则输出必须可定位、可修复并有严重性分级。

政策分 deny、需审批和告警三档,并返回具体资源地址、失败字段与修复建议。复合场景中,一条“所有安全组不得 0.0.0.0/0”的规则阻塞了合法公网 LB,团队开始大量全局豁免。

例外最小化、限时、可审计且到期复核。

break-glass 例外应绑定工单、最小 scope、短时生效并事后自动复核,而非永久白名单。长期改为结合端口、资源类型、前置 WAF 与数据标签判定风险,并让例外只作用于资源地址和期限。

用历史 plan 和规则测试控制误报,避免政策失去公信力。

规则需有 owner、测试、版本、例外、到期和指标;先对历史 plan 回放评估误报,再渐进 enforce。复合场景中,一条“所有安全组不得 0.0.0.0/0”的规则阻塞了合法公网 LB,团队开始大量全局豁免。

IaC 测试如何覆盖语法、契约、集成与破坏性风险?

技术说明

测试金字塔可包含格式/validate、lint 与安全扫描,变量验证和函数级测试,基于 plan JSON 的契约断言,以及临时账号中的 apply→验证→destroy 集成测试。静态测试快但不能发现 provider API、权限、配额与真实路由问题;集成测试真实但慢、有成本且清理失败会泄露资源,因此按模块风险分层。

关键模块应验证正向能力和负向安全边界,例如私网实例无法从公网访问、KMS 权限确实拒绝非授权身份。对 destroy/replace 建变更预算,对数据库/网络做升级与迁移场景测试。测试环境使用隔离账号、短期凭证、唯一标签和 janitor,但 janitor 删除前也需验证归属,避免通配清理。

实践经验

复合场景中,NAT 模块静态检查全绿,真实部署却因目标区配额不足失败并留下半套路由。新增临时账号集成测试后能在发布前验证配额、回程和清理。长期为昂贵测试设置夜间与版本发布触发。集成覆盖提高但反馈变慢,因此 PR 先跑契约测试,合并前只跑变更影响的场景。

面试回答要点

静态、plan 契约和真实 apply 测试覆盖不同故障类别。

测试金字塔可包含格式/validate、lint 与安全扫描,变量验证和函数级测试,基于 plan JSON 的契约断言,以及临时账号中的 apply→验证→destroy 集成测试。集成覆盖提高但反馈变慢,因此 PR 先跑契约测试,合并前只跑变更影响的场景。

关键安全属性要做负向验证。

关键模块应验证正向能力和负向安全边界,例如私网实例无法从公网访问、KMS 权限确实拒绝非授权身份。新增临时账号集成测试后能在发布前验证配额、回程和清理。

临时环境必须有隔离、归属标签和安全清理。

测试环境使用隔离账号、短期凭证、唯一标签和 janitor,但 janitor 删除前也需验证归属,避免通配清理。新增临时账号集成测试后能在发布前验证配额、回程和清理。

测试选择按变更影响与风险,而非所有模块同一套餐。

静态测试快但不能发现 provider API、权限、配额与真实路由问题;集成测试真实但慢、有成本且清理失败会泄露资源,因此按模块风险分层。集成覆盖提高但反馈变慢,因此 PR 先跑契约测试,合并前只跑变更影响的场景。

state 损坏、误删或资源部分成功时如何恢复?

技术说明

第一原则是停止所有 writer,保存当前 state、后端历史版本、配置 commit、计划/应用日志和云审计。先判断是 state 文件不可读、映射错误、真实资源缺失,还是 apply 部分完成。使用后端版本恢复时不能仅选“最近一个”,要核对 serial/lineage 与真实对象;可用 state list/show 和只读 plan 建差异表,敏感数据处理同生产凭证。

恢复动作可包括恢复可信 state 版本、import 已存在对象、从 state 移除不存在/转移所有权对象,或按配置重建。每一步后重新 plan 并限制目标范围;-target 只适合作为恢复外科工具,不应成为日常应用方式,因为可能遗漏依赖。涉及数据资源先备份和确认删除保护,禁止直接编辑 state JSON,除非受支持工具无法处理且有严格审阅。

实践经验

复合场景中,后端权限误配导致 state 被删除,但版本保留仍在。团队冻结流水线,恢复删除前版本,再把其后已成功创建的对象按审计 ID import;最终完整 plan 仅显示预期标签差异。长期对后端启用版本锁定、删除保护和恢复演练。恢复旧 state 会重新暴露已轮换 secret,故同时做凭证轮换和访问审计。

面试回答要点

先冻结写入并保全 state、日志、审计三类证据。

第一原则是停止所有 writer,保存当前 state、后端历史版本、配置 commit、计划/应用日志和云审计。恢复旧 state 会重新暴露已轮换 secret,故同时做凭证轮换和访问审计。

恢复目标是 state 与真实资源重新一致,而非文件能打开。

先判断是 state 文件不可读、映射错误、真实资源缺失,还是 apply 部分完成。恢复旧 state 会重新暴露已轮换 secret,故同时做凭证轮换和访问审计。

import/state rm 等动作逐项执行并以完整 plan 收尾。

每一步后重新 plan 并限制目标范围;-target 只适合作为恢复外科工具,不应成为日常应用方式,因为可能遗漏依赖。团队冻结流水线,恢复删除前版本,再把其后已成功创建的对象按审计 ID import;最终完整 plan 仅显示预期标签差异。

-target 是受控恢复手段,不是规避依赖图的常规方式。

每一步后重新 plan 并限制目标范围;-target 只适合作为恢复外科工具,不应成为日常应用方式,因为可能遗漏依赖。恢复旧 state 会重新暴露已轮换 secret,故同时做凭证轮换和访问审计。

Ansible 的幂等性来自哪里,command/shell 任务如何安全化?

技术说明

幂等性不是 Ansible6 自动保证,而是模块根据当前状态与期望状态决定是否变更,例如 package、user、template 模块能读取并比较资源。自定义脚本、command/shell 默认不理解业务状态,重复执行可能产生重复用户、数据或重启。可用 creates/removes、明确状态查询、changed_when/failed_when 和事务性脚本建立边界,但条件必须代表真实完成,而非仅检查一个脆弱文件。

任务还要正确支持 check mode、diff、退出码与错误处理;handler 仅在真正 changed 时触发。对数据库迁移、外部 API 等非幂等操作,使用版本表、唯一幂等键与一次性迁移工具,不能靠 playbook 串行假装 exactly-once。执行后第二遍应得到零变更,是很实用的幂等测试。

实践经验

复合场景中,playbook 用 shell 每次追加同一 sysctl 配置,运行数月后文件膨胀且不同值顺序覆盖。证据是任务每次都显示 changed、配置有重复行。止血改用受控 sysctl/模板模块并验证运行值;长期 CI 在临时主机连续执行两遍并要求第二遍零变更。整文件模板能消除漂移,但可能覆盖其他所有者配置,应先明确文件所有权或使用片段目录。

面试回答要点

幂等来自模块的状态比较和业务唯一性,不来自 YAML。

幂等性不是 Ansible 自动保证,而是模块根据当前状态与期望状态决定是否变更,例如 package、user、template 模块能读取并比较资源。止血改用受控 sysctl/模板模块并验证运行值;长期 CI 在临时主机连续执行两遍并要求第二遍零变更。

command/shell 要有真实 guard、准确 changed/failed 语义。

可用 creates/removes、明确状态查询、changed_when/failed_when 和事务性脚本建立边界,但条件必须代表真实完成,而非仅检查一个脆弱文件。整文件模板能消除漂移,但可能覆盖其他所有者配置,应先明确文件所有权或使用片段目录。

第二次运行零变更是基本测试。

执行后第二遍应得到零变更,是很实用的幂等测试。止血改用受控 sysctl/模板模块并验证运行值;长期 CI 在临时主机连续执行两遍并要求第二遍零变更。

文件和服务的所有权边界要先于模板化决定。

幂等性不是 Ansible 自动保证,而是模块根据当前状态与期望状态决定是否变更,例如 package、user、template 模块能读取并比较资源。整文件模板能消除漂移,但可能覆盖其他所有者配置,应先明确文件所有权或使用片段目录。

Ansible inventory、变量优先级和动态 inventory 如何治理?

技术说明

inventory 定义主机与组,动态 inventory 可从云 API/CMDB按标签生成目标;group_vars/host_vars、role defaults/vars、play vars、extra vars 等有不同优先级。资深实践不是背完整优先级表,而是减少来源:默认值放 role defaults,环境差异放少数版本化 group vars,secret 从 vault/secret manager 注入,避免 extra-vars 随意覆盖安全参数。

动态标签若错误可能扩大目标,因此执行前输出并审批 host limit、批次和环境,使用稳定资产 ID 而非仅显示名。inventory cache 要有新鲜度与失效策略;主机退役时还需从 CMDB、DNS、监控和 known_hosts 等外围系统移除。变量调试应使用脱敏后的来源视图,不在日志打印 secret。正式执行还应保存解析后的目标快照,避免长任务期间动态 inventory 变化导致前后批次不一致。

实践经验

复合场景中,云标签 env=prod 被模板误加到测试节点,补丁 playbook 命中了额外主机。预执行目标数量门禁发现从 40 变 87 而中止。长期标签写入由 IaC 控制,Ansible 同时校验账号 ID、主机证书属性并限制最大批次。多重校验降低误选,但资产数据不一致会阻塞维护,需要明确权威源与修复 SLA。

面试回答要点

减少变量来源比依赖复杂优先级更可控。

资深实践不是背完整优先级表,而是减少来源:默认值放 role defaults,环境差异放少数版本化 group vars,secret 从 vault/secret manager 注入,避免 extra-vars 随意覆盖安全参数。预执行目标数量门禁发现从 40 变 87 而中止。

动态 inventory 需验证账号、标签、数量和新鲜度。

inventory 定义主机与组,动态 inventory 可从云 API/CMDB按标签生成目标;group_vars/host_vars、role defaults/vars、play vars、extra vars 等有不同优先级。长期标签写入由 IaC 控制,Ansible 同时校验账号 ID、主机证书属性并限制最大批次。

目标清单本身是高风险变更输入,应纳入审批。

动态标签若错误可能扩大目标,因此执行前输出并审批 host limit、批次和环境,使用稳定资产 ID 而非仅显示名。预执行目标数量门禁发现从 40 变 87 而中止。

secret 通过专用系统注入,调试输出必须脱敏。

变量调试应使用脱敏后的来源视图,不在日志打印 secret。长期标签写入由 IaC 控制,Ansible 同时校验账号 ID、主机证书属性并限制最大批次。

Role、collection 与可复用 playbook 应如何设计?

技术说明

Role 组织 tasks、handlers、templates、defaults、vars 与 metadata,适合封装单一职责能力;collection 对模块、插件和 role 进行命名空间化发布。可复用 role 应有少量、强约束输入,默认安全,明确支持平台与依赖,输出通过 facts/结果而非隐式全局变量。不要把环境名分支散落在 task 中,应让 inventory 提供期望差异。

版本要固定并校验来源,变更按兼容性发布;Molecule 或等价临时实例测试可验证 converge、idempotence、verify 和 destroy。模板变更应触发精准 handler,role 不应无条件重启共享服务。若一个 role 同时改内核、网络和应用,故障半径与回滚难度过大,应按所有权拆分并由 play 编排。collection 升级也应作为依赖变更审阅,不能让控制节点自动选择最新版本。

实践经验

复合场景中,共享“基础”role 新增无条件重启 SSH,应用部署顺带执行后造成一批节点短暂失联。止血是固定旧版本并停止批次;长期拆出 ssh-hardening role,只有配置真实变化才 handler 重载,并在 canary 主机验证新会话。拆分增加版本与编排数量,但让风险和所有者更清晰。

面试回答要点

role 封装单一职责,collection 提供可发布命名空间。

Role 组织 tasks、handlers、templates、defaults、vars 与 metadata,适合封装单一职责能力;collection 对模块、插件和 role 进行命名空间化发布。复合场景中,共享“基础”role 新增无条件重启 SSH,应用部署顺带执行后造成一批节点短暂失联。

defaults 是接口,环境分支不应散落在实现内部。

不要把环境名分支散落在 task 中,应让 inventory 提供期望差异。止血是固定旧版本并停止批次;长期拆出 ssh-hardening role,只有配置真实变化才 handler 重载,并在 canary 主机验证新会话。

版本固定、幂等测试和真实实例验证缺一不可。

版本要固定并校验来源,变更按兼容性发布;Molecule 或等价临时实例测试可验证 converge、idempotence、verify 和 destroy。止血是固定旧版本并停止批次;长期拆出 ssh-hardening role,只有配置真实变化才 handler 重载,并在 canary 主机验证新会话。

handler 必须精准且只由真实变化触发。

模板变更应触发精准 handler,role 不应无条件重启共享服务。止血是固定旧版本并停止批次;长期拆出 ssh-hardening role,只有配置真实变化才 handler 重载,并在 canary 主机验证新会话。

如何用 Ansible 做可恢复的滚动变更?

技术说明

滚动变更通过 serial 控制批次,结合 max_fail_percentage/any_errors_fatal、pre_tasks 健康检查和明确失败阈值;每台主机先从负载均衡摘流、等待连接排空,变更与重启后做本机及端到端验证,再重新加流。forks 只控制并发执行,不等同于业务可用批次。run_once 与 delegate_to 要小心批次语义和重复执行。

回滚需有已验证旧包/旧配置、数据格式兼容和服务恢复步骤;block/rescue/always 可表达局部补偿,但跨主机变更不是真事务。控制器断开后目标任务可能继续执行,因此任务要幂等且能查询状态。发布应记录每批目标、变更结果与健康指标,并在错误预算或业务 SLI 触发时自动停止后续批次。

实践经验

复合场景中,配置语法虽通过,但新版本启动后内存增长,第一批 5% 在十分钟后才异常。原流程两分钟即继续,影响扩大。止血是停止 play、回滚已变更批次并恢复流量;长期增加与故障时间常数匹配的观察窗和业务指标门禁。观察窗拉长维护时间,因此低风险补丁与核心代理采用不同策略。

面试回答要点

serial 是业务批次,forks 只是执行并发。

forks 只控制并发执行,不等同于业务可用批次。止血是停止 play、回滚已变更批次并恢复流量;长期增加与故障时间常数匹配的观察窗和业务指标门禁。

摘流、排空、变更、验证、加流构成单机状态机。

滚动变更通过 serial 控制批次,结合 max_fail_percentage/any_errors_fatal、pre_tasks 健康检查和明确失败阈值;每台主机先从负载均衡摘流、等待连接排空,变更与重启后做本机及端到端验证,再重新加流。止血是停止 play、回滚已变更批次并恢复流量;长期增加与故障时间常数匹配的观察窗和业务指标门禁。

失败门禁看业务 SLI,不只看命令退出码。

发布应记录每批目标、变更结果与健康指标,并在错误预算或业务 SLI 触发时自动停止后续批次。止血是停止 play、回滚已变更批次并恢复流量;长期增加与故障时间常数匹配的观察窗和业务指标门禁。

回滚必须验证数据/配置向后兼容。

回滚需有已验证旧包/旧配置、数据格式兼容和服务恢复步骤;block/rescue/always 可表达局部补偿,但跨主机变更不是真事务。止血是停止 play、回滚已变更批次并恢复流量;长期增加与故障时间常数匹配的观察窗和业务指标门禁。

Ansible Vault 和外部 secret manager 如何选择与轮换?

技术说明

Ansible Vault 加密仓库中的变量/文件,适合版本化静态密文,但解密密码的分发、轮换和审计仍需解决;密文一旦在控制节点解密,就可能进入进程、临时文件、diff 或目标主机。no_log: true 能减少任务输出,却会降低诊断能力且不能覆盖模块/外部程序所有泄露路径。

外部 secret manager 更适合动态凭证、细粒度访问、审计和自动轮换,Ansible 通过短期工作负载身份按需取值。选择依据是凭证生命周期、离线需求和目标系统能力;即使用外部系统,也要避免把取回的 secret 写成永久文件。轮换设计采用新旧重叠、消费者 reload/重连验证、撤销旧版本和失败回退。

实践经验

复合场景中,Vault 密码作为共享 CI 变量多年不变,离职人员仍可能持有离线仓库与密码。止血是轮换所有密文内凭证与 vault identity;长期迁移高价值密码到 secret manager,CI 用 OIDC 获取,Vault 仅保留低频离线配置。动态取密依赖 secret 服务可用性,应有有界缓存和故障模式设计。

面试回答要点

Vault 解决密文入库,不自动解决解密身份与审计。

Ansible Vault 加密仓库中的变量/文件,适合版本化静态密文,但解密密码的分发、轮换和审计仍需解决;密文一旦在控制节点解密,就可能进入进程、临时文件、diff 或目标主机。止血是轮换所有密文内凭证与 vault identity;长期迁移高价值密码到 secret manager,CI 用 OIDC 获取,Vault 仅保留低频离线配置。

外部 secret manager 更适合短期、动态和可吊销凭证。

外部 secret manager 更适合动态凭证、细粒度访问、审计和自动轮换,Ansible 通过短期工作负载身份按需取值。止血是轮换所有密文内凭证与 vault identity;长期迁移高价值密码到 secret manager,CI 用 OIDC 获取,Vault 仅保留低频离线配置。

no_log 是减暴露措施,不是完整秘密保护。

no_log: true 能减少任务输出,却会降低诊断能力且不能覆盖模块/外部程序所有泄露路径。止血是轮换所有密文内凭证与 vault identity;长期迁移高价值密码到 secret manager,CI 用 OIDC 获取,Vault 仅保留低频离线配置。

轮换必须验证消费者切换并最终撤销旧版本。

轮换设计采用新旧重叠、消费者 reload/重连验证、撤销旧版本和失败回退。止血是轮换所有密文内凭证与 vault identity;长期迁移高价值密码到 secret manager,CI 用 OIDC 获取,Vault 仅保留低频离线配置。

Argo CD 的 Application、repo-server、controller 与 cluster credential 如何协作?

技术说明

Argo CD7 Application 描述 source(Git/Helm/OCI 等)与 destination cluster/namespace,以及 sync policy。repo-server 获取并渲染期望 manifests,application-controller 比较期望与集群 live state、计算健康/同步状态并执行协调,API/UI 提供交互与 RBAC;实际部署形态可能有分片/扩展组件。它是 GitOps8 声明协调器,不应把模板渲染阶段变成可任意访问生产网络的脚本平台。

集群凭证与仓库凭证是高价值身份,应最小权限、短期化/轮换并按项目隔离。AppProject 可限制允许的 source repo、destination 和资源种类;仅 namespace RBAC 不足以阻止创建 ClusterRole 等集群资源。repo-server 插件、Helm value 和自定义工具都有供应链风险,要固定版本、限制网络/文件系统并验证生成结果。控制器扩容或分片时还要防多个实例对同一对象产生超额 API 压力。

实践经验

复合场景中,一个租户 Application 指向未经批准仓库并创建 ClusterRoleBinding,因为项目 destination 受限但 cluster resource 未限制。审计锁定资源来源。止血是撤销绑定、暂停 Application 并轮换受影响身份;长期收紧 AppProject source/destination/resource allowlist,平台与租户使用不同 controller 身份。严格 allowlist 增加新 CRD 上线流程,需要快速审批通道。

面试回答要点

repo-server 负责生成期望,controller 负责 diff 与协调。

repo-server 获取并渲染期望 manifests,application-controller 比较期望与集群 live state、计算健康/同步状态并执行协调,API/UI 提供交互与 RBAC;实际部署形态可能有分片/扩展组件。止血是撤销绑定、暂停 Application 并轮换受影响身份;长期收紧 AppProject source/destination/resource allowlist,平台与租户使用不同 controller 身份。

AppProject 同时限制来源、目标和资源种类。

AppProject 可限制允许的 source repo、destination 和资源种类;仅 namespace RBAC 不足以阻止创建 ClusterRole 等集群资源。复合场景中,一个租户 Application 指向未经批准仓库并创建 ClusterRoleBinding,因为项目 destination 受限但 cluster resource 未限制。

仓库渲染插件属于生产供应链执行面。

repo-server 插件、Helm value 和自定义工具都有供应链风险,要固定版本、限制网络/文件系统并验证生成结果。复合场景中,一个租户 Application 指向未经批准仓库并创建 ClusterRoleBinding,因为项目 destination 受限但 cluster resource 未限制。

集群凭证按租户/环境最小化,避免一个控制器全能。

集群凭证与仓库凭证是高价值身份,应最小权限、短期化/轮换并按项目隔离。复合场景中,一个租户 Application 指向未经批准仓库并创建 ClusterRoleBinding,因为项目 destination 受限但 cluster resource 未限制。

Argo CD sync wave、hook 与健康检查如何编排复杂发布?

技术说明

sync phase/hook 可在 PreSync、Sync、PostSync、SyncFail 等阶段运行任务,sync wave 通过整数顺序安排同阶段资源,控制器通常等待较早 wave 同步且健康后继续。它适合 CRD 先于 CR、迁移任务先于应用等依赖,但不是通用工作流引擎;hook Job 可能重试或残留,外部副作用必须幂等并配置删除策略。

Kubernetes 对象存在不等于业务 ready,Argo 健康检查需为 CRD/rollout 定义准确 condition。数据库 schema 变更应采用 expand/contract,确保新旧应用兼容;不能把不可逆 migration 放 PreSync 后假设应用回滚即可回退数据。跨 Application 依赖最好通过明确平台层与契约解耦,避免巨型 app-of-apps 隐式顺序。选择性同步可能改变 hook 执行预期,生产流程必须覆盖其实际语义测试。

实践经验

复合场景中,PreSync migration 因网络超时被 Job 重试,非幂等 ALTER 部分成功后第二次失败,应用无法发布。证据来自 Job attempt 与数据库 DDL 日志。止血是停止自动 sync、人工确认 schema 后部署兼容版本;长期迁移有版本账本、幂等前置检查,采用 expand/contract。更细阶段会拉长交付周期,却显著改善回滚边界。

面试回答要点

wave 是声明资源排序,不是跨系统事务。

sync phase/hook 可在 PreSync、Sync、PostSync、SyncFail 等阶段运行任务,sync wave 通过整数顺序安排同阶段资源,控制器通常等待较早 wave 同步且健康后继续。止血是停止自动 sync、人工确认 schema 后部署兼容版本;长期迁移有版本账本、幂等前置检查,采用 expand/contract。

hook 必须可重试、幂等且有明确清理策略。

它适合 CRD 先于 CR、迁移任务先于应用等依赖,但不是通用工作流引擎;hook Job 可能重试或残留,外部副作用必须幂等并配置删除策略。复合场景中,PreSync migration 因网络超时被 Job 重试,非幂等 ALTER 部分成功后第二次失败,应用无法发布。

健康检查要反映业务可用 condition。

Kubernetes 对象存在不等于业务 ready,Argo 健康检查需为 CRD/rollout 定义准确 condition。止血是停止自动 sync、人工确认 schema 后部署兼容版本;长期迁移有版本账本、幂等前置检查,采用 expand/contract。

数据库迁移与应用发布使用向前/向后兼容阶段。

数据库 schema 变更应采用 expand/contract,确保新旧应用兼容;不能把不可逆 migration 放 PreSync 后假设应用回滚即可回退数据。止血是停止自动 sync、人工确认 schema 后部署兼容版本;长期迁移有版本账本、幂等前置检查,采用 expand/contract。

self-heal、auto-sync 与 prune 如何避免把错误迅速放大?

技术说明

auto-sync 自动应用 Git 期望,self-heal 纠正集群侧漂移,prune 删除 Git 中已不存在的对象。三者提高收敛性,也让错误提交、错误路径或生成器 bug 快速影响大量资源。生产应限制并发/批次,关键 Application 手动或分阶段晋级,prune 对 namespace、CRD、PVC 等高风险资源增加保护和审批,并使用 sync window 控制变更时段。

Git 提交可回滚不代表系统可逆:资源删除、数据迁移和云控制器副作用可能无法由 revert 恢复。策略应验证渲染后的对象集、删除数量、目标 cluster/namespace、签名与评审,先在 canary 集群同步;监控 OutOfSync 原因、sync error、prune 列表与业务 SLI。事故期间手工修复若 self-heal 开启,会被立即覆盖,需通过受控暂停与代码回写协调。

实践经验

复合场景中,目录重构使生成器输出空清单,prune 尝试删除多个 namespace 工作负载。删除预算门禁在 canary 阻止扩散。止血是暂停自动同步、恢复上一个制品并核对已删对象;长期将“对象数骤减”作为强门禁,对数据资源设置保留策略。降低自动 prune 会遗留孤儿资源,需要定期审计和受控清理。

面试回答要点

self-heal 修集群漂移,prune 删除期望外对象,风险不同。

auto-sync 自动应用 Git 期望,self-heal 纠正集群侧漂移,prune 删除 Git 中已不存在的对象。止血是暂停自动同步、恢复上一个制品并核对已删对象;长期将“对象数骤减”作为强门禁,对数据资源设置保留策略。

Git revert 不等于数据与外部副作用回滚。

Git 提交可回滚不代表系统可逆:资源删除、数据迁移和云控制器副作用可能无法由 revert 恢复。止血是暂停自动同步、恢复上一个制品并核对已删对象;长期将“对象数骤减”作为强门禁,对数据资源设置保留策略。

对对象数、目标环境和高风险删除设置机器门禁。

策略应验证渲染后的对象集、删除数量、目标 cluster/namespace、签名与评审,先在 canary 集群同步;监控 OutOfSync 原因、sync error、prune 列表与业务 SLI。止血是暂停自动同步、恢复上一个制品并核对已删对象;长期将“对象数骤减”作为强门禁,对数据资源设置保留策略。

事故手改必须先管理 reconcile,再迅速回写 Git。

事故期间手工修复若 self-heal 开启,会被立即覆盖,需通过受控暂停与代码回写协调。降低自动 prune 会遗留孤儿资源,需要定期审计和受控清理。

GitOps 中 secret、多集群和租户边界如何设计?

技术说明

Git 不能保存明文 secret。可采用加密清单(解密密钥留在目标环境)、sealed secret、external-secret 引用或 CSI;核心是密钥与密文分离、仓库读者不能解密生产值、轮换与吊销可审计。渲染日志、diff 和缓存也要防明文泄露。若控制器能解密所有环境,一个仓库插件漏洞可能跨环境扩散。

多集群采用分层注册与 pull/受限 push 模式,按环境/租户拆控制器身份、项目和仓库路径;应用团队只能修改自身 namespace 资源,平台资源由不同审批路径管理。集群注册凭证短期化并验证目标 UID/账号,防同名集群误投。配置晋级应引用同一制品 digest,仅环境参数变化,而非各集群重新构建。

实践经验

复合场景中,单个中心控制器持有所有 prod 集群管理员凭证,插件命令注入后存在全域风险。止血是停用插件、轮换集群凭证并检查审计;长期每个环境设受限 controller、渲染在沙箱执行,平台资源独立管道。分散控制器增加运营成本,但把凭证和故障半径限制在环境内。

面试回答要点

secret 方案要说明密钥在哪、谁能解、明文是否落日志/缓存。

可采用加密清单(解密密钥留在目标环境)、sealed secret、external-secret 引用或 CSI;核心是密钥与密文分离、仓库读者不能解密生产值、轮换与吊销可审计。止血是停用插件、轮换集群凭证并检查审计;长期每个环境设受限 controller、渲染在沙箱执行,平台资源独立管道。

多集群控制器身份按环境和租户拆分。

多集群采用分层注册与 pull/受限 push 模式,按环境/租户拆控制器身份、项目和仓库路径;应用团队只能修改自身 namespace 资源,平台资源由不同审批路径管理。分散控制器增加运营成本,但把凭证和故障半径限制在环境内。

平台级与 namespace 级资源使用不同所有权路径。

多集群采用分层注册与 pull/受限 push 模式,按环境/租户拆控制器身份、项目和仓库路径;应用团队只能修改自身 namespace 资源,平台资源由不同审批路径管理。止血是停用插件、轮换集群凭证并检查审计;长期每个环境设受限 controller、渲染在沙箱执行,平台资源独立管道。

环境间晋级同一 digest,避免重建造成供应链漂移。

配置晋级应引用同一制品 digest,仅环境参数变化,而非各集群重新构建。分散控制器增加运营成本,但把凭证和故障半径限制在环境内。

如何为 GitOps/IaC 平台设计灾备与大规模变更控制?

技术说明

平台灾备要区分 Git、制品仓库、state 后端、secret/KMS、GitOps 控制器和目标集群。Git 可重建期望对象,但不能重建未纳管外部状态、PVC 数据、解密密钥或 Terraform 映射;因此每项都有 RTO/RPO、备份、跨故障域副本和恢复顺序。先恢复身份/KMS与只读访问,再恢复 state/制品,最后分批恢复协调器,避免陈旧期望立即改动目标。

大规模变更采用 blast-radius budget:按环境、区域、租户和资源比例分批,canary→观察→扩大;设置删除/替换数量、并发、错误预算和自动停机门禁。全局 kill switch 应能暂停 reconcile/apply 但保留观测,恢复后先生成 fresh diff。break-glass 需双人授权、最短期限、完整审计和事后代码回写。

实践经验

复合场景中,Git 托管和主区域控制器同时不可用,团队从镜像恢复控制器后立即 auto-sync,使用了落后两小时的缓存清单并回退合法变更。止血是暂停 reconcile、以远端集群 live state 与最新镜像仓库对账,再恢复 Git 后分批同步。长期灾备演练明确“恢复控制器不等于开启写入”,并保存 commit/digest/state 一致检查点。更严格恢复门禁会增加 RTO,但显著降低二次事故。

面试回答要点

Git 只保存部分期望,state、数据、密钥和制品需独立灾备。

平台灾备要区分 Git、制品仓库、state 后端、secret/KMS、GitOps 控制器和目标集群。长期灾备演练明确“恢复控制器不等于开启写入”,并保存 commit/digest/state 一致检查点。

恢复顺序先身份/只读证据,再逐步启用 writer。

先恢复身份/KMS与只读访问,再恢复 state/制品,最后分批恢复协调器,避免陈旧期望立即改动目标。复合场景中,Git 托管和主区域控制器同时不可用,团队从镜像恢复控制器后立即 auto-sync,使用了落后两小时的缓存清单并回退合法变更。

全局变更按故障域分批,并有删除与错误预算门禁。

大规模变更采用 blast-radius budget:按环境、区域、租户和资源比例分批,canary→观察→扩大;设置删除/替换数量、并发、错误预算和自动停机门禁。复合场景中,Git 托管和主区域控制器同时不可用,团队从镜像恢复控制器后立即 auto-sync,使用了落后两小时的缓存清单并回退合法变更。

kill switch、break-glass 和恢复后 fresh diff 必须演练。

全局 kill switch 应能暂停 reconcile/apply 但保留观测,恢复后先生成 fresh diff。长期灾备演练明确“恢复控制器不等于开启写入”,并保存 commit/digest/state 一致检查点。


  1. TerraformOpenTofu 都是以声明式配置管理基础设施的 IaC 工具。 

  2. state(状态文件)记录配置中的资源地址与远端真实对象之间的映射,是生成变更计划和跟踪所有权的关键数据。 

  3. provider 是 IaC 工具与云平台、SaaS 或其他 API 交互的插件,负责读取和修改特定类型的资源。 

  4. plan 计算并展示拟执行的差异,apply 执行经过确认的变更;生产流程应保证审批与执行针对同一份计划。 

  5. drift(配置漂移)指真实基础设施状态偏离受管理配置或已记录状态,可能来自手工修改或其他控制器。 

  6. Ansible 是通过 inventory、playbook 和模块执行配置管理与自动化的工具。参见 Ansible 官方文档。 

  7. Argo CD 是面向 Kubernetes 的声明式持续交付控制器,会比较 Git 中的期望状态与集群实际状态。参见 Argo CD 官方文档。 

  8. GitOps 是以版本控制中的声明作为期望状态,并由自动化控制器持续协调实际环境的运维方式。