Kubernetes 资源管理:声明式 vs 命令式 API 与标签实战
在 Kubernetes (K8S) 的世界里,高效、可靠地管理应用资源是运维和开发的核心任务。Kubernetes 提供了强大的 API 来与集群交互,主要分为声明式 (Declarative) API 和 命令式 (Imperative) API 两种方式。理解它们的区别并熟练运用标签 (Labels) 进行资源组织,对于构建健壮、可维护的生产环境至关重要。
本文将深入探讨这两种 API 范式,并通过 Pod 资源的增删改查及标签管理的实际案例,为你揭示 Kubernetes 资源管理的精髓。
一、 声明式 API vs 命令式 API:核心差异与选择
这两种 API 都可以实现对 Kubernetes 资源的增、删、改、查操作,但它们的设计哲学和使用场景截然不同。
相同点:
- 最终目的都是管理(增删改查)Kubernetes 集群中的资源对象(如 Pods, Deployments, Services 等)。
不同点:
-
交互方式:
- 声明式 API: 侧重于定义期望状态 (Desired State)。你需要编写资源清单(通常是 YAML 或 JSON 文件),描述你 希望 资源最终达到的状态。然后使用
kubectl apply -f <manifest_file>命令,由 Kubernetes 控制器负责将当前状态调整至期望状态。 - 命令式 API: 侧重于执行具体操作 (Action)。你直接告诉 Kubernetes 要做什么,例如
kubectl run(创建)、kubectl delete(删除)、kubectl label(打标签) 等。不需要预先编写完整的资源清单。
- 声明式 API: 侧重于定义期望状态 (Desired State)。你需要编写资源清单(通常是 YAML 或 JSON 文件),描述你 希望 资源最终达到的状态。然后使用
-
状态管理:
- 声明式 API: 资源清单是状态的“事实来源 (Source of Truth)”。易于版本控制(如 Git),便于追踪变更、回滚和协作。
kubectl apply具有幂等性,即多次执行同一个apply操作,只要资源清单不变,最终结果都将收敛到期望状态,不会产生副作用。这是 GitOps 实践的基础。 - 命令式 API: 状态变更直接发生在集群中,不易追踪历史变更。对于复杂操作的复现和自动化相对困难。命令通常不具备幂等性(例如,多次执行
kubectl create会尝试创建多个同名资源而报错,除非资源已存在)。
- 声明式 API: 资源清单是状态的“事实来源 (Source of Truth)”。易于版本控制(如 Git),便于追踪变更、回滚和协作。
-
适用场景:
- 声明式 API: 强烈推荐用于生产环境、CI/CD 流水线、需要版本控制和审计的场景。适合管理复杂的、长期存在的应用部署。
- 命令式 API: 适用于快速测试、调试、一次性任务或简单的脚本化操作。例如,快速启动一个临时 Pod 进行测试,或者在脚本中执行简单的资源修改。
总结:
| 特性 | 声明式 API (kubectl apply -f) |
命令式 API (kubectl run, create, delete, label 等) |
|---|---|---|
| 核心思想 | 定义期望状态 | 执行具体动作 |
| 输入 | 资源清单 (YAML/JSON) | 命令行参数 |
| 幂等性 | 是 (Yes) | 否 (No, 通常) |
| 状态追踪 | 易于版本控制 (Git) | 困难 |
| 生产推荐 | 是 (Yes) | 否 (No, 主要用于辅助) |
| 便捷性 | 配置较复杂,但长期维护性好 | 快速直接,适合临时任务 |
二、 实战演练:资源管理对比
让我们通过具体的 Pod 资源管理案例,直观感受两种 API 的差异。
假设我们有以下 Pod 资源清单 01-pods-xiuxian-single.yaml:
# 01-pods-xiuxian-single.yaml
# 指定api的版本号
apiVersion: v1
# 指定资源的类型
kind: Pod
# 指定元数据信息
metadata:
# 声明资源的名称
name: xiuxian-v1
# 定义资源的期望状态
spec:
# 指定Pod调度到哪个节点 (生产环境通常不建议硬编码 nodeName)
nodeName: worker232
# 指定Pod内的容器
containers:
# 指定容器的镜像
- image: registry.cn-hangzhou.aliyuncs.com/yinzhengjie-k8s/apps:v1
# 指定容器的名称
name: xiuxian
案例 1:查看资源
-
声明式 (基于文件上下文): 查看由特定文件定义的资源状态。
[root@master231 pods]# kubectl get -f 01-pods-xiuxian-single.yaml -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES xiuxian-v1 1/1 Running 0 26m 10.100.1.9 worker232 <none> <none>这里的
-f指示kubectl读取文件内容,找出该文件定义的资源 (kind: Pod,metadata.name: xiuxian-v1),然后去集群查询 这个特定资源 的当前状态。 -
命令式 (基于资源类型): 查看集群中所有指定类型的资源。
[root@master231 pods]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES xiuxian-v1 1/1 Running 0 27m 10.100.1.9 worker232 <none> <none> xiuxian-v2 2/2 Running 0 28m 10.100.1.8 worker232 <none> <none>这直接查询集群中所有的
Pod资源。
案例 2:创建资源
-
声明式: 使用
apply命令应用资源清单。[root@master231 pods]# kubectl apply -f 01-pods-xiuxian-single.yaml pod/xiuxian-v1 created [root@master231 pods]# kubectl get pods xiuxian-v1 -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES xiuxian-v1 1/1 Running 0 5s 10.100.1.10 worker232 <none> <none>如果
xiuxian-v1已存在,apply会比较清单和现有资源的状态,并进行必要的更新以达到清单定义的期望状态。 -
命令式: 使用
run或create命令直接创建。# 注意: 'kubectl run' 在较新版本中主要用于创建 Deployment, # 直接创建 Pod 更推荐使用 'kubectl create pod' 或通过 Deployment 等控制器。 # 这里我们遵循示例使用 run。 [root@master231 pods]# kubectl run xixi --image=harbor.oldboyedu.com/oldboyedu-web/xiuxian:v2 pod/xixi created [root@master231 pods]# kubectl get pods xixi -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES xixi 1/1 Running 0 10s 10.100.2.5 worker233 <none> <none>这直接在集群中创建了一个名为
xixi的 Pod。没有与之关联的资源清单文件(除非你手动保存)。
三、 Kubernetes 标签 (Labels):资源管理的利器
在 Kubernetes 中,一切皆资源。随着资源数量的增长,如何有效地组织和筛选它们变得至关重要。标签 (Labels) 就是为此而生的。
1. 什么是标签?
- 标签是附加到 Kubernetes 资源(如 Pods, Nodes, Services 等)上的键值对 (Key-Value Pairs)。
- 它们旨在用于识别资源的属性,这些属性对用户有意义,但不直接对核心系统产生语义影响。
- 标签使得我们可以灵活地组织和选择 (Select) 资源的子集。
2. 查看标签
使用 --show-labels 选项可以显示资源的标签:
[root@master231 pods]# kubectl get pods -o wide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
xiuxian-v1 1/1 Running 0 6m46s 10.100.1.10 worker232 <none> <none> <none> # 注意,之前创建的 Pod 默认可能没有标签
xixi 1/1 Running 0 5m13s 10.100.2.5 worker233 <none> <none> run=xixi # kubectl run 会自动添加 run=<pod-name> 标签
3. 管理标签
标签的管理同样可以采用声明式和命令式两种方式。
-
命令式管理标签 (临时性修改):
-
添加/更新标签:
# 为名为 xiuxian-v1 的 Pod 添加标签 [root@master231 pods]# kubectl label pods xiuxian-v1 school=oldboyedu class=linux92 address=ShaHe pod/xiuxian-v1 labeled # 通过资源清单文件指定的资源添加标签 (-f) [root@master231 pods]# kubectl label -f 01-pods-xiuxian-single.yaml role=backend pod/xiuxian-v1 labeled # 修改现有标签的值 (需要 --overwrite) [root@master231 pods]# kubectl label pods xiuxian-v1 class=Linux92 --overwrite pod/xiuxian-v1 labeled -
删除标签: 在标签键名后加上
-[root@master231 pods]# kubectl label pods xiuxian-v1 address- pod/xiuxian-v1 unlabeled -
重要提示: 通过命令式
kubectl label添加或修改的标签,如果其管理的资源(例如 Podxiuxian-v1)是由一个没有包含这些标签的资源清单(如01-pods-xiuxian-single.yaml)创建的,那么当你删除这个 Pod 并重新用kubectl apply -f 01-pods-xiuxian-single.yaml创建它时,这些命令式添加的标签将会丢失!因为声明式apply会将资源恢复到清单定义的期望状态,而原始清单中没有这些标签。# 查看标签 (包含命令式添加的标签) [root@master231 pods]# kubectl get pods xiuxian-v1 --show-labels NAME READY STATUS RESTARTS AGE LABELS xiuxian-v1 1/1 Running 0 13m class=Linux92,role=backend,school=oldboyedu # 删除 Pod [root@master231 pods]# kubectl delete -f 01-pods-xiuxian-single.yaml pod "xiuxian-v1" deleted # 重新用原始清单创建 [root@master231 pods]# kubectl apply -f 01-pods-xiuxian-single.yaml pod/xiuxian-v1 created # 查看标签 -> 命令式添加的标签已丢失! [root@master231 pods]# kubectl get pods xiuxian-v1 --show-labels NAME READY STATUS RESTARTS AGE LABELS xiuxian-v1 1/1 Running 0 2s <none>
-
-
声明式管理标签 (持久化):
-
在资源清单中定义标签: 这是推荐的方式,特别是对于需要持久化管理的标签。在
metadata字段下添加labels块。# 03-pods-labels.yaml apiVersion: v1 kind: Pod metadata: name: xiuxian-labels # 在这里定义标签 labels: school: oldboyedu class: linux92 app: myapp environment: production spec: nodeName: worker232 # 生产中通常不指定 containers: - image: harbor.oldboyedu.com/oldboyedu-web/xiuxian:v2 name: xiuxian - image: harbor.oldboyedu.com/oldboyedu-linux/alpine:3.20.2 name: alpine command: ["sleep", "3600"] # 添加命令以保持 alpine 运行 -
应用清单:
[root@master231 pods]# kubectl apply -f 03-pods-labels.yaml pod/xiuxian-labels created [root@master231 pods]# kubectl get pods xiuxian-labels --show-labels NAME READY STATUS RESTARTS AGE LABELS xiuxian-labels 2/2 Running 0 9s app=myapp,class=linux92,environment=production,school=oldboyedu -
修改或删除: 直接修改 YAML 文件中的
labels部分,然后再次执行kubectl apply -f 03-pods-labels.yaml。Kubernetes 会自动更新 Pod 的标签以匹配文件中的定义。这种方式管理的标签是持久的,与资源的生命周期绑定(只要该资源由这个清单管理)。
-
生产环境最佳实践:
- 优先使用声明式方式定义和管理标签。 将标签作为资源定义的一部分纳入版本控制。
- 命令式标签操作主要用于临时调试或快速检查。
四、 基于标签过滤资源:Selector 的威力
标签的核心价值在于选择器 (Selectors)。通过标签选择器,你可以精确地筛选出符合特定条件的资源子集,并对它们进行批量操作。
-
基本语法: 使用
-l或--selector标志。- 匹配存在某个键的标签:
-l key - 精确匹配键值对:
-l key=value - 不匹配某个键值对:
-l key!=value - 匹配多个条件 (AND):
-l key1=value1,key2=value2 - 基于集合的匹配:
-l 'key in (value1, value2)',-l 'key notin (value1, value2)'
- 匹配存在某个键的标签:
-
实战案例:
# 准备一些带标签的 Pods # (假设已创建 xiuxian-labels, xiuxian-v1 (后被打上 class=Linux92 标签), xixi) # 查看所有带有 'class' 标签的 Pods [root@master231 pods]# kubectl get pods -o wide --show-labels -l class NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS xiuxian-labels 2/2 Running 0 4m43s 10.100.1.12 worker232 <none> <none> app=myapp,class=linux92,environment=production,school=oldboyedu xiuxian-v1 1/1 Running 0 7m10s 10.100.1.11 worker232 <none> <none> class=Linux92,role=backend,school=oldboyedu # 查看 'class' 标签值为 'Linux92' 的 Pods [root@master231 pods]# kubectl get pods -o wide --show-labels -l class=Linux92 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS xiuxian-v1 1/1 Running 0 9m1s 10.100.1.11 worker232 <none> <none> class=Linux92,role=backend,school=oldboyedu # 查看 'class' 标签值不为 'Linux92' 的 Pods (注意区分大小写) [root@master231 pods]# kubectl get pods -o wide --show-labels -l class!=Linux92 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS xiuxian-labels 2/2 Running 0 7m7s 10.100.1.12 worker232 <none> <none> app=myapp,class=linux92,environment=production,school=oldboyedu xixi 1/1 Running 0 21m 10.100.2.5 worker233 <none> <none> run=xixi # 查看 'school=oldboyedu' 且 'class=linux92' 的 Pods [root@master231 pods]# kubectl get pods -o wide --show-labels -l school=oldboyedu,class=linux92 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS xiuxian-labels 2/2 Running 0 10m 10.100.1.12 worker232 <none> <none> app=myapp,class=linux92,environment=production,school=oldboyedu # 过滤节点 (Node) 资源 [root@master231 pods]# kubectl get nodes --show-labels -l kubernetes.io/hostname=worker232 NAME STATUS ROLES AGE VERSION LABELS worker232 Ready <none> 19h v1.23.17 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker232,kubernetes.io/os=linux... # 基于标签批量删除 Pods (!!! 生产环境请极度小心 !!!) [root@master231 pods]# kubectl get pods -l class --show-labels # 先确认要删除的对象 NAME READY STATUS RESTARTS AGE LABELS xiuxian-labels 2/2 Running 0 9m27s app=myapp,class=linux92,environment=production,school=oldboyedu xiuxian-v1 1/1 Running 0 11m class=Linux92,role=backend,school=oldboyedu [root@master231 pods]# kubectl delete pods -l class # 删除所有带有 'class' 标签的 Pod pod "xiuxian-labels" deleted pod "xiuxian-v1" deleted [root@master231 pods]# kubectl get pods --show-labels # 验证删除结果 NAME READY STATUS RESTARTS AGE LABELS xixi 1/1 Running 0 25m run=xixi
标签选择器是 Kubernetes 中非常核心的概念,不仅用于 kubectl 命令,更广泛应用于 Service 发现 Pod、Deployment 管理 ReplicaSet、DaemonSet 在特定节点部署 Pod 等多种场景。
五、 总结与建议
- 声明式 API 是 Kubernetes 资源管理的首选方式,尤其是在生产环境。 它提供了幂等性、版本控制和可审计性,是实现 GitOps 和自动化运维的基础。
- 命令式 API 作为有益补充,适用于快速实验、调试和简单脚本。
- 标签是 Kubernetes 中组织和筛选资源的关键机制。 务必为你的资源打上具有明确含义的标签(如
app,environment,tier,owner等)。 - 强烈建议在资源清单 (YAML) 中声明式地管理标签,以确保其持久性和一致性。
- 谨慎使用基于标签选择器的批量删除操作 (
kubectl delete -l),务必在执行前仔细确认筛选结果。
掌握声明式与命令式 API 的差异,并善用标签进行资源管理,将使你驾驭 Kubernetes 更加得心应手,为构建稳定、高效的云原生应用奠定坚实基础。
希望这篇博文对你理解和实践 Kubernetes 资源管理有所帮助!如果你有任何问题或想法,欢迎在评论区交流。
浙公网安备 33010602011771号