
应用部署这件事说简单也简单把镜像推上去、配置挂进去、服务拉起来三条命令的事说复杂也复杂尤其是当你面对的不是一台机器而是一整个需要统一编排、统一配置、统一观测的集群时部署方式选错了后面每一次发版都是折磨。我这次要聊的是一套围绕 CKE 做应用部署的完整落地思路。CKE 在这里指的是一类以容器编排为核心、把配置管理、密钥管理、滚动发布、健康检查打包在一起的应用运行底座你可以把它理解成一个应用交付的控制面——它不负责写业务代码但决定了你的业务代码以什么姿态跑起来、怎么升级、出问题怎么回滚、配置改了怎么生效。很多人第一次接触这类平台容易把它当成高级版的应用服务器于是沿用老思路手工改配置、重启进程、盯着日志看有没有起来。结果就是部署过程不可复现环境之间漂移严重出了问题只能靠人肉记忆去回溯。我这篇内容想解决的就是把基于 CKE 的应用部署从一堆零散操作变成一套有章法、可复现、能交接的流程。适合两类人看一类是刚接手容器化部署、手里有一堆应用要上线的工程师另一类是已经在用编排平台但部署流程还很野生、想把它规范化的团队骨干。下面我会从部署模型的选择讲起一路讲到配置注入、发布策略、排错链路和最后的经验沉淀尽量把每一步为什么这么做讲透而不是只丢一堆命令给你抄。1. 先想清楚 CKE 部署模型到底在管什么动手之前得先把这套底座的职责边界划清楚。CKE 这类平台的核心抽象其实就三层工作负载你的应用以什么形态运行比如无状态服务、定时任务、常驻守护进程、配置与密钥应用运行需要的外部参数和敏感信息、发布控制器决定新版本怎么替换旧版本、失败怎么处理。这三层是解耦的理解这一点非常关键因为后面所有的部署设计本质上都是在回答这三层怎么组合。1.1 工作负载形态选错后面全是补丁我见过最常见的错误是把一个需要持久化状态的服务硬塞进无状态工作负载里跑。表面上看能起来但一旦发生调度迁移数据就丢了然后团队开始加各种临时挂载、启动脚本里做数据恢复越补越乱。正确的判断逻辑是这样的先问这个应用有没有本地状态。如果它把数据写在本地磁盘、且这份数据对重启后的正确性有影响那它就不该用无状态形态要么改成把状态外置到独立存储要么用带状态的工作负载形态并配合稳定的存储卷声明。判断标准我一般用一张表来对照落地时直接套应用特征推荐工作负载形态关键理由无本地状态、可水平扩展无状态服务任意副本可互换滚动发布简单有本地状态、需稳定标识带状态工作负载副本有稳定网络标识与存储绑定一次性或周期性执行任务型工作负载生命周期短成功即终止每个节点都要跑一份守护型工作负载随节点调度自动铺开这张表不是让你死记而是让你在动手前先做一次形态体检。形态选对了后面的副本数、更新策略、存储声明都是顺理成章的事形态选错了你会发现每个环节都在跟平台对抗。1.2 副本数与资源请求别拍脑袋算一遍副本数不是越多越稳。我踩过的坑是一个内存占用 800MB 左右的服务资源请求随手写了 256MB副本开了 6 个结果调度器把好几个副本塞到同一台节点上运行一段时间后节点内存吃紧开始驱逐服务反而抖得厉害。这里的核心逻辑是资源请求决定了调度器怎么给你分配位置限制决定了运行时能用到多少。请求写小了调度器以为你很轻拼命往一台机器上堆请求写大了浪费容量。一个可复现的算法是这样的先压测拿到单副本的稳定内存占用峰值比如 800MB然后请求值取峰值的 1.2 到 1.5 倍也就是 1GB 左右限制值取峰值的 1.5 到 2 倍给突发留余量。副本数则用目标并发 ÷ 单副本安全并发来估再留一个副本做冗余。这套算法不精确但比拍脑袋强得多而且它逼你去压测压测本身就是一次对应用真实资源画像的摸底。提示资源请求和限制的比值不要拉得太开请求 256MB、限制 4GB 这种配置会让调度严重失真节点看起来还有余量实际一跑就爆。1.3 命名空间与标签体系部署的地基命名空间划分看似是管理动作其实直接影响部署的可维护性。我的习惯是按环境 业务域两个维度切比如开发、预发、生产各一个命名空间同一环境内再按业务域用标签区分。标签体系要在第一次部署时就定好至少包含应用名、版本、环境、负责人四个维度。为什么强调这个因为后面的滚动发布、灰度、监控聚合、日志检索全都依赖标签做筛选。标签定得随意后面想按应用聚合指标都聚不起来只能一个个手工挑运维成本直接翻倍。2. 配置与密钥注入部署里最容易翻车的一环应用能不能起来一半看镜像一半看配置。CKE 这类平台把配置和密钥做成了独立对象好处是配置和镜像解耦改配置不用重新打镜像坏处是如果你不理解它的注入时机和更新机制就会出现配置改了但应用没生效这种经典问题。这一章我把配置注入的几种方式、更新行为、以及敏感信息处理讲清楚。2.1 三种注入方式的适用边界配置注入一般有三种路子环境变量、配置文件挂载、启动参数。它们不是随便选的各有各的脾气。环境变量适合少量、扁平、启动时就需要读到的参数比如数据库地址、日志级别。它的优点是简单直接应用代码里读一下环境变量就行缺点是更新不会自动生效——环境变量是在容器启动时注入的你改了配置对象运行中的容器不会感知必须重启工作负载才会重新读取。这一点很多人栽过跟头改完配置以为生效了实际跑的还是老值。配置文件挂载适合结构化、体积较大的配置比如一份完整的应用配置文件。它的更新行为取决于挂载方式以卷方式挂载的配置文件底层文件更新后容器内看到的文件内容会在一段时间后同步通常有几十秒延迟但应用是否重新加载还得看应用自己有没有监听文件变化。所以挂载即生效是个错觉真正生效的前提是应用支持热加载。启动参数适合那些必须在进程启动命令行里传入的开关灵活性最差一般只在没有其他办法时用。我的选型原则很简单能在配置文件里表达的就别塞环境变量能通过应用自身热加载解决的就别靠重启。这样部署的稳定性最高变更的影响面最小。2.2 密钥对象的使用纪律密钥管理是安全红线也是部署流程里最容易被忽视的细节。CKE 提供的密钥对象本质是把敏感信息从镜像和代码里剥离出来单独存储、单独授权。使用时有几条纪律必须守住。第一密钥绝不进镜像、不进代码仓库、不写进普通配置文件。我见过把数据库密码直接写进应用配置文件的一旦配置文件被误提交等于把钥匙挂在门上。第二密钥对象的访问权限要按命名空间和角色收紧不是所有工作负载都能读所有密钥。第三密钥轮换要有流程改完密钥对象后依赖它的工作负载需要重启才能读到新值——这一点和环境变量一样不会自动生效。注意密钥对象更新后不重启工作负载应用读到的仍是旧密钥。轮换密钥时务必把更新密钥对象和重启依赖工作负载当成一个原子操作来执行中间别漏步骤。2.3 配置版本化让每次部署可回溯配置漂移是部署事故的高发区。同一个应用开发环境跑得好好的上了生产就起不来十有八九是配置不一致。解决办法是配置版本化把配置对象也纳入版本管理每次变更都留痕部署时明确指定用的是哪个版本的配置。具体做法可以给配置对象打上版本标签或者在配置内容里加一个版本字段部署清单里引用固定版本。这样出问题时你能快速回答这次部署用的到底是哪份配置而不是靠翻聊天记录去猜。我一般会在部署清单里把配置对象的名称带上版本后缀比如应用配置加一个日期或递增号虽然看起来啰嗦但回溯的时候非常省心。代价是配置对象会变多需要定期清理旧版本这个清理动作可以做成例行任务。3. 发布策略滚动、灰度、回滚怎么配合部署不是把新版本推上去这么简单真正考验设计的是新版本有问题时怎么办。CKE 这类平台一般内置了滚动发布能力但滚动发布只是基础灰度控制和快速回滚才是让发布变得可控的关键。这一章讲发布策略的组合拳。3.1 滚动发布的参数怎么调滚动发布的核心参数有两个最大不可用和最大超出。前者控制发布过程中最多允许多少个副本不可用后者控制最多允许多少个额外副本被临时创建。这两个参数直接决定了发布的速度和风险。如果最大不可用设为 0、最大超出设为 1意思是发布时先起一个新副本等它就绪后再下线一个旧副本全程保证可用副本数不低于期望值。这种配置最稳但发布慢适合对可用性要求极高的服务。如果最大不可用设为 25%、最大超出设为 25%发布就快很多但过程中可用容量会短暂下降适合能容忍短暂容量波动的内部服务。我的经验是对外服务用保守参数内部服务用激进参数并且一定要配好就绪探针。就绪探针没配好滚动发布就是盲滚——平台不知道新副本到底能不能接流量只能按时间硬等要么等太久拖慢发布要么等太短把流量打到一个还没准备好的实例上。3.2 就绪探针与存活探针的分工这两个探针经常被混为一谈其实职责完全不同。就绪探针回答的是这个实例现在能不能接流量存活探针回答的是这个实例是不是已经卡死了、需要重启。搞混的后果很严重把耗时的初始化逻辑塞进存活探针会导致实例还没初始化完就被判定死亡、反复重启陷入重启循环。正确的做法是就绪探针检查应用是否完成了初始化、依赖是否可用比如能不能连上数据库、缓存是否预热完成存活探针只检查进程是否还在正常响应用一个轻量的健康端点即可。探针的初始延迟要给足尤其是启动慢的应用初始延迟设短了实例还没起来就被判死发布永远成功不了。3.3 灰度与回滚的衔接灰度发布是在滚动发布之上再加一层流量控制先让一小部分流量打到新版本观察指标正常后再逐步放大比例。CKE 环境下做灰度通常靠副本比例或者流量规则来实现。副本比例的方式简单比如总共 10 个副本先起 1 个新版本副本观察一段时间没问题再扩大流量规则的方式更精细可以按请求特征分流但配置复杂度也更高。回滚的关键是保留历史版本。平台一般会保留若干个历史修订版本回滚就是把工作负载指回上一个修订。这里有个容易忽略的点回滚只回滚工作负载的镜像和配置引用不回滚数据。如果新版本做了不兼容的数据结构变更回滚后旧版本可能读不了新数据。所以涉及数据变更的发布必须提前设计向前兼容的迁移方案回滚预案里要写清楚数据怎么处理。发布场景推荐策略回滚要点常规功能迭代滚动发布 就绪探针保留上一修订直接指回高风险核心服务灰度 指标观察灰度阶段即可止损无需全量回滚涉及数据结构变更分阶段发布先兼容后切换回滚需配套数据兼容方案4. 部署后的观测与排错链路部署成功不等于部署正确。我见过太多发布成功、服务全挂的案例——平台报告所有副本就绪但用户请求全在报错。原因往往是就绪探针写得太宽松或者根本没检查依赖。所以部署之后必须有一套观测和排错链路能在几分钟内定位问题出在哪一层。4.1 从现象到根因的分层排查排错最忌讳一上来就翻应用日志。正确的顺序是从外到内分层排查先看工作负载状态副本数对不对、有没有反复重启、事件里有没有调度失败或镜像拉取失败再看网络与依赖服务能不能解析、端口通不通、依赖的数据库和缓存连不连得上最后才看应用日志。这个顺序能把大部分部署层面的问题挡在应用日志之前省下大量时间。举个真实场景某次发布后服务 502第一反应是应用挂了结果一查工作负载状态副本数是 0事件里写着镜像拉取失败——镜像标签打错了。如果先去翻应用日志会发现日志里啥也没有因为容器根本没起来。分层排查的价值就在这里。4.2 事件与日志的配合使用平台的事件对象记录了调度、拉取、挂载、探针失败等关键动作是排错的第一手材料。应用日志则记录业务逻辑层面的信息。两者要配合看事件告诉你平台层面发生了什么日志告诉你应用层面发生了什么。我习惯在部署后第一时间看事件确认没有异常事件再看应用启动日志确认初始化正常最后做一次端到端请求验证。这三步走完才算真正部署完成。4.3 常见部署故障对照表把高频故障整理成对照表排错时直接查效率最高现象可能原因排查动作副本一直不就绪就绪探针过严或初始延迟不足调大初始延迟放宽探针阈值反复重启存活探针误判或资源限制过小检查探针配置与内存限制镜像拉取失败标签错误或仓库凭证失效核对镜像地址与拉取凭证配置不生效环境变量未重启或挂载未同步重启工作负载确认挂载方式服务间调用失败服务发现或网络策略阻断检查服务定义与网络策略5. 把部署流程沉淀成可交接的资产部署做一次不难难的是让团队里任何人都能按同样的流程做出同样的结果。这一章讲怎么把前面这些设计固化成可复用的资产让部署从个人手艺变成团队能力。5.1 部署清单的目录组织部署清单不要一股脑塞进一个文件。我推荐按应用 资源类型组织目录每个应用一个目录里面按工作负载、服务、配置、密钥、存储声明分文件。这样改配置只动配置文件改镜像只动工作负载文件职责清晰代码评审时也容易看出改了什么。目录里再放一个说明文件写清楚这个应用依赖哪些外部服务、部署顺序是什么、回滚步骤是什么新人接手时不用到处问人。5.2 部署前的检查清单部署前跑一遍检查清单能挡掉大部分低级错误。我的清单一般包含镜像标签是否明确禁止用最新标签、资源请求和限制是否填写、探针是否配置、配置和密钥引用是否存在、副本数是否符合预期、发布策略参数是否合理。这份清单可以做成脚本自动校验也可以做成人工核对项关键是每次部署都执行不能因为这次改动小就跳过。跳过检查的那次往往就是出事的那次。5.3 部署记录与复盘每次部署留一条记录谁发的、什么时间、发了什么版本、用了哪份配置、结果如何。这条记录在出问题时是无价之宝。更进一步每次故障后做一次简短复盘把根因和改进行动记下来沉淀到团队的知识库里。时间长了你会发现大部分部署事故都是重复的几类问题复盘做多了同类问题自然就少了。我在实际落地这套流程时最大的体会是部署的可靠性不取决于平台多强大而取决于流程里有多少环节是必须做、且做了有记录的。平台能帮你自动化的部分尽量自动化但检查清单、发布记录、回滚预案这些人肉环节恰恰是最后一道防线。踩过几次因为跳过检查而导致的发布事故之后我现在宁可发布慢十分钟也要把清单走完——这十分钟往往能省下后面几小时的救火时间。