你有没有见过码头工人搬运集装箱?一个标准箱从货轮上吊起,放到卡车上,拉到仓库;如果货物要更新,就换一个全新的箱子,没有人会拆开旧箱子的钢板去补漏。这恰恰是“不可变基础设施”的核心直觉:服务器不是会被长期修修补补的“老房子”,而是一只只随时可以被整体替换的“集装箱”。部署新版本,不是登录机器改文件,而是把新镜像打包成新集装箱,整箱换上,旧箱直接销毁。 如果只看一个码头,这套流程已经很顺了。但真正的问题是:如果业务只押在一家云厂商的“专属码头”上,用它的独门吊具、独有存储格式、不可迁移的管理 API,一旦它涨价、限流、出故障,你就等于被“供应商锁定”了。多云的智慧,是让集装箱符合国际标准,同时保留几条备用航线。它会用标准化镜像、抽象层、基础设施即代码等工具,让业务像集装箱一样在不同云码头之间自由流动。本文会用“码头与集装箱”这条线,依次讲清不可变基建、部署策略、代码化基建、多云架构、锁定规避、工具生态和实践治理。

岗位关联

学完这套知识,你就能理解 AI 时代基础设施的“集装箱化”逻辑,并掌握用多云策略规避供应商锁定的工程能力——这几乎是每一位 AI 平台工程师、MLOps 工程师的核心必修课。

目录
  1. 可视化演示
  2. 不可变基建
  3. 部署策略
  4. 代码化基建
  5. 多云架构
  6. 锁定规避
  7. 工具生态
  8. 实践治理
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示多云策略与供应商锁定规避:应用经抽象层接入多朵云、抽象层隔离云厂商API、主备/负载分布/多云联合部署模式,通过交互理解多云架构。

本节配有交互动效(进入视口后自动加载,约 3KB)。

多云拓扑:分散云依赖 应用经抽象层接入多朵云 AWS/Azure/GCP差异化发挥 App → Abs → 多云 规避供应商锁定提高可用性

不可变基建

在老码头的仓库区,墙裂了、门歪了,工头第一反应是叫维修工。补丁打多了,图纸和实物越来越对不上;某天想扩建,才发现根本没有可参考的结构。不可变基础设施的逻辑完全不同:仓库不是一个会被反复修补的“老房子”,而是一个由中央工厂预制的标准集装箱。要换新配置,就重新压一个箱子,整只吊走旧的、吊进新的,没人会拿着焊枪修集装箱。

技术上的说法是:不可变基础设施(Immutable Infrastructure)要求云虚拟机或容器一旦创建就不再修改。应用更新不再 SSH 进实例执行升级命令,而是把新的黄金镜像(Golden Image)构建好,用新实例直接替换旧实例。这个理念来自“宠物 vs 牲口”的老笑话:宠物有名字、生病了要治;牲口只有编号,病了就换一头。

好处是环境高度一致、行为可复现、回滚只需要切回旧镜像;坏处是首次构建镜像较慢、临时进机器排查问题不方便。于是我们用“替换修复比”来决定该不该换。

在码头上,标准化集装箱让“换”比“修”更快;在云上,黄金镜像就是你的标准集装箱。只要画面里出现“登录生产服务器改文件”,就已经回到了老码头时代。

R=CrepairCreplace\displaystyle R = \frac{C_{\text{repair}}}{C_{\text{replace}}}
R 表示“修复成本除以替换成本”,大于 1 时,直接换新实例比打补丁更划算。
  1. 修复成本包含人工排查、补丁操作、停机损失和配置漂移带来的隐性成本。
    Crepair=Cmanual+Cdrift\displaystyle C_{\text{repair}} = C_{\text{manual}} + C_{\text{drift}}
  2. 替换成本包含构建新镜像、启动实例、接入流量和销毁旧实例的成本。
    Creplace=Cbuild+Claunch\displaystyle C_{\text{replace}} = C_{\text{build}} + C_{\text{launch}}
  3. 决策规则R 大于 1 时说明“修不如换”,这就是不可变基础设施的决策边界。
    R>1⇒replace is better\displaystyle R > 1 \Rightarrow \text{replace is better}

部署策略

集装箱到了码头,总不能所有箱子一秒全砸下去。聪明的码头调度会设计不同的换箱节奏:蓝绿部署、滚动部署、金丝雀发布。它们不是互相竞争,而是不同风险偏好下换班方式。

蓝绿部署(Blue-Green)维护两套完全相同的环境:蓝色在线,绿色闲置。发布时把新版本铺到绿色环境,验证后一键把流量从蓝切到绿;回滚就是再把流量切回蓝。滚动部署(Rolling Deploy)则是小批量替换实例,一批验证完再换下一批,服务不中断但发布窗口较长。金丝雀发布(Canary Release)先把新版本给 1% 的真实流量用,观察指标后再逐步放大。

这三种方式的共同前提是:实例不可变,版本切换只是“换一批箱子”,回滚不是撤销操作,而是把旧版黄金镜像整体换回。部署风险可以用三个变量估计:

调度员关心的不是某个箱子哪里锈了,而是整条船的换箱风险。只要发布动作仍然是“整箱替换”,蓝绿、滚动、金丝雀就都是同一套集装箱逻辑的节奏变体。

E=λ×t×n\displaystyle E = \lambda \times t \times n
E 是“故障影响”,等于故障发生率、暴露时间和影响实例数量的乘积;部署策略的目标就是压缩 t 和 n。
  1. 故障发生率λ 代表新版本出现问题的概率,来自测试覆盖率和历史发布数据。
    λ=P(failure)\displaystyle \lambda = P(\text{failure})
  2. 暴露时间t 是从发布开始到发现问题并把流量切走之间的时长,时间越短,损失越小。
    t=tfail+trollback\displaystyle t = t_{\text{fail}} + t_{\text{rollback}}
  3. 影响实例数n 是故障期间受影响的实例或用户规模;蓝绿把 n 压到接近 0,金丝雀把 n 缩小到 1%。
    n=blast radius\displaystyle n = \text{blast radius}

代码化基建

集装箱可以换,但绝不能随便换。码头需要图纸和台账:哪些箱子在哪个泊位,应该是什么状态。这就是基础设施即代码(IaC,Infrastructure as Code)的定位:用声明式配置描述期望状态,让机器而不是记忆去执行。

Terraform 就是这类工具的代表。你不用写“先建子网再建虚拟机”的命令序列,而是写“最终应该存在一个子网、一台虚拟机、一个安全组”。工具会读当前状态,和期望状态对比,只增删改差异部分。这个“状态文件”是仓库的台账,它让人能一眼看出码头实际停靠的箱子是不是图纸上该有的箱子。

实际操作中,IaC 还有两个重要动作:模块复用便于把公共网络、存储、权限封装成可复用模块;版本控制让每一次基础设施变更都像代码提交一样可追溯。如果实际状态和期望状态不一致,就产生了“配置漂移”:

图纸和台账让港口经验沉淀成仓库里的“配方”,而不是某位老师的私人记忆。代码化基建让多云策略不再是拍脑袋,而是可审查、可回放、可审计的工程行为。

D=∑k=1n(dk−ak)2\displaystyle D = \sqrt{\sum_{k=1}^{n}(d_k - a_k)^2}
D 是配置漂移距离,d 代表期望配置,a 代表实际配置;D 越大,环境越不可信。
  1. 期望值d_k 表示第 k 个配置项的期望值,来自 IaC 配置文件。
    dk=desired value for key k\displaystyle d_k = \text{desired value for key } k
  2. 实际值a_k 表示第 k 个配置项当前实际值,来自云厂商 API 或状态文件。
    ak=actual value for key k\displaystyle a_k = \text{actual value for key } k
  3. 距离合成把所有差异平方求和再开根号,得到一维的“漂移程度”。
    D=∑k=1n(dk−ak)2\displaystyle D = \sqrt{\sum_{k=1}^{n}(d_k - a_k)^2}

多云架构

一个港口再大,也可能遇到台风封港;把所有宝贝只押在一个码头上,等于把命运交给单一房东。多云架构就是把货分到几个港口,让它们互为备份。

从高可用设计看,多云的核心原则是“不要把鸡蛋放在一个篮子里”。云 A 故障时,流量切到云 B;云 B 的可用率没有变,但整体系统的可用率会因为冗余而提高。从成本优化看,多朵云之间可以形成比价和竞价空间;从数据分布看,不同地区业务可以用离用户最近的云,降低延迟;从故障隔离看,单朵云内部的区域故障不会瞬间拖垮全局。

多云不是没有代价:网络出口流量可能收费,数据一致性需要额外设计,技术栈复杂度也更高。但只要各云故障不是完全正相关,独立可用率就能合成出更高的整体可用率:

三座码头的联合可用率,来自“不是所有码头同时瘫痪”的朴素直觉。多云架构不是花架子,而是用概率思维把风险摊到多个港口。

Atotal=1−∏i=1n(1−ai)\displaystyle A_{\text{total}} = 1 - \prod_{i=1}^{n}(1-a_i)
整体可用率等于“1 减去所有云同时故障的概率”;每朵云可用率独立时,多朵云联合可用的概率会显著上升。
  1. 单云故障率1 - a_i 表示第 i 朵云不可用的概率。
    1−ai\displaystyle 1-a_i
  2. 同时故障概率如果故障相互独立,N 朵云同时坏的概率是连乘。
    ∏i=1n(1−ai)\displaystyle \prod_{i=1}^{n}(1-a_i)
  3. 整体可用率从 1 中减去“全部不可用”的情况,就是“至少有一朵云可用”的概率。
    Atotal=1−∏i=1n(1−ai)\displaystyle A_{\text{total}} = 1 - \prod_{i=1}^{n}(1-a_i)

锁定规避

集装箱之所以全球通用,是因为尺寸、锁扣、吊装标准高度一致。如果某家码头偏要给你装专属挂钩,搬到另一座码头时才发现所有箱子都卸不下来,这就是供应商锁定(Vendor Lock-in)。

锁定的来源通常很具体:专有 API、托管数据库的特殊格式、私有负载均衡配置、甚至昂贵的数据出口流量费。一开始用起来爽,几年后想换云,才发现迁移成本高到让人放弃。

规避策略不是“完全不用云厂商特色服务”,而是给依赖关系记账,并保留逃生路线。抽象层策略要求业务尽量通过 Infrastructure as Code 与通用资源类型交互,把云厂商差异封装在 Provider 内部;API 可移植要求代码优先用开源标准协议,而不是云厂商专属 SDK;数据迁移路径则要求定期把数据库快照、对象存储桶、镜像仓库复制到独立备份空间。用“锁定度”量化风险:

目标是让每个集装箱都能在任意标准码头卸货,而不是把吊具焊死在某一座码头上。锁定规避不是一次重构,而是一条长期保持的可迁移性纪律。

L=NproprietaryNtotal\displaystyle L = \frac{N_{\text{proprietary}}}{N_{\text{total}}}
L 是专有组件占总组件比例;比例越高,被单一码头绑架的程度越深。
  1. 专有组件数N_proprietary 是依赖云厂商专属 API、托管服务或数据格式的组件数量。
    Nproprietary\displaystyle N_{\text{proprietary}}
  2. 总组件数N_total 是整个系统里的全部基础设施组件数量。
    Ntotal\displaystyle N_{\text{total}}
  3. 比例计算两者相除,得到“被绑定组件的占比”,作为锁定风险指标。
    L=NproprietaryNtotal\displaystyle L = \frac{N_{\text{proprietary}}}{N_{\text{total}}}

工具生态

有了标准和理念,还需要码头设备:吊车、叉车、调度系统。基础设施工具生态就是这些机械的集合,它们让“不可变”、“多云”、“规避锁定”从口号变成可执行动作。

Terraform 是目前最主流的“调度台”,通过 Provider 屏蔽各云厂商 API 差异,一份配置可以被推到 AWS、Azure、GCP 等不同码头;Pulumi 则允许用 Python、TypeScript 等真实编程语言写基础设施逻辑;Crossplane 把云资源包装成 Kubernetes 自定义资源,让应用团队用熟悉的控制平面管理多云;策略即代码工具(如 OPA)负责在审批管道里拦截不合规配置,相当于港口安全员的自动巡检;迁移工具负责把镜像、存储和数据从一个码头搬到另一个码头。

工具越多,越需要量化“到底有多少资源真的被 IaC 管起来了”,否则容易把一两朵云的手动配置误当成“全公司多云平台”。我们用“基础设施代码覆盖率”来评估:

设备越多越好,但必须和码头账本对得上。工具生态的价值不是让你多装几个机械臂,而是让整套装卸流程标准化、可监控、可改进。

Cport=NmanagedNtotal\displaystyle C_{\text{port}} = \frac{N_{\text{managed}}}{N_{\text{total}}}
C_port 是被 IaC 管理的资源占总资源比例,用来衡量“调度台”到底掌控了多少码头设备。
  1. 已管理资源N_managed 表示纳管进 IaC 和版本控制的资源数量。
    Nmanaged\displaystyle N_{\text{managed}}
  2. 全部资源N_total 表示账号下所有云资源总数,包括手动创建的部分。
    Ntotal\displaystyle N_{\text{total}}
  3. 覆盖率两者相除,越接近 1 说明基础设施越“可被代码控制”。
    Cport=NmanagedNtotal\displaystyle C_{\text{port}} = \frac{N_{\text{managed}}}{N_{\text{total}}}

实践治理

再先进的码头也要有安全员、账房和海关。实践治理决定理念能否落地:团队协作、安全合规、成本治理和演进路线缺一不可。

团队协作上,“谁构建、谁运行”的文化让研发不只交付代码,还要交付包含黄金镜像、IaC 配置和部署管道的完整版本;安全合规要嵌进 CI/CD,镜像扫描、策略检查、密钥管理都在部署前自动完成;成本治理则要像账房一样盯住每朵云的资源账单,把“浪费”变成可量化的数字。演进路线上,不必一步迁到多云:先选一朵主云把不可变基建跑通,再用抽象层慢慢扩展第二朵云;存量散货机组可以用“绞杀者模式”逐步替换成标准集装箱,而不是一夜之间重写。

成本治理中最常见的问题不是“单价贵”,而是“买了不用”。一台 GPU 机器无论是否跑满,机器租金都在持续产生,于是浪费成本公式是:

港口不是一天建成的。实践治理就是逐步把散货换成标准箱,让安全员、账房、调度员都围着同一套蓝图协作,而不是各记各的账。

W=∑r=1n(ar−ur)×pr\displaystyle W = \sum_{r=1}^{n}(a_r - u_r) \times p_r
W 是资源浪费金额,a 是已分配容量,u 是实际使用容量,p 是单价;这个公式帮账房找出“空转的吊车”。
  1. 每类资源分配量a_r 表示第 r 类资源分配了多少容量。
    ar=allocated capacity\displaystyle a_r = \text{allocated capacity}
  2. 每类资源实际使用量u_r 表示真实被用掉的容量,空闲部分就是浪费。
    ur=used capacity\displaystyle u_r = \text{used capacity}
  3. 单价与求和乘以单价 p_r 并累加,得到全集团成本浪费总额。
    W=∑r=1n(ar−ur)×pr\displaystyle W = \sum_{r=1}^{n}(a_r - u_r) \times p_r

AI 应用场景

场景一:AI训练集群的不可变交付

阶段:训练环境交付

解决的问题:传统 GPU 集群环境依赖漂移,昨天能跑的训练脚本今天报错;手动装驱动、改 CUDA 版本会耗费 MLOps 团队大量时间。不可变基建把 CUDA、PyTorch、依赖库和校验脚本封进黄金镜像,训练任务启动时直接拉起全新实例,跑完整体销毁。

具体案例:某自动驾驶公司每次模型训练前,用 IaC 在云上创建 32 卡 GPU 集群,镜像版本随代码提交一起进入 CI/CD;训练结束环境自动销毁,下一次训练又是一只全新的集装箱。

场景二:多推理云容灾

阶段:在线推理服务

解决的问题:单一云区域故障会让线上推理中断;在多个云部署相同服务,并让流量通过抽象层动态切换,用户几乎无感。容器镜像、模型文件和推理服务配置保持可迁移,就能避免供应商锁定。

具体案例:大模型公司把推理网关部署在三朵云,用统一 Terraform 模块维护;某云区域网络抖动时,10 秒内把流量切到另一朵云,连实时对话都没有中断。

场景三:GPU 成本治理

阶段:资源成本优化

解决的问题:GPU 空闲是最大的成本浪费,但往往被“反正要用”掩盖。治理看板用浪费公式跟踪已分配但未使用的 GPU 容量,结合不可变实例的定时缩容、Spot 竞价,把成本从“估不准”变成“可度量”。

具体案例:量化交易公司按收盘时间自动销毁非生产 GPU 集群,并把离线训练任务调度到竞价实例上,月度云账单下降近四成。

Python 演示

python31 行
import math def multi_cloud_availability(availabilities):    # 各云故障独立 可用率列表取反后连乘    return 1 - math.prod(1 - a for a in availabilities) def portability_score(portable_weights, total_weights):    # 可迁移组件权重占总权重比例    portable = sum(portable_weights)    total = sum(total_weights)    return round(portable / total, 3) def immutable_batches(total_instances, batch_size):    # 滚动替换实例 每批数量固定    batches = []    done = 0    while done < total_instances:        current = min(batch_size, total_instances - done)        batches.append(current)        done += current    return batches if __name__ == "__main__":    values = [0.995, 0.990, 0.993]    print("multi cloud availability:", multi_cloud_availability(values))     portable_weights = [6, 5]    total_weights = [6, 5, 4, 3]    print("portability score:", portability_score(portable_weights, total_weights))     print("immutable batches:", immutable_batches(10, 3))
目的:用三个简单函数演示多云可用率、可移植性评分和不可变滚动批次的计算,让抽象概念变成可运行的数字。
  1. return 1 - math.prod(1 - a for a in availabilities)把每朵云的故障率相乘,再用 1 减去,就是“至少一朵云可用”的概率。
  2. portable = sum(portable_weights)累加被抽象层覆盖的组件权重,也就是能自由迁移的部分。
  3. total = sum(total_weights)累加所有组件权重,作为可移植性分母。
  4. current = min(batch_size, total_instances - done)滚动替换时,最后一批如果不足一个批次,就只取剩余数量。
  5. batches.append(current)记录每批替换数量,方便安排发布窗口。
  6. while done < total_instances:一直替换到所有实例都完成版本升级为止。

常见误区

误区既然用了 Docker 和统一镜像,三朵云都能跑同一套应用,那直接把镜像复制到三朵云就是多云了吧?

正解容器镜像只解决了应用层可移植,网络、存储、负载均衡、权限模型等底层设施仍然各不相同。真正多云必须用 IaC 抽象层管理这些差异,并做故障隔离和数据出口演练。否则就像集装箱规格统一了,但每个码头的吊具还是只认自己的钩子。

为何常见:容器确实隐藏了大量底层差异,容易让人以为“能跑”就等于“可移植”。

误区我写了一个 shell 脚本自动创建云资源,这就是基础设施即代码了。

正解IaC 的核心是声明式描述期望状态,并依赖状态文件感知漂移;shell 脚本是命令式的,只告诉机器“怎么做”,没有“最终应该长什么样”。同一段脚本跑一万次可能产生一万个中间态,这不是 IaC。

为何常见:把“自动化”和“声明式”混为一谈,看到不用手动点控制台就以为是 IaC。

误区叫“不可变”那是不是建好就永远不动,安全补丁也打不了了?

正解不可变指的是“不修补运行中的实例”,而不是“不更新软件”。每次安全更新都打进新的黄金镜像,再用新实例替换旧实例,旧实例销毁。补丁没有消失,只是从“现场手术”变成了“出厂前重新压箱”。

为何常见:immutable 这个英文词本身容易带来“永远不变”的直觉误导。

误区只要引入了 Terraform 之类的抽象,供应商锁定就彻底消失了,后面不用再管。

正解抽象层会随着云厂商新服务和 API 变更而漂移,甚至悄然退化成“针对某朵云的定制封装”。规避锁定需要持续做可移植性测试、定期演练镜像与数据迁移,并在新组件引入时评估它的锁定度。

为何常见:人们总希望用一个工具解决永久问题,但锁定规避本质上是持续治理。

面试题

Q1. 不可变基础设施的核心思想是?

单选题 · easy

  • A.对线上实例持续打补丁
  • B.用新实例整体替换旧实例← 正确答案
  • C.完全禁用自动更新机制
  • D.登录服务器手动改配置

答案:B。不可变基础设施拒绝修复运行中的实例,而是把变更放进新镜像,然后整箱替换。A、D 是典型可变基础设施思维,C 的错误在于把“不可变”误当成“不更新”。

Q2. 蓝绿部署的最大特点是?

单选题 · easy

  • A.新旧版本同时在线切换← 正确答案
  • B.逐台分批替换实例
  • C.先给少量用户灰度试点
  • D.直接删除旧版本数据

答案:A。蓝绿部署维护两套并行环境,通过切换流量完成发布;滚动部署才是分批替换,金丝雀发布才是小流量试点,D 则是错误操作。

Q3. 基础设施即代码中的“声明式配置”描述的是?

单选题 · easy

  • A.一步步执行操作命令
  • B.描述期望的最终状态← 正确答案
  • C.记录网络物理链路
  • D.指定硬件采购清单

答案:B。声明式配置只表达“最终应该有什么”,不关心具体执行步骤;A 是命令式脚本思路,C、D 都不是基础设施配置语义。

Q4. 多云联合可用率公式成立的关键假设是?

单选题 · mid

  • A.各云故障完全同时发生
  • B.各云故障概率相互独立← 正确答案
  • C.单云可用率必然低于 0.9
  • D.多云会放大雪崩效应

答案:B。联合可用率用“同时故障概率连乘”,前提是各云故障相互独立。如果故障完全同步发生,多云的冗余价值就会消失,因此 B 对、A 错。

Q5. 供应商锁定的主要根源是?

单选题 · mid

  • A.使用标准化虚拟机镜像
  • B.依赖专有API与托管服务← 正确答案
  • C.采用开源容器调度平台
  • D.同步部署到多个云区域

答案:B。锁定来自专有 API、私有数据格式和不可迁移托管服务。标准化镜像和开源平台反而降低锁定,部署到多个区域是多云行为而非锁定根源。

Q6. Terraform 的 Provider 主要作用是?

单选题 · mid

  • A.屏蔽不同云厂商的API差异← 正确答案
  • B.加密跨云传输的数据流量
  • C.替代Kubernetes完成调度
  • D.自动生成应用的业务代码

答案:A。Provider 把各云 API 差异封装成统一资源模型,让 IaC 配置可以跨云使用;它不负责加密、容器调度,更不生成业务代码。

Q7. 不可变部署中通常如何执行回滚?

单选题 · mid

  • A.用旧黄金镜像替换整组实例← 正确答案
  • B.对当前实例逆向执行补丁
  • C.修改数据库存储引擎格式
  • D.重启负载均衡并清空缓存

答案:A。不可变部署没有“撤销补丁”,只有“切回旧镜像并整体替换”。B 正是可变基础设施做法,C、D 与版本回滚无关。

Q8. 多云架构通常能带来哪些收益?

多选题 · mid

  • A.提升整体供应商议价能力← 正确答案
  • B.降低单一云故障影响范围← 正确答案
  • C.减少对特定厂商的业务依赖← 正确答案
  • D.必然降低所有资源使用成本

答案:ABC。多云能提升议价权、增强故障隔离、降低供应商依赖。但它也会增加网络和运维复杂度,未必降低成本,所以 D 的“必然降低”是错的。

Q9. 供应商锁定规避的有效手段包括?

多选题 · extreme

  • A.在IaC层引入抽象接口封装← 正确答案
  • B.定期演练数据与镜像迁移← 正确答案
  • C.限制使用专有托管服务← 正确答案
  • D.始终选择报价最低的云厂商

答案:ABC。抽象层、迁移演练、控制专有服务依赖都是保留逃生路线的做法;只贪图便宜而忽视可迁移性,反而可能在未来付出更高迁移代价。

Q10. 关于配置漂移下列说法正确的是?

多选题 · hard

  • A.手工登录改配置会导致漂移← 正确答案
  • B.状态文件可以辅助发现漂移← 正确答案
  • C.漂移只可能出现在多云场景
  • D.定期巡检并重新应用IaC可缓解← 正确答案

答案:ABD。任何绕过 IaC 的手工修改都会让实际状态离开期望状态,状态文件正是对比工具;漂移在单云也会发生,所以 C 错。定期巡检和重新 apply 是有效治理手段。