# 从容器到集群，哪些责任发生了变化

原文: https://yishto.com/learn/delivery/containers-orchestration-and-iac/

作者: [Yishto](https://yishto.com/about/)

以无状态资料 API 区分镜像、实例、探针、调度资源和基础设施状态，检查容器与集群交付中的责任边界。

首次发布: 2026-11-10
内容更新: 2026-11-10

一个资料预览 API 需要读取对象存储里的文件，并返回可公开展示的摘要。它没有本地持久数据，适合练习容器化。把程序放进镜像只完成了交付的一部分：运行权限、进程健康、流量入口、资源预算与云资源变更仍需要明确负责人。

案例中的机器有八个 CPU 预算单位和十六个内存预算单位，两组实例分别申请不同资源。这里的数值是简化的教学单位，不代表某种云机器规格，也没有做吞吐量测试。

## 镜像与运行实例承担不同责任

镜像包含用户空间的程序、依赖和默认启动方式。容器是从镜像启动的受隔离进程，通常共享宿主机内核；虚拟机则有自己的操作系统内核。镜像可以减少依赖差异，但 CPU 架构、内核能力、运行配置和外部服务仍会影响实际行为。

镜像 tag 可以被重新指向另一份内容。需要追踪发布时，记录内容 digest、源代码提交、构建环境和依赖锁定结果。旧 tag 叫作 stable 并不能证明它还指向昨天验证过的镜像。尽量让测试和正式环境使用同一份已经构建的产物。

不要把密钥复制进构建目录，再在后一层删除。早期镜像层和构建日志仍可能保留内容。运行时通过受控方式注入配置与凭据，镜像只放公开可分发的程序。使用非 root 进程、减少可写目录和多余能力，可以缩小被利用后的影响范围；容器隔离不能替代完整安全设计。

## 无状态要求可以丢弃实例

资料服务需要能在任意新实例上继续运行。上传对象、任务结果和数据库记录要放在明确的外部持久系统里，本地临时文件只用于可以重建的中间过程。服务必须解释重启后临时文件消失的行为，而不能依赖某个实例一直活着。

请求结束、连接关闭和进程退出也有顺序。停止接收新请求后，应给正在处理的工作留出有限时间，再退出。长任务更适合转成有持久状态的后台任务；否则滚动发布会让用户不知道预览是否完成。外部存储需要单独的访问权限、备份策略和失败处理。

先在单个容器层面检查启动参数、配置缺失、端口绑定、日志输出和退出码。只在默认配置下启动成功，不能说明生产环境的网络与权限已经可用。本文的离线代码不启动 Docker，也不验证真实镜像。

## 编排器持续协调期望状态

Kubernetes 控制器观察实际状态，并尝试让它接近声明的期望状态，例如保持指定数量的 Pod。Pod 是调度与运行的基本单元；Service 提供稳定的访问方式，将流量导向符合条件的后端。容器重启、Pod 重建和迁移到另一节点是不同事件，不能把它们统称为同一种恢复。

readiness 表达实例当前是否应接流量，失败时应从可用后端中移出。liveness 用于发现需要重启才能恢复的状态。startup probe 适用于启动较慢的进程，避免尚未完成初始化就被其他探针反复判坏。探针接口自身也要便宜、可靠，并有合理的超时与失败阈值。

如果数据库短暂不可达就让所有实例 liveness 失败，重启并不能修复数据库，反而增加启动流量。应区分进程死锁、依赖异常和业务拒绝。readiness 失败也可能让全部实例退出服务，必须观察并设计降级行为，不能把探针当成无风险开关。

## 资源申请影响调度，限制影响运行

为服务估算 CPU 与内存请求，再选择限制和副本数量。请求表达调度时需要预留的资源；限制约束运行时的资源使用，两者含义不同。内存不足可能导致进程被终止，CPU 限制可能造成处理延迟。具体行为要结合运行环境测试。

下面只比较申请总量与一个总预算，不使用真实的 Kubernetes 调度器。它假定每个实例的资源字段完整，且数值非负。

```python
capacity = {"cpu": 8, "memory": 16}
pods = [{"cpu": 2, "memory": 4}, {"cpu": 3, "memory": 6}]
def fits(items):
    return all(sum(p[resource] for p in items) <= maximum
               for resource, maximum in capacity.items())
assert fits(pods)
assert not fits(pods + [{"cpu": 4, "memory": 2}])
print(fits(pods))
```

实际输出是 `True`。已有两个实例共申请五个 CPU、十个内存单位，可以放进总预算。再加入申请四个 CPU 的实例，总 CPU 达到九，断言确认它超过八个单位。

总量满足只是必要检查。真实调度还涉及每个节点能否单独容纳某个 Pod、节点保留资源、污点、亲和性、可用区与存储约束。集群总内存充足，仍可能没有任何单个节点放得下一个大 Pod。扩容也要先检查下游容量，否则增加实例会扩大数据库压力。

## 基础设施代码需要状态与权限

Terraform 配置声明希望存在的资源，plan 展示预计变更，state 记录配置与实际资源之间的映射。配置保存在 Git 中便于审查，但 state 可能包含敏感信息，不能把它当成普通源码公开。状态存储要控制访问，并根据后端能力配置并发锁，防止多个操作者同时修改。

审查 plan 时逐项看创建、修改和销毁，确认环境、资源标识与依赖。应用层回滚不自动恢复已经删除的云资源。控制台手工修改会造成漂移，后续 plan 需要解释差异，再决定纳入配置还是恢复原状态。

云 IAM 则决定部署程序和运行程序分别能操作哪些资源。资料 API 只需要读取指定环境的对象范围；创建集群与修改权限的能力属于交付流程。优先使用可管理的工作负载身份和短期凭据，并确认具体平台支持的方式。一个通用管理员密钥会把多个责任边界合并。

## 练习：检验责任是否落到了具体机制

写一份资料 API 的交付说明，列出镜像 digest、启动参数、临时目录、外部存储、三类探针语义、资源请求与限制，以及运行身份可访问的范围。加入实例重建、依赖不可达、配置缺失和预算不足四个失败分支。

验收时，新实例应能仅靠镜像与受控配置启动；重建后不丢失已完成业务数据；依赖故障不会触发无限重启；未获授权的存储操作被拒绝。给离线预算函数增加缺失字段、负数和单节点约束检查，并记录它仍无法覆盖的调度条件。若随后实施真实部署，另外记录平台、配置和观测结果，不把离线断言算作集群验证。

## 资料来源与延伸阅读

- [Container concepts](https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-a-container/)
- [Kubernetes concepts](https://kubernetes.io/docs/concepts/)
- [Infrastructure as code](https://developer.hashicorp.com/terraform/intro)
- [Identity and access management](https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html)

资料核验：2026-11-10。教学示例不代表线上实测。

## 相关文章

- [让命令能在另一台电脑上运行](https://yishto.com/learn/developer-workflow/shell-environments-and-ports/)
- [应用发布前，哪些检查与平台有关](https://yishto.com/learn/application-platforms/application-release-and-maintenance/)
