3-1-kubernetes资源对象介绍

熊 0 阅读 容器

1. 资源对象基础

Kubernetes集群将所有节点上的资源都整合到一个大的虚拟资源池里 , 以代替一个个单独的服务器。如果把集群类比为一台传统的服务器 , 那么Kubernetes( Master)就好比是操作系统内核 , 其主要职责在于抽象资源并调度任务 , 而Pod资源对象就是那些运行于用户空间中的进程。

Kuberentes抽象出多种概念来描述应用程序及其周边组件 , 如Pod、Deployment、Service等 , 这些概念被统称为资源。而对象则是“资源”的实例 , 如具体的某个Pod、具体的某个Service。在日常语境中 , 我们通常不会特意区分资源和对象 , 可以使用”资源“、“资源对象”来泛指某类资源的实例 , 也即是对象。

类别

名称

资源对象

Pod、ReplicaSet、ReplicationController、Deployment、StatefulSet、DaemonSet、Job、CronJob、HorizontalPodAutoscaling、Node、Namespace、Service、Ingress、Label、CustomResourceDefinition

存储对象

Volume、PersistentVolume、Secret、ConfigMap

策略对象

SecurityContext、ResourceQuota、LimitRange

身份对象

ServiceAccount、Role、ClusterRole

20201225110611268
  • 全局型资源

    Kubernetes还存在一些用于定义集群自身配置信息的资源类型, 它们不属于任何名称空间且仅应该由集群管理员操作。

    • Namespace(命名空间)

      很多地方都有 Namespace的概念 , 如 Linux 中的 Namespace , 容器就使用了该技术来实现对于系统资源的访问隔离。Kubernetes集群中Namespace也是用于隔离 , 它提供了一种对集群中的对象进行分组和隔离的机制。使用Namespace可以将不同应用程序或不同团队的资源进行隔离 , 从而防止资源冲突和应用程序之间的相互影响。

    • Node

      Kubernetes并不能直接管理其工作节点, 但它会把由管理 员添加进来的任何形式(物理机或虚拟机等)的工作节点映射为一个 Node资源对象, 因而节点名称(标识符)在集群中必须唯一。

    • Role

      角色, 隶属于名称空间, 代表名称空间级别由规则组成的 权限集合, 可被RoleBinding引用。

    • ClusterRole

      集群角色, 隶属于集群而非名称空间, 代表集群 级别的、由规则组成的权限集合, 可被RoleBinding和 ClusterRoleBinding引用。

    • RoleBinding

      用于将Role中的许可权限绑定在一个或一组用户 之上, 从而完成用户授权, 它隶属于且仅能作用于名称空间级别。

    • ClusterRoleBinding

      将ClusterRole中定义的许可权限绑定在 一个或一组用户之上, 通过引用全局名称空间中的ClusterRole将集群 级别的权限授予指定用户。

  • 工作负载型资源

    Pod用于承载容器化应用, 代表着Kubernetes之上工作负载的表现 形式。它负责运行容器, 并为容器解决环境性的依赖, 例如向容器注入临时或持久化的存储空间、配置信息或密钥数据等。而诸如滚动更新、扩容和缩容一类的编排任务则由“控制器”对象负责, 专用于Pod 编排任务的控制器也可统称为Pod控制器。

    应用程序分为无状态和有状态两种类型, 无状态应用中的每个Pod 实例均可被其他同类实例所取代, 但有状态应用的每个Pod实例均有其独特性, 必须单独标识和管理, 因而它们分别由两种不同类型的Pod控制器进行管理。例如, ReplicationController、ReplicaSet和 Deployment负责管理无状态应用, StatefulSet则用于管控有状态类应用。还有些应用较为独特, 有些需要在集群中的每个节点上运行单个 Pod资源, 负责收集日志或运行系统服务等任务, 该类编排操作由 DaemonSet控制器对象进行, 而需要在正常完成后退出故无须始终处于运行状态任务的编排工作则隶属Job控制器对象。CronJob控制器对象 还能为Job型的任务提供定期执行机制。

    • Pod

      Pod 是 Kubernetes 中最小的部署单元 , 可以包含一个或多个容器。每个 Pod 都有一个唯一的 IP 地址 , 并且内部容器可以共享网络栈、存储等。Pod 提供了一种轻量级的方式来部署容器 , 可以实现高效地资源利用。

    • ReplicationController:

      用于确保每个Pod副本在任一时刻均能 满足目标数量, 即它用于保证每个容器或容器组总是运行并可访问 ; 它是上一代的无状态Pod应用控制器, 建议读者使用新型控制器 Deployment和ReplicaSet来取代它。

    • ReplicaSet:

      新一代ReplicationController, 它与 ReplicationController唯一不同之处在于支持的标签选择器不同, ReplicationController只支持“等值选择器”, 而ReplicaSet还支持 基于集合的选择器

    • Deployment

      Deployment 用于管理 Pod 的部署和更新的控制器 , 可以通过指定副本数和容器镜像来定义 Pod 模板。Deployment 可以自动检测并处理 Pod 的故障 , 保证应用程序的高可用性 , 通常用于部署无状态的服务。

    • StatefulSet

      功能与Deployment类似 , 但适用于部署有状态的应用服务。StatefulSet能够为每个Pod创建一个独特的标识 , 并会保证Pod之间的启动顺序。通常用于部署数据库等应用服务。

    • DaemonSet

      用于确保每个节点都运行了某Pod的一个副本, 包括 后来新增的节点;而节点移除将导致Pod回收;DaemonSet常用于运行 各类系统级守护进程, 例如kube-proxy和Flannel网络插件, 以及日志收集和临近系统的Agent应用, 例如fluentd、Logstash、Prometheus 的Node Exporter等。

    • Job

      用于管理运行完成后即可终止的应用, 例如批处理作业任 务;Job创建一个或多个Pod, 并确保其符合目标数量, 直到应用完成 而终止。

  • 负载均衡与路由资源

    • Service

      Service 是一种抽象的对象 , 用于暴露 Pod 的网络服务。Service 可以将一组 Pod 组合在一起 , 并使用一个唯一的 DNS 名称和虚拟 IP 地址 , 提供负载均衡服务。Service 还可以定义访问控制策略 , 用于提高应用程序的可用性和安全性。

      service是Kubernetes标准的资源类型之一, 用于为工作负载实例 提供固定的访问入口及负载均衡服务, 它把每个可用后端实例定义为 Endpoint资源对象, 通过IP地址和端口等属性映射至Pod实例或相应的 服务端点。

    • Ingress

      Ingress 是 Kubernetes 中用于管理 HTTP 和 HTTPS 流量的对象。它允许外部流量进入集群 , 并将流量路由到不同的 Service 上。工作负载提供7层(HTTP/HTTPS)代理及 负载均衡功能

  • 配置型资源

    • ConfigMap

      ConfigMaps 用于在 Kubernetes 中存储配置数据 , 它们可以用于存储键值对、文件或目录。ConfigMaps 作为 Kubernetes 对象创建 , 并可在容器中作为卷或环境变量进行挂载。ConfigMaps 的好处在于可以将配置数据与应用程序代码分离 , 使得配置数据更易于管理和更新。

    • Secret

      Secrets 类似于 ConfigMaps , 但用于存储敏感信息 , 例如密码、API 密钥和证书。与 ConfigMaps 一样 , Secrets 可以在容器中作为卷或环境变量进行挂载。Secrets 的数据是加密 , 并且只有经过授权的用户访问时才会解密。

  • 存储型资源

    Docker容器分层联合挂载的方式决定了其系统文件无法在容器内部存储持久化数据, 因而容器引擎引入外部存储卷的方式来解决此类 问题, 相应地, Kubernetes支持在Pod级别附加Volume资源对象为容器 添加可用的外部存储。Kubernetes支持众多类型的存储设备或存储系 统, 例如GlusterFS、Ceph RBD和Flocker等, 还可通过FlexVolume及 CSI(Container Storage Interface)存储接口扩展支持更多类型的 存储系统。

    另外, 基于镜像运行容器应用时, 其配置信息在镜像制作时以硬 编码的方式置入, 所以很难为不同的环境定制所需的配置。Docker使 用环境变量等作为解决方案, 但需要在容器启动时将配置作为变量值 传入, 且无法在运行时修改。Kubernetes的ConfigMap资源能够以环境 变量或存储卷的方式接入Pod资源的容器中, 并可被多个同类的Pod共享引用, 从而做到“一次修改, 多处生效”。不过, 这种方式不适用 于存储敏感数据, 例如证书、私钥和密码等, 那是另一个资源类型 Secret的功能

    • PersistentVolumes(PV)

      PV 是集群中独立的存储Volume , 可以是物理存储设备(如 : 磁盘)、网络存储设备(如 , Nas)或者是分布式存储 系统( 如GlusterFS、Ceph等) 。

    • PersistentVolumeClaims( PVC)

      PVC 是用于申请PV资源的对象。创建 PVC 时会指定存储的大小和资源 , Kubernetes 将查找与请求匹配的可用 PV 并将它们绑定在一起。然后用户可以使用 PVC 访问存储。

  • 任务型资源

    • Job

      短暂运行的任务 , 一旦完成就会终止 , 常用于批处理任务、数据处理等场景。

    • CronJob

      基于时间的作业调度 , 类似于Linux中的cron , 可以按照预定时间或周期执行作业。

  • 元数据型资源

    此类资源对象用于为集群内部的其他资源对象配置其行为或特性, 例如HPA资源对象可用于控制自动伸缩工作负载类型资源对象的规 模, Pod模板提供了创建Pod对象的预制模板, 而LimitRange可为名称空间内的Pod应用设置其CPU和内存等系统级资源的数量限制等。

注: 一个应用通常需要多个资源的支撑, 例如用Deployment资源编排 应用实例(Pod)、用ConfigMap和Secret资源保存应用配置、用Service或Ingress资源暴露服务、用Volume资源提供持久化存储等。

Kubernetes中资源对象一般通过YAML文件定义, 也是为了后续方便资源对象的管理。Kubernetes中通过声明式API创建资源对象, 通过控制器(Controller)维持资源对象声明时的期望状态。

YAML文件有5部分, 每部分的主要作用概括如下, 在Kubernetes中YAML文件编写也有提及。

  1. apiVersion : 创建该资源对象使用的Kubernetes API的版本。

  2. kind : 想要创建的资源对象的类型, 如Pod、ReplicationController、Service、Namespace等。

  3. metadata : 在当前名称空间, 定义识别资源对象的唯一标识, 包括name名称、可选的namespace名称空间等字段。

  4. spec : 定义对资源对象所需状态的完整描述, 包括replicas副本数量、Pod选择器、Pod标签、容器名称、镜像、端口映射等字段。

  5. status : 代表资源对象当前的状态(一般由Kubernetes自动维护)。

2. 资源对象管理

Kubernetes API是管理各种资源对象的唯一入口 , 它提供了一个 RESTful风格的CRUD(Create、Read、Update和Delete)接口用于查询 和修改集群状态 , 并将结果存储在集群状态存储系统etcd中。事实 上 , API Server也是用于更新etcd中资源对象状态的唯一途径 , Kubernetes的其他所有组件和客户端都要通过它完成查询或修改操作。从这个角度来讲 , 它们都算得上是API Server的 客户端

任何RESTful风格API的核心概念都是“资源” , 资源可以根据其特性分组 , 每个组是同一类型资源的集合 , 即仅包含一种类型的资 源 , 并且各资源间不存在顺序的概念 , 集合本身也是资源。对应于 Kubernetes中 , Pod、Deployment和Service等都是所谓的资源类型 , 它们由相应类型的对象集合而成

对于用户而言 , 直接操作API无疑是不方便的 , 因此 , Kubernetes也为我们提供了kubectl命令行工具 , 可以让我们使用命令的方式调用API。

当需要创建资源对象时 , kubectl可以通过配置列表来声明这些 “对象”。配置列表可以被看作是对象“属性”的描述文件 , 格式可以是 “JSON” 或 “YAML” , 常用的是YAML格式。

以Pod为例 , 以下是一个简单的pod.yaml文件模板。

apiVersion: v1
kind: Pod
metadata:
    name: myapp-pod
    labels:
      app: myapp
spec:
    containers:
    - name: myapp-container
      image: busybox
      command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']

可以看到该文件内容是由几个模块组成 , 分别是apiVersion、kind、metadata和spec , 它们的功能定义如下:

  • apiVersion: 这里指定创建该对象所使用的Kubernetes API版本 , 目前Kubernetes大部分常见的核心资源对象都归属于v1这个核心API。

  • kind: 指定对象所属的资源类型 , 如Pod、Service、Deployment等。

  • metadata: 用于配置对象的元数据信息 , 如名称、标签、注释、namespace等 , 其中标签是K8s中一个具有特色的概念 ,

  • spec: 用于描述对象的规格 , 可以看作是对象期望的状态。如本例中的Pod对象包含了一个名称为myapp-pod的容器 , 该容器的镜像为busybox , 并带有启动命令。那么 , 当执行这个配置列表时 , kubernetes将按照这个规格去创建Pod。

除了以上四个部分 , 对象还会有一个status字段 , 它用于描述对象的实际状态 , 这部分的内容由Kubernetes系统负责维护和更新。在任何时段 , Kubernetes会努力管理着对象的实际状态与期望状态相匹配。

当完成配置列表后 , 接下来就是将其在集群中声明创建。

如下:

$ kubectl create -f pod.yaml
pod/myapp-pod created

现在 , 我们查看资源 , 可以对象实例已经起来了。

$ kubectl  get pod
NAME        READY   STATUS    RESTARTS   AGE
myapp-pod   1/1     Running   0          87s

2.1 资源及其在API中的组织形式

资源对象代表了系统上的持久类实体 , 而Kubernetes用这些持久实体来表达集群的状态, 包括容器化的应用程序正运行于哪些节点 , 每个应用程序有哪些资源可用 , 以及每个应用程序各自的行为策略, 例如重启、升级及容错策略等。一个对象可能会由多个资源组合而 成, 用户可对这些资源执行增、删、改、查等管理操作。Kubernetes 通常使用标准的RESTful术语来描述API概念。

  1. 资源类型是指在URL中使用的名称, 例如pods、namespaces和 services等, 其URL格式为GROUP/VERSION/RESOURCE, 例如 apps/v1/deployments。

  2. 每个资源类型都有一个对应的JSON表示格式, 称为一个“种类”;客户端创建对象时, 一般需要以JSON规范提交对象的配置信息。

  3. Kind代表资源对象所属的类型, 例如Namespace、 Deployment、Service及Pod等, 而这些资源类型又大体可以分为3个类 别。

    • 对象类 : 对象表示Kubernetes系统上的持久化实体, 一个对象可能包含多个资源, 客户端可以对其执行多种操作 ; Namespace、 Deployment、Service及Pod等都属于这个类别。

    • 列表类 : 通常是指同一类型资源的集合, 例如PodLists和 NodeLists等。

    • 简单类 : 常用于在对象上执行某种特殊操作, 或管理非持久化的 实体, 例如/binding或/status等。

Kubernetes绝大多数的API资源都属于“对象”型类别, 代表集群中某个抽象组件的实例。有一小部分的API资源类型为“虚拟”类型, 用于表达一类“操作”。所有的对象型资源都拥有一个独有的名称标识以完成幂等的创建及获取操作, 但虚拟型资源无须获取或不依赖于幂等性时也可以不使用专用标识符。

有些资源类型的作用域为集群级别, 操作权限归属于集群管理员, 例如Namespace和PersistentVolume等, 但绝大多数资源类型都隶 属名称空间级别, 可由用户使用, 例如Pod、Deployment和Service 等。名称空间级别资源的URL路径中含有其所属空间的名称, 当这些资源对象在名称空间被删除时, 其URL路径中的名称也会被一并删除, 并 且访问这些资源对象也将受控于其所属的名称空间级别的授权审查。

Kubernetes把API分割为多个逻辑组合以便于扩展和管理, 每个组合称为一个API群组, 支持单独启用或禁用, 并能够再次分解。API Server支持为不同群组使用不同的版本, 允许各组以不同的速度演进, 而且支持同一群组同时存在不同的版本, 例如autoscaling/v1、 autoscaling/v2beta2和autoscaling/v2beta1等, 因此能够在不同的群组中定义同名的资源类型, 从而能在稳定版本的群组及新的实验群 组中同时存在不同特性的同一个资源类型。在当前集群中, API Server所支持的API群组及相关版本信息可通过kubectl api-versions 命令获取。

root@kubeadm-master1:~# kubectl api-versions
admissionregistration.k8s.io/v1
apiextensions.k8s.io/v1
apiregistration.k8s.io/v1
apps/v1
authentication.k8s.io/v1
authorization.k8s.io/v1
autoscaling/v1
autoscaling/v2
batch/v1
certificates.k8s.io/v1
configuration.konghq.com/v1
configuration.konghq.com/v1alpha1
configuration.konghq.com/v1beta1
coordination.k8s.io/v1
discovery.k8s.io/v1
events.k8s.io/v1
flowcontrol.apiserver.k8s.io/v1
flowcontrol.apiserver.k8s.io/v1beta3
networking.k8s.io/v1
node.k8s.io/v1
policy/v1
rbac.authorization.k8s.io/v1
scheduling.k8s.io/v1
storage.k8s.io/v1
v1

提示: 随着API的发展, Kubernetes会定期进行API重组或升级, 并弃用过期的版本, 因而不同版本的Kubernetes所支持的API群组以及资源 类型的归属可能会有所不同。

API弃用策略请参考文档 : Deprecated API Migration Guide | Kubernetes

Kubernetes将RESTful风格的API以层级结构组织在一起, 每个API 群组表现为一个以/apis为根路径的RESTful路径, 例 如/apis/apps/v1, 不过名称为core的核心群组有一个专用的简化路 径 : /api/v1。目前, 常用的API群组可归为如下两类。

  1. 核心群组 : RESTful路径为/api/v1, 在资源的配置信息 apiVersion字段中引用时可以不指定路径, 而仅给出版本, 例如 apiVersion: v1, 如上面的命令kubectl api-versions结果中最后一 个群组所示。

  2. 命名的群组: RESTful路径为/apis/$GROUP_NAME/$VERSION, 例如/apis/apps/v1, 在apiVersion字段中引用它时需要移除/apis前 缀, 例如apiVersion: apps/v1等。

名称空间级别的每一个资源类型在API的URL路径表示都可简单抽象为形如 /apis/<group>/<version>/namespaces/<namespace>/<kind plural> 的路径。例如default名称空间中, Deployment类型的路径为/apis/apps/v1/namespaces/default/deployments, 通过此路径可 获取到default名称空间中所有Deployment对象的列表。

root@kubeadm-master1:~# kubectl get --raw /apis/apps/v1/namespaces/default/deployments | jq .
{
  "kind": "DeploymentList",
  "apiVersion": "apps/v1",
  "metadata": {
    "resourceVersion": "591845"
  },
  "items": []
}

另外, Kubernetes还支持由用户自定义资源类型, 目前常用的方式有3种 : 一是修改Kubernetes源代码自定义类型 ; 二是创建一个自定 义的API Server, 并将其聚合至集群中 ; 三是使用CRD(Custom Resource Definition, 自定义资源), 它们都可用于API群组扩展。

2.2 访问Kubernetes RESTful API

为安全起见, kubeadm部署的API Server通常仅支持双向SSL/TLS 认证的HTTPS通信, 客户端需要事先在服务器端认证才能与之建立通信。在临时测试的场景中, 用户也可以借助kubectl proxy命令在本地主机上为API Server启动一个代理网关, 从而在本地支持HTTP协议, 即使用curl命令向该代理发起请求便能模拟资源对象的请求和响应过程。

image-20240507023733932

例如, 下面的命令中, kubectl命令在本地回环接口上的8080端口 启动了API Server的一个代理网关

root@kubeadm-master1:~#  curl localhost:8080/api/v1/namespaces/
{
  "kind": "NamespaceList",
  "apiVersion": "v1",
  "metadata": {
    "resourceVersion": "592801"
  },
....
​

我们也可以使用JSON的命令行处理器的jq命令对响应的JSON数据 流进行内容过滤, 例如下面的命令仅显示相关NamespaceList对象中的 各成员对象的名称 :

root@kubeadm-master1:~# curl -s localhost:8080/api/v1/namespaces/ | jq .items[].metadata.name 
"default"
"kube-flannel"
"kube-node-lease"
"kube-public"
"kube-system"
"kubernetes-dashboard"
​

给出特定的Namespace资源对象的名称便能直接获取到相应的资源 信息, 以kube-system名称空间为例:

root@kubeadm-master1:~# curl -s localhost:8080/api/v1/namespaces/kube-system 
{
  "kind": "Namespace",
  "apiVersion": "v1",
  "metadata": {
    "name": "kube-system",
    "uid": "c9f910ee-97d1-4b34-80f5-721e958e4b52",
    "resourceVersion": "5",
    "creationTimestamp": "2024-05-03T15:35:18Z",
    "labels": {
      "kubernetes.io/metadata.name": "kube-system"
    },
    "managedFields": [
      {
        "manager": "kube-apiserver",
        "operation": "Update",
        "apiVersion": "v1",
        "time": "2024-05-03T15:35:18Z",
        "fieldsType": "FieldsV1",
        "fieldsV1": {
          "f:metadata": {
            "f:labels": {
              ".": {},
              "f:kubernetes.io/metadata.name": {}
            }
          }
        }
      }
    ]
  },
  "spec": {
    "finalizers": [
      "kubernetes"
    ]
  },
  "status": {
    "phase": "Active"
  }
}

上述命令响应的结果中展现了Kubernetes大多数资源对象的资源配置格式, 它是一个JSON序列化的数据结构, 具有kind、 apiVersion、metadata、spec和status这5个一级字段, 各字段的意义 和功能将在下一节中重点介绍

3. 对象类资源配置规范

创建Kubernetes对象时, 必须提供描述该对象期望状态的规范以 及相关的基本信息, 例如对象名称、标签和注解等元数据, 并以JSON 格式提交给API Server。在大多数情况下, 用户以YAML格式的配置清单定义对象的相关信息, 并由kubectl在发起API请求时将其自动转换 为JSON格式。

API Server接收和返回的所有JSON对象都遵循同一个模式, 即它们都具有kind和apiVersion字段, 分别用于标识对象所属的资源类 型、API群组及相关的版本, 可合称为类型元数据(TypeMeta)。同时, 大多数的对象或列表类型的资源还会有metadata、spec和status 这3个嵌套型的字段。

  • metadata字段为资源提供元数据信息, 例如 名称、隶属的名称空间和标签等, 因而也称为对象元数据 (ObjectMeta) ;

  • spec字段则是由用户负责声明对象期望状态的字段, 不同资源类型的期望状态描述方式各不相同, 因此其嵌套支持的 字段也不尽相同 ;

  • status字段则记录活动对象的当前状态信息, 也称为观察状态, 它由Kubernetes系统自行维护, 对用户来说为只读字段, 不需要在配置清单中提供, 而是在查询集群中的对象时由API Server在响应中返回。

每个资源类型代表一种特定格式的数据结构, 它接收并返回该格式的对象数据, 同时, 一个对象也可嵌套多个独立的“小”对象, 并 支持每个小对象的单独管理操作。例如对Pod类型的资源来说, 用户可 创建、更新或删除Pod对象, 而每个Pod对象的metadata、spec和 status字段的值又是各自独立的对象型数据, 所以它们可被单独操作。需要注意的是, status对象由Kubernetes系统单独进行自动更新, 且不支持用户手动操作。

3.1. 定义资源对象

相较于使用curl命令直接向API发起请求来说, kubectl命令或其他UI工具(例如Dashboard)更为便捷和高效。例如, kubectl get TYPE/NAME -o yaml命令能获取到任何一个对象的YAML格式的配置清单 , 也可使用kubectl get TYPE/NAME -o json命令获取JSON格式的配置清单。例如, 下面的命令能够打印出Namespace对象kube-system的详细数据:

root@kubeadm-master1:~# kubectl get namespace kube-system -o yaml
apiVersion: v1
kind: Namespace
metadata:
  creationTimestamp: "2024-05-03T15:35:18Z"
  labels:
    kubernetes.io/metadata.name: kube-system
  name: kube-system
  resourceVersion: "5"
  uid: c9f910ee-97d1-4b34-80f5-721e958e4b52
spec:
  finalizers:
  - kubernetes
status:
  phase: Active

除了极少数的资源外, Kubernetes系统上的绝大多数资源都是由用户创建。用户只需要定义出声明式的对象配置清单, 而后由相应的控制器通过控制循环来确保对象的运行状态与用户定义的期望状态无 限接近或等同。承载对象定义的配置文件称为配置清单 ( manifest),虽然可直接以JSON格式描述对象, 但更常见的还是 以.yaml或.yml结尾的YAML文件。除了status字段, 该类文件的格式类似kubectl get命令获取到的YAML或JSON形式的输出结果。例如, 下面 就是一个创建Namespace资源时提供的资源配置清单示例, 它仅提供了 几个必要的字段。

apiVersion: v1
kind: Namespace
metadata:
  name: env
spec:
  finalizers:
  - kubernetes

把上面配置清单中的内容保存到文件中 , 使用kubectl create -f /PATH/TO/FILE命令即可将其提交至集群。创建完成后打印其YAML或 JSON格式的结果时可以看到Kubernetes自动补全了未定义的字段 , 并 提供了相应的数据 , 这部分功能由第9章讲到的准入控制器实现。事实上 , Kubernetes的大多数资源都能够以相同的方式创建和查看 , 而且 它们几乎都遵循类似的组织结构。

root@kubeadm-master1:~# kubectl get deployment demoapp -o yaml -n dev
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  creationTimestamp: "2024-05-08T09:25:33Z"
  generation: 1
  labels:
    app: demoapp
  name: demoapp
  namespace: dev
  resourceVersion: "149488"
  uid: 1ba207cd-8358-4094-8e3e-5c3001826663
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
.....

为了节省篇幅 , 上面的输出结果中省去了大部分的内容 , 仅保留 了其主体结构。命令结果显示出 , 它同样遵循Kubernetes API标准的 资源组织格式 , 由apiVersion、kind、metadata、spec和status这5个 核心字段组成。事实上 , 对大多数资源来说 , apiVersion 、kind 和 metadata字段的功能基本相同 , spec则是资源的期望状态 , 而资源之所以存在不同类型 , 是因为它们在该字段内的嵌套属性存在显著差别。

3.2. 对象元数据

metadata字段内嵌多个字段以定义对象的元数据 , 这些字段大体可分为必要字段和可选字段两类。

名称空间级别的资源的必选字段如下

  • namespace : 当前对象隶属的名称空间 , 默认值为default。

  • name : 当前对象的名称标识 , 同一名称空间下同一类型的对象名称必须唯一。

  • uid : 当前对象的唯一标识符 , 其唯一性仅发生在特定的时间段 和名称空间中 , 主要用于区别拥有同样名字的“已删除”和“重新创 建”的同一个名称的对象。

可选字段通常是指那些或由Kubernetes系统自行维护和设置 , 或 存在默认值 , 或本身允许使用空值等一类的字段。常用的可选字段有 如下几个。

  • labels : 该资源对象的标签 , 键值型数据 , 常被用作标签选择器 的挑选条件。

  • annotations : 非标识目的的元数据 , 键值格式 , 但不可作为标签选择器的挑选条件 , 其意义或解释方式一般由客户端自行定义。

  • resourceVersion : 对象的内部版本标识符 , 用于让客户端确定 对象变动与否。

  • generation: 用于标识当前对象目标状态的代别。

  • creationTimestamp: 当前对象创建时的时间戳。

  • deletionTimestamp: 当前对象删除时的时间戳。

配置清单中未在metadata字段中明确定义的可选嵌套字段 , 会由 一系列的finalizer组件予以自动填充。而当用户需要强制对资源创建 的目标资源对象进行校验或者修改时 , 则要使用initializer组件完成 , 例如 , 为每个待创建的Pod对象添加一个Sidecar容器。另外 , 不同的资源类型也会存在一些其专有的嵌套字段 , 例如ConfigMap资源还支持使用clusterName等

3.3. 资源的期望状态

Kubernetes API中定义的大部分资源都有spec和status两个字段 : 前一个是声明式API风格的期望状态 , 由用户负责定义而由系统读 取 ; 后一个是系统写入的实际观测到的状态 , 可被用户读取 , 以了解 API对象的实际状况。控制器是Kubernetes的核心组件之一 , 负责将用户通过spec字段声明的API对象状态“真实”反映到集群之上 , 尤其是创建和更新操作 , 并持续确保系统观测到并写入status的实际状态符合用户期望的状态。

例如 , Deployment是负责编排无状态应用的声明式控制器 , 当创建一个具体的Deployment对象时 , 需要在其spec字段中指定期望运行 的Pod副本数量、匹配Pod对象的标签选择器以及创建Pod的模板等。 Deployment控制器读取该对象的spec字段中的定义 , 过滤出符合标签选择器的所有Pod对象 , 并对比该类Pod对象的总数与用户期望的副本数量 , 进行“多退少补”操作 , 多出的Pod会被删除 , 少的将根据Pod 模板进行创建 , 而后将结果保存于Deployment对象的status字段中。 随后 , Deployment控制器在其控制循环中持续监控status字段与spec 的差异 , 任何不同都将由控制器启动相应操作进行对齐。

然而 , 出于不同目的分别设计的API资源功能不尽相同 , 它们的期 望状态也会有所不同 , 因而不同资源类型的spec字段的定义格式也必然各不相同 , 具体使用时需要参照Kubernetes API参考手册进行了 解 , 核心资源对象的常用配置字段将会在本书后面章节进行讲解。

3.4. 获取资源配置清单格式文档

在定义资源配置清单时 , 尽管apiVersion、kind和metadata有据可循 , 但spec字段对不同的资源来说千差万别 , 用户难以事先全部掌握 , 这就不得不参考Kubernetes API文档了解各字段的详细使用说明。Kubernetes的设计和开发人员显然也考虑到了这点 , 他们直接在系统中内置了这些文档 , 并提供了具体的打印命令kubectl explain , 该命令将根据给出的对象类型或相应的嵌套字段来显示相关下一级文档。例如 , 下面的命令能够打印出Pod资源的一级字段及其使用格式。

root@kubeadm-master1:~# kubectl explain pods
image-20240509144210980

每个对象的spec字段的文档通常会包含KIND、VERSION、 RESOURCE、DESCRIPTION和FIELDS几个小节 , 其中FIELDS一节中给出了 可嵌套使用的字段、数据类型及功能描述。各字段的数据类型遵循 JSON规范 , 包括数值型、字符串、布尔型、数组或列表、对象和空值 等 , 其中数值型还可分为整型、分数(Fraction)和指数 (Exponent)3种。其中对象类型的字段还可以嵌套其他字段 , 且每个对象的文档也支持单独打印。例如 , 查看Pod资源内嵌的Spec对象支持 嵌套使用的二级字段 , 可使用类似如下命令。

root@kubeadm-master1:~# kubectl explain pods.spec
image-20240509144243660

上面命令结果显示 , containers字段的数据类型是对象列表 ([]Object) , 也是一个必选字段(带有-required-标记)。任何值为对象类型数据的字段都会嵌套一到多个下一级字段 , 例如Pod对象中的每个容器也是对象型数据 , 它同样包含嵌套字段 , 但Kubernetes不支持单独创建容器对象 , 而是容器对象必须包含在Pod对象的上下文 中。容器的配置文档可通过三级字段获取 , 命令及其结果示例如下:

root@kubeadm-master1:~# kubectl explain pods.spec.containers
KIND:       Pod
VERSION:    v1

FIELD: containers <[]Container>

DESCRIPTION:
    List of containers belonging to the pod. Containers cannot currently be
    added or removed. There must be at least one container in a Pod. Cannot be
    updated.
    A single application container that you want to run within a pod.
    
FIELDS:
  args	<[]string>
    Arguments to the entrypoint. The container image's CMD is used if this is
    not provided. Variable references $(VAR_NAME) are expanded using the
    container's environment. If a variable cannot be resolved, the reference in
    the input string will be unchanged. Double $$ are reduced to a single $,
    which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will
    produce the string literal "$(VAR_NAME)". Escaped references will never be
    expanded, regardless of whether the variable exists or not. Cannot be
    updated. More info:
    https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell

.....

内置文档大大降低了用户手动创建资源配置清单的难度 , explain 也的确是用户的常用命令之一。更便捷的配置方式 , 是以同类型的现有活动对象的清单为模板生成目标资源的配置文件。以活动对象生成配置模板的命令格式为kubectl get TYPE NAME -o yaml

3.5. 资源对象管理方式

Kubernetes的API Server遵循声明式编程范式而设计 , 侧重于构建程序逻辑而无须描述其实现流程 , 用户只需要设定期望的状态 , 系统即能依赖相应的控制器自行确定需要执行的操作 , 以确保达到用户期望的状态。事实上 , 声明式API和控制器模式也是Kubernetes的编排等功能赖以实现的根本。

另一种对应的类型称为命令式编程的范式 , 代码侧重于通过创建 一种告诉计算机如何执行操作的算法或步骤来更改程序状态的语句 , 它与硬件的工作方式密切相关 , 通常代码将使用条件语句、循环和类继承等控制结构。为了便于用户使用 , kubectl命令也支持命令式的编排功能 , 用户直接通过命令及其选项就能完成对象管理操作 , 前面用到的run、expose、delete和get等命令都属于此类 , 它们在执行时需要用户告诉系统要做的事情的具体步骤。例如 , 使用run命令创建一个 有着3个Pod对象副本的Deployment对象或通过delete命令删除一个名为demoapp的Service对象等。

kubectl的命令也可大体分为3类: 命令式命令(imperative command)、命令式对象配置(imperative object configuration) 和声明式对象配置(declarative object configuration)。

  1. 命令式命令

    命令式命令是指将实施于目标对象的操作以选项及选项参数的方式提供给kubectl命令 , 并直接操作Kubernetes集群中的活动对象 , 因而无法提供之前配置的历史记录。这是在集群中运行“一次性”任务 的最简单方法。常用的命令式命令如下。

    • 创建对象 : run、expose、autoscale和create <objecttype> [<subtype>] <instancename>。

    • 更新对象 : scale、annotate、label、set 、edit和 patch。

    • 删除对象 : delete <type>/<name>。

    • 查看对象: get、describe和logs。

    命令式命令简单易用 , 但无法实现代码复用、修改复审及审计日志等功能。配置跟踪和配置复用的功能要依赖由配置清单承载的“对 象配置” , 如此用户才能够像管理代码文件一样来管理这类配置清单。写好配置清单并非易事 , 需要用户深入学习Kubernetes API , 理解并掌握常用对象的常用字段的使用方法 , 这也是熟练使用 Kubernetes系统的基础。

    配置清单本质上是一个JSON或YAML格式的文本文件 , 由资源对象 的配置信息组成 , 支持使用Git等进行版本控制。而用户能够以资源清单为基础 , 在Kubernetes系统上选择以命令式或声明式进行资源对象管理 , 如图所示。

    1584613265053-581d221b-a008-49b2-9f16-c49f1710b8ed
  2. 命令式对象配置

    命令式对象配置管理方式包括create、delete、get和replace等 命令。与命令式命令不同 , 它通过资源配置清单读取要管理的目标资源对象 , 通用格式为kubectl create|delete| replace|get -f , 其中的filename和url分别是指以本地文件路径或 URL来指定配置清单文件。命令式对象配置的管理操作直接作用于活动对象 , 因而即使修改配置清单中极小的一部分内容 , 在使用replace命令进行对象更新时也将会导致整个对象被完全替换。所以 , 混合使用 命令式命令进行清单文件带外修改时 , 必然导致用户丢失活动对象的当前状态。

  3. 声明式对象配置

    声明式对象配置并不直接指明要进行的对象管理操作 , 而是提供 配置清单文件给Kubernetes系统 , 并委托系统来跟踪活动对象的状态 变动。资源对象的创建、删除及修改操作全部通过唯一的命令kubectl apply完成 , 且每次操作时 , 提供给命令的配置信息都将保存在对象的注解信息(kubectl.kubernetes.io/last-applied-configuration) 中 , 它通过对比检查活动对象的当前状态、注解中的配置信息及资源 清单中的配置信息进行变更合并 , 从而实现仅修改变动字段的高级补丁机制

    声明式对象配置支持针对目录进行操作 , 通过在目录中存储多个对象配置文件 , 然后由apply命令递归地创建、更新或删除这些对象 , 它保留对活动对象所做的更改操作 , 但并不会将更改合并回对象配置文件中。另外 , kubectl diff命令提供了预览要更改的配置的方法。

    • 创建: kubectl apply -f <directory>/。

    • 更新: kubectl apply -f <directory>/ , 可以先使用kubectl diff -f <directory>/命令预览。

    • 删除 : kubectl apply -f <directory>/ --prune -l your=label , 建议使用命令式的方法kubectl delete -f 。

    • 查看: 命令式的方法kubectl get -f <filename|url> -o yaml

命令式对象配置相较于声明式对象配置来说 , 其缺点还在于同一目录下的配置文件必须同时进行同一种操作 , 例如要么都创建 , 要么都更新等 , 而且其他用户的更新也必须一并反映在配置文件中 , 否则将在下一次的变动中被覆盖。但声明式对象配置并无此要求或限制 , 它仅作用于自己声明的各对象 , 事先不存在的对象会被创建 , 而已存在对象则会被保留或者修改以吻合声明中的定义 , 具体操作取决于活动对象的当前状态与用户声明状态的对比结果。

声明式对象配置是优先推荐用户使用的管理机制 , 但对于新手来说 , 、命令式命令的配置方式更易于上手 , 对系统有所了解后也易于切换为配置清单管理方式。因此 , 仅推荐高级用户使用声明式配置 , 建议同时使用版本控制系统存储期望的状态和跨对象的历史信息。


参考链接

《Kubernetes从入门到进阶》之四: 资源对象 (qq.com)

《Kubernetes从入门到进阶》之五: 创建资源对象 (qq.com)