Kubernetes 声明式 API 详解
K8s 最核心的设计思想,理解了它才算真正理解K8s。
一、什么是声明式 API?
声明式 = 告诉系统"我想要什么",系统自己想办法达到。
打个比方
| 方式 | 场景 | 你做什么 | 谁负责实现 |
|---|---|---|---|
| 命令式 | 自己开车 | 握方向盘、踩油门、踩刹车 | 你自己 |
| 声明式 | 坐自动驾驶 | 说"我要去公司" | 系统(车) |
二、命令式 vs 声明式 对比
| 维度 | 命令式(Imperative) | 声明式(Declarative) |
|---|---|---|
| 你告诉系统 | 怎么做 | 要什么 |
| 操作方式 | 一步一步下命令 | 描述最终期望状态 |
| 谁负责实现 | 你自己 | 系统 |
| 可回滚吗 | 很难,要自己记步骤 | 容易,直接改配置 |
| 可版本管理吗 | 难,步骤不好存 | 容易,配置就是代码 |
| 出错了怎么办 | 你自己排查 | 系统自动重试 |
| 幂等性 | ❌ 重复执行可能报错 | ✅ 重复执行结果一样 |
三、K8s 中的实际例子
3.1 命令式操作
# 一步一步来
kubectl run nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl scale deployment nginx --replicas=3
问题:
- 步骤多了容易忘
- 想回滚不知道回到哪一步
- 别人不知道你是怎么操作的
- 操作没有历史记录
3.2 声明式操作
写一个 YAML 文件,描述"我想要什么":
# nginx-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
spec:
replicas: 3 # 我想要3个副本
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25 # 用nginx镜像
ports:
- containerPort: 80
执行:
kubectl apply -f nginx-deploy.yaml
K8s 做了什么?
- 读取你的 YAML(期望状态)
- 查看当前集群状态
- 对比差异
- 自动创建/更新/删除资源,达到期望状态
想改副本数?
直接改 YAML 里的 replicas: 5,再 kubectl apply -f 就行。
想回滚?
直接用旧版本的 YAML 再 apply 一次。
四、核心机制:控制器循环(Controller Loop)
┌─────────────────────────────────────────┐
│ 控制器循环 │
│ │
│ 观察当前状态 → 对比期望状态 → 执行调整 │
│ ↑ ↓ │
│ └──────────────────────────┘ │
│ 无限循环 │
└─────────────────────────────────────────┘
关键特点
- 不停检查:控制器持续监控资源状态
- 自动调谐:当前状态 ≠ 期望状态 → 自动调整
- 失败重试:调整失败了?没关系,下次循环再试
- 最终一致:只要期望状态正确,最终一定能达到
为什么叫"控制平面"?
它就像一个恒温器:
- 你设定温度(期望状态)
- 恒温器不停检测当前温度
- 温度低了自动加热,温度高了自动停止
- 永远维持你设定的温度
五、声明式 API 的四大优势
1. 配置即代码(Infrastructure as Code)
你的 YAML 就是你的基础设施代码:
- 可以 Git 版本管理
- 可以 Code Review
- 可以多人协作
- 出问题了可以回滚到历史版本
2. 自愈能力
- Pod 挂了?控制器自动重建
- 节点挂了?控制器自动把 Pod 迁到别的节点
- 不用你管,系统自己维护状态
3. 幂等性
kubectl apply 可以重复执行,结果一样。
命令式操作重复执行可能报错(比如"资源已存在")。
4. 可预测
你知道最终状态是什么,不用担心中间步骤。
六、声明式的坑(也要知道)
坑1:不是所有操作都适合声明式
比如:
- 一次性的任务(执行个命令)
- 需要人工确认的操作
- 状态不确定的迁移
坑2:声明式不等于不用管
系统会自动维护,但你要知道:
- 期望状态写对了吗?
- 系统为什么达不到期望状态?
- 怎么排查问题?
坑3:声明式可能掩盖问题
比如副本数一直达不到,系统在不停地重试,但你可能没注意到。
要配合监控和告警。
七、K8s 中哪些资源是声明式的?
| 资源 | 声明式? | 说明 |
|---|---|---|
| Deployment | ✅ 是 | 最典型的声明式资源 |
| StatefulSet | ✅ 是 | 有状态应用 |
| DaemonSet | ✅ 是 | 每个节点一个Pod |
| Service | ✅ 是 | 服务发现 |
| ConfigMap / Secret | ✅ 是 | 配置管理 |
| Job | ⚠️ 半声明式 | 运行一次就完了 |
| Pod | ⚠️ 不建议 | 建议用Deployment管理 |
八、实际操作对比
场景:把副本从3个改成5个
命令式方式
kubectl scale deployment nginx --replicas=5
- 优点:快
- 缺点:不知道谁改的、为什么改、改之前是多少、出问题怎么回滚
声明式方式
# 1. 编辑 YAML 文件,把 replicas 改成 5
# 2. 预览变更
kubectl diff -f nginx-deploy.yaml
# 3. 提交
kubectl apply -f nginx-deploy.yaml
# 4. Git 提交,留痕
git add nginx-deploy.yaml
git commit -m "扩容到5个副本,应对流量高峰"
- 优点:有历史、可追溯、可回滚、可审计
- 缺点:多了几步操作
九、生产环境最佳实践
1. 全部用声明式
- 所有资源都用 YAML 管理
- 不用
kubectl run、kubectl expose这种命令式 - 临时测试可以用命令式,正式环境必须用声明式
2. YAML 文件存 Git
- 每个环境一套配置(dev/test/prod)
- 改动都有记录
- 出问题可以回滚
- 可以 Code Review
3. apply 前先 diff
# 先看会改什么
kubectl diff -f nginx-deploy.yaml
# 确认没问题再 apply
kubectl apply -f nginx-deploy.yaml
4. 不要混用
- 要么全用 YAML,要么全用命令
- 混用会导致状态混乱
- 你用命令式改了,下次 apply 可能被覆盖掉
5. 配合 GitOps
进阶玩法:
- Git 是唯一可信源
- 改 Git 自动同步到集群
- 不需要手动 kubectl apply
十、思考题答案(验证理解)
Q1:为什么 kubectl apply 可以重复执行,而 kubectl create 不行?
答:
create是命令式:“创建一个资源”,如果已经存在就报错apply是声明式:“让资源变成这个样子”,已经存在就更新,不存在就创建
Q2:如果我用命令式改了一个资源,又用声明式 apply,会发生什么?
答:
apply 会把资源状态改成 YAML 里定义的样子,你命令式改的内容会被覆盖掉。
所以:不要混用声明式和命令式!
Q3:声明式API的核心,到底是"YAML"还是"控制器循环"?
答:
核心是控制器循环。YAML 只是描述期望状态的一种方式。
真正让声明式工作的,是那个不停检查、不停调整的控制器循环。
没有控制器循环,YAML 就是个普通文本文件。
十一、一句话总结
声明式 API 的本质:你定义终点,系统找路过去。
理解了这个,你就理解了 K8s 的灵魂。

8613

被折叠的 条评论
为什么被折叠?



