用 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:
- 非 root + 只读文件系统:Dockerfile 里
useradd -m -u 1000 ... appuser并 chown;Pod 层用runAsNonRoot: true、readOnlyRootFilesystem: true强制执行——镜像和 Pod 两层都要11; - ServiceAccount + 最小权限 RBAC:给应用专用的 ServiceAccount, 只授它用得上的权限(第 14 章 RBAC 的落地);
- namespace 级 Pod 安全标准(Pod Security Standards/Admission): 在 namespace 上贴 enforce 标签,违规 Pod 直接被拒;
- NetworkPolicy:默认拒绝 + 精确放行——和第 10 章"网络即防火墙" 一脉相承,只是策略对象化:先 deny all,再逐条允许"api 可以连 db 的 5432"之类;
- 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. 可带走的¶
- 部署五序:镜像→namespace→ConfigMap/Secret→PVC→Deployment+Service1。
- 访问应用:
minikube service --url或kubectl port-forward1。 - liveness 重启、readiness 摘流量、startup 给窗口——三探针三件事3。
- startup 算术:30×5=150 秒启动宽限4。
- 自愈分工:ReplicaSet 保数量,readiness 管接客56。
- 滚动:
maxSurge: 1/maxUnavailable: 0先加后减;rollout undo回滚7。 - 蓝绿五步法,机关是 Service selector 一行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」) |
-
出处:「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」)。 ↩↩↩↩ -
出处:「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」)。 ↩ -
出处:「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」)。 ↩↩↩ -
出处:「Defining liveness, readiness, and startup probes」第 62–86 段(
text/180-fm-defining-liveness-readiness-and-startup-probes.txt:72,搜「failureThreshold」;:75,搜「150 seconds」)。 ↩↩ -
出处:「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」)。 ↩↩↩ -
出处:「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」)。 ↩↩↩ -
出处:「Zero-downtime deployments」(
text/181-fm-zero-downtime-deployments.txt:188,搜「rollout undo」;:199,搜「strategy」;:202,搜「maxSurge」;:203,搜「maxUnavailable」)。 ↩↩↩ -
出处:「Zero-downtime deployments」的蓝绿表(因转码顺序位于文件 182 开头:
text/182-fm-security-best-practices.txt:3,搜「Blue」;:12,搜「Table 16.1」)。 ↩↩↩ -
出处:「Zero-downtime deployments」的取舍总结(
text/182-fm-security-best-practices.txt:17,搜「gradual」;:15,搜「full manual control」)。 ↩ -
出处:「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」)。 ↩↩↩↩ -
出处:「Security best practices」的 Step 1(
text/182-fm-security-best-practices.txt:59,搜「useradd」;:33,搜「nologin」;:35,搜「runAsNonRoot」)。 ↩↩