Kubernetes 资源管理:声明式 vs 命令式 API 与标签实战

在 Kubernetes (K8S) 的世界里,高效、可靠地管理应用资源是运维和开发的核心任务。Kubernetes 提供了强大的 API 来与集群交互,主要分为声明式 (Declarative) API命令式 (Imperative) API 两种方式。理解它们的区别并熟练运用标签 (Labels) 进行资源组织,对于构建健壮、可维护的生产环境至关重要。

本文将深入探讨这两种 API 范式,并通过 Pod 资源的增删改查及标签管理的实际案例,为你揭示 Kubernetes 资源管理的精髓。

一、 声明式 API vs 命令式 API:核心差异与选择

这两种 API 都可以实现对 Kubernetes 资源的增、删、改、查操作,但它们的设计哲学和使用场景截然不同。

相同点:

  • 最终目的都是管理(增删改查)Kubernetes 集群中的资源对象(如 Pods, Deployments, Services 等)。

不同点:

  1. 交互方式:

    • 声明式 API: 侧重于定义期望状态 (Desired State)。你需要编写资源清单(通常是 YAML 或 JSON 文件),描述你 希望 资源最终达到的状态。然后使用 kubectl apply -f <manifest_file> 命令,由 Kubernetes 控制器负责将当前状态调整至期望状态。
    • 命令式 API: 侧重于执行具体操作 (Action)。你直接告诉 Kubernetes 要做什么,例如 kubectl run (创建)、kubectl delete (删除)、kubectl label (打标签) 等。不需要预先编写完整的资源清单。
  2. 状态管理:

    • 声明式 API: 资源清单是状态的“事实来源 (Source of Truth)”。易于版本控制(如 Git),便于追踪变更、回滚和协作。kubectl apply 具有幂等性,即多次执行同一个 apply 操作,只要资源清单不变,最终结果都将收敛到期望状态,不会产生副作用。这是 GitOps 实践的基础。
    • 命令式 API: 状态变更直接发生在集群中,不易追踪历史变更。对于复杂操作的复现和自动化相对困难。命令通常不具备幂等性(例如,多次执行 kubectl create 会尝试创建多个同名资源而报错,除非资源已存在)。
  3. 适用场景:

    • 声明式 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 会比较清单和现有资源的状态,并进行必要的更新以达到清单定义的期望状态。

  • 命令式: 使用 runcreate 命令直接创建。

    # 注意: '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 添加或修改的标签,如果其管理的资源(例如 Pod xiuxian-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 资源管理有所帮助!如果你有任何问题或想法,欢迎在评论区交流。

posted on 2025-04-21 17:01  Leo-Yide  阅读(95)  评论(0)    收藏  举报