跳转至

用 Kubernetes 部署、更新与保护应用

这一章把第 15 章的对象全部用上,走一个应用的一生: 上线、体检、升级、加固。 主线例子是 TaskBoard——前端(NGINX 静态页)、api(REST 后端)、db(PostgreSQL 带持久存储)三组件小应用。每一步都先在本地集群(minikube)验证再往前走。

1. 部署:五块积木按序搭

书里的顺序本身就是最佳实践(每一步可独立验证)1:

  ① minikube start;用 minikube image build 直接把镜像构建进集群
      (省掉推注册表再拉的往返)
  ② 建专用 namespace taskboard,并把 kubectl 上下文指到它
      → 资源隔离、一把 delete ns 全清场
  ③ ConfigMap(非密配置)+ Secret(数据库凭据)
      → apply 后 kubectl get configmap,secret 验收
      (书里注明:示例用 stringData 图可读性,生产要外部密管+静态加密)
  ④ PersistentVolumeClaim:1 GB 存储声明给 PostgreSQL
  ⑤ 三个 Deployment + 三个 Service,从底往上:db → api(2 副本)→ frontend
      每步 kubectl rollout status deploy/xxx 等"successfully rolled out"
      集群内用 busybox 容器对 api 服务的 /health 端点做 wget 冒烟[^1]

访问应用的通用姿势两种:minikube service frontend --url(给一个 http://127.0.0.1:51788 式的 URL)或 kubectl port-forward svc/frontend 8081:80 (任何集群通用)1。

2. 探针:让 K8s 真的"懂"你的应用

应用跑起来了,但K8s 还不知道 Pod 是真健康还是假活着——API 进程挂死、 容器启动慢,K8s 默认都当成没事2。三种探针(第 14 章"接缝"的正式形态)3:

探针 问什么 失败后果
liveness 容器还正常运转吗 重启容器
readiness 能接流量了吗 把 Pod 从 Service 端点暂时摘除(不重启)
startup (慢启动专用)初始化完没 在此之前暂停 liveness/readiness 检查

TaskBoard 的 API 暴露 /health(正常返回 {"status":"ok"}),把它配进 Deployment 的容器规格即可3。startup probe 的算术书里给了: failureThreshold: 30 × periodSeconds: 5 = 150 秒启动窗口—— 数据库迁移、数据预热这类慢启动不再会被误杀4。

两个肉眼可见的自愈实验(值得照做):

  • 杀 Pod:挑一个 API Pod kubectl exec ... kill 1 → 终端 A 看旧 Pod Terminating、新 Pod ContainerCreating→Running;终端 B 看 Service 端点 短暂少一个 IP、新 Pod readiness 通过后加回;终端 C 看控制面事件流 (Killing、Created、Scheduled、Started、Readiness probe succeeded)5。
  • 断依赖:把 db 缩到 0 → API Pod 仍 Running 但 READY 变 0/1 (readiness 失败)→ 自动从 Service 摘除,流量不再打到"活着但干不了活"的 Pod;恢复 db 后自愈回流6。

这两场戏说明 ReplicaSet 与 readiness 的分工:一个管"数量对",一个管"谁能接客"。

3. 零停机更新:滚动与蓝绿

滚动更新(Deployment 默认策略)——改镜像 tag 即触发:一批一批换, 书里调优的参数是 maxSurge: 1(最多多出一个新 Pod)、maxUnavailable: 0 (旧 Pod 不许少)——先加后减,任何时刻容量不缩水;出问题 kubectl rollout undo deployment/api 一键回滚7。

蓝绿部署——书里给了完整的五步表8:

步骤 环境 流量 备注
1 只有 blue(v1.0.0) ✅ 稳定生产
2 部署 green(v1.1.0) ❌ 只测不接客
3 切 Service selector ✅ v1.1.0 用户上了 green
4 移除 blue ✅ 清场
5 (可选)回切 ✅ v1.0.0 秒级回滚

蓝绿的全部机关就是改 Service 的 selector 一行;滚动适合持续交付的 "天天发",蓝绿适合"切流量前先验证"的谨慎场景。两者目标相同(零停机), 节奏不同9。

4. 安全:把安全写成配置

书里的立场一句顶全章:"安全不是最后加的功能,在 K8s 里安全就是配置, 和 Deployment、Service 一样的写法。" 五步走10:

  1. 非 root + 只读文件系统:Dockerfile 里 useradd -m -u 1000 ... appuser 并 chown;Pod 层用 runAsNonRoot: true、readOnlyRootFilesystem: true 强制执行——镜像和 Pod 两层都要11;
  2. ServiceAccount + 最小权限 RBAC:给应用专用的 ServiceAccount, 只授它用得上的权限(第 14 章 RBAC 的落地);
  3. namespace 级 Pod 安全标准(Pod Security Standards/Admission): 在 namespace 上贴 enforce 标签,违规 Pod 直接被拒;
  4. NetworkPolicy:默认拒绝 + 精确放行——和第 10 章"网络即防火墙" 一脉相承,只是策略对象化:先 deny all,再逐条允许"api 可以连 db 的 5432"之类;
  5. secrets 的安全真相:K8s 的 Secret 默认只是 base64 编码——混淆,不是 加密;生产要开 etcd 静态加密,或直接用 Vault/云厂商密管10。

5. 作者的判断与证据

  • "先加后减(maxSurge 1/maxUnavailable 0)"是滚动更新的稳妥默认, 代价是更新期间需要一点额外容量——书里作为推荐配置给出7。
  • 蓝绿=一行 selector 的讲法把这套"高大上"部署模式拉回了 YAML 现实, 证据就是那张五步表8。
  • base64 ≠ 加密的警告(书中明写 "provides obfuscation but not strong encryption")值得贴在每个用 Secret 的团队墙上10。
  • 双终端自愈实验是全书最直观的"控制循环"演示,机制与现象逐条对应56。

判断(我们的,不是书里的): 本章最该带走的不是某个 YAML,而是 "应用对 K8s 说的话越多,K8s 替应用做得越多" 这条曲线:/health 端点一个, 换来 liveness/readiness 两种自动处置;label 一个,换来 Service 的选择器与 NetworkPolicy 的靶子;ConfigMap/Secret 一对,换来配置与凭据的分离管理。 反过来,什么都不声明的应用在 K8s 里只是"能跑",拿不到任何自动化的红利。 如果错,会错在: 声明式自动化的红利有天花板——应用语义(什么算"健康"、 什么算"就绪")终究只有开发者知道;探针配错(liveness 探到依赖上)反而会 造成重启风暴。自动化不是免思考,是把思考挪到声明处。

6. 边界与局限

  • 示例以 minikube 为基准;kind/Docker Desktop 在"暴露 Service"一步命令不同 (书中给了注记)。
  • GitOps 缺位:本章全是 kubectl apply 手工流;第 14 章预告的 Argo CD/Flux 没在这里接上(第 20 章 CI/CD 案例补了一点)。
  • NetworkPolicy 需要 CNI 支持才有实际效果——书中没强调这一点, 某些本地集群的默认网络插件并不执行策略(补充,不在书里,来自通用知识)。
  • HPA(自动扩缩)、资源 requests/limits 的调优未展开。

7. 可带走的

  1. 部署五序:镜像→namespace→ConfigMap/Secret→PVC→Deployment+Service1。
  2. 访问应用:minikube service --url 或 kubectl port-forward1。
  3. liveness 重启、readiness 摘流量、startup 给窗口——三探针三件事3。
  4. startup 算术:30×5=150 秒启动宽限4。
  5. 自愈分工:ReplicaSet 保数量,readiness 管接客56。
  6. 滚动:maxSurge: 1/maxUnavailable: 0 先加后减;rollout undo 回滚7。
  7. 蓝绿五步法,机关是 Service selector 一行8。
  8. 安全即配置:非 root+只读、ServiceAccount 最小权限、Pod 安全标准、 NetworkPolicy 默认拒绝、Secret 要真加密1011。

8. 原文地图

主题 原书章 原文位置
TaskBoard 组件与部署序 Deploying our first application text/179-fm-deploying-our-first-application.txt:2(搜「TaskBoard」) · text/179-fm-deploying-our-first-application.txt:23(搜「minikube image build」) · text/179-fm-deploying-our-first-application.txt:31(搜「namespace」)
ConfigMap/Secret 与 PVC Deploying our first application text/179-fm-deploying-our-first-application.txt:41(搜「ConfigMap」) · text/179-fm-deploying-our-first-application.txt:53(搜「stringData」) · text/179-fm-deploying-our-first-application.txt:61(搜「PersistentVolumeClaim」)
逐组件部署与冒烟 Deploying our first application text/179-fm-deploying-our-first-application.txt:84(搜「rollout status」) · text/179-fm-deploying-our-first-application.txt:106(搜「wget」) · text/179-fm-deploying-our-first-application.txt:127(搜「minikube service」)
为什么需要探针 Defining liveness, readiness, and startup probes text/180-fm-defining-liveness-readiness-and-startup-probes.txt:1(搜「doesn't yet know」) · text/180-fm-defining-liveness-readiness-and-startup-probes.txt:15(搜「restarts」) · text/180-fm-defining-liveness-readiness-and-startup-probes.txt:20(搜「removes」) · text/180-fm-defining-liveness-readiness-and-startup-probes.txt:21(搜「delays」)
startup 算术 Defining liveness, readiness, and startup probes text/180-fm-defining-liveness-readiness-and-startup-probes.txt:72(搜「failureThreshold」) · text/180-fm-defining-liveness-readiness-and-startup-probes.txt:75(搜「150 seconds」)
自愈双实验 Defining liveness, readiness, and startup probes text/180-fm-defining-liveness-readiness-and-startup-probes.txt:116(搜「kill 1」) · text/180-fm-defining-liveness-readiness-and-startup-probes.txt:132(搜「--replicas=0」) · text/180-fm-defining-liveness-readiness-and-startup-probes.txt:136(搜「0/1」)
滚动参数与回滚 Zero-downtime deployments text/181-fm-zero-downtime-deployments.txt:188(搜「rollout undo」) · text/181-fm-zero-downtime-deployments.txt:202(搜「maxSurge」) · text/181-fm-zero-downtime-deployments.txt:203(搜「maxUnavailable」)
蓝绿五步表 Zero-downtime deployments text/182-fm-security-best-practices.txt:3(搜「Blue」) · text/182-fm-security-best-practices.txt:13(搜「Table 16.1」)
滚动 vs 蓝绿的取舍 Zero-downtime deployments text/182-fm-security-best-practices.txt:17(搜「gradual」)
安全即配置 Security best practices text/182-fm-security-best-practices.txt:28(搜「not a feature」) · text/182-fm-security-best-practices.txt:40(搜「base64」)
非 root 与只读 Security best practices text/182-fm-security-best-practices.txt:59(搜「useradd」)

  1. 出处:「Deploying our first application」第 1–155 段(text/179-fm-deploying-our-first-application.txt:3,搜「frontend」;:23,搜「minikube image build」;:31,搜「create namespace」;:41,搜「ConfigMap」;:65,搜「apply -f k8s/storage.yaml」;:84,搜「rollout status」;:127,搜「minikube service」)。 ↩↩↩↩

  2. 出处:「Defining liveness, readiness, and startup probes」第 1–6 段(text/180-fm-defining-liveness-readiness-and-startup-probes.txt:2,搜「hangs」;:3,搜「assume everything is fine」)。 ↩

  3. 出处:「Defining liveness, readiness, and startup probes」第 8–29 段(text/180-fm-defining-liveness-readiness-and-startup-probes.txt:12,搜「probes」;:15,搜「restarts the」;:18,搜「removes the Pod」;:21,搜「delays」;:26,搜「status」)。 ↩↩↩

  4. 出处:「Defining liveness, readiness, and startup probes」第 62–86 段(text/180-fm-defining-liveness-readiness-and-startup-probes.txt:72,搜「failureThreshold」;:75,搜「150 seconds」)。 ↩↩

  5. 出处:「Defining liveness, readiness, and startup probes」第 88–126 段(text/180-fm-defining-liveness-readiness-and-startup-probes.txt:116,搜「kill 1」;:120,搜「Terminating」;:124,搜「Readiness probe succeeded」)。 ↩↩↩

  6. 出处:「Defining liveness, readiness, and startup probes」第 127–137 段(text/180-fm-defining-liveness-readiness-and-startup-probes.txt:132,搜「--replicas=0」;:136,搜「0/1」;:137,搜「removed from the Service」)。 ↩↩↩

  7. 出处:「Zero-downtime deployments」(text/181-fm-zero-downtime-deployments.txt:188,搜「rollout undo」;:199,搜「strategy」;:202,搜「maxSurge」;:203,搜「maxUnavailable」)。 ↩↩↩

  8. 出处:「Zero-downtime deployments」的蓝绿表(因转码顺序位于文件 182 开头:text/182-fm-security-best-practices.txt:3,搜「Blue」;:12,搜「Table 16.1」)。 ↩↩↩

  9. 出处:「Zero-downtime deployments」的取舍总结(text/182-fm-security-best-practices.txt:17,搜「gradual」;:15,搜「full manual control」)。 ↩

  10. 出处:「Security best practices」第 1–24 段(text/182-fm-security-best-practices.txt:28,搜「not a feature」;:2,搜「configuration」;:6,搜「ServiceAccount」;:11,搜「NetworkPolicy」;:14,搜「secrets」;:19,搜「base64」;:20,搜「obfuscation」;:22,搜「encryption at rest」)。 ↩↩↩↩

  11. 出处:「Security best practices」的 Step 1(text/182-fm-security-best-practices.txt:59,搜「useradd」;:33,搜「nologin」;:35,搜「runAsNonRoot」)。 ↩↩