为了近距离检查 Kubernetes API 对象,我们需要一个具体的例子。让我们以 Node 对象为例,它应该很容易理解,因为它代表了您可能比较熟悉的东西——集群中的一台计算机。

我用 kind 工具配置的 Kubernetes 集群有三个节点——一个 master 和两个 worker。它们由 API 中的三个 Node 对象表示。我可以使用 kubectl get 节点查询 API 并列出这些对象,如下一个清单所示。

  1. $ kubectl get nodes
  2. NAME STATUS ROLES AGE VERSION
  3. kind-control-plane Ready master 1h v1.18.2
  4. kind-worker Ready <none> 1h v1.18.2
  5. kind-worker2 Ready <none> 1h v1.18.2

下图显示了三个 Node 对象和组成集群的实际集群机器。每个 Node 对象实例代表一个主机。在每个实例中,Spec 部分包含主机的(部分)配置,而 Status 部分包含主机的状态。
image.png

节点对象与其他对象略有不同,因为它们通常由 Kubelet(运行在集群节点上的节点代理)而不是用户创建。当您将机器添加到集群时,Kubelet 通过创建代表主机的 Node 对象来注册节点。然后,用户可以编辑 Spec 部分中的(部分)字段。

探索 Node 对象的完整清单

让我们仔细看看其中一个 Node 对象。通过运行 kubectl get nodes 命令列出集群中的所有 Node 对象,然后选择要检查的一个。然后,执行 kubectl get node -o yaml 命令,将 替换为节点的名称,如下面的清单所示。

  1. $ kubectl get node kind-control-plane -o yaml
  2. apiVersion: v1
  3. kind: Node
  4. metadata:
  5. annotations: ...
  6. creationTimestamp: "2020-05-03T15:09:17Z"
  7. labels: ...
  8. managedFields: ...
  9. name: kind-control-plane #C
  10. resourceVersion: "3220054"
  11. selfLink: /api/v1/nodes/kind-control-plane
  12. uid: 16dc1e0b-8d34-4cfb-8ade-3b0e91ec838b
  13. spec:
  14. podCIDR: 10.244.0.0/24 #E
  15. podCIDRs: #E
  16. - 10.244.0.0/24 #E
  17. taints:
  18. - effect: NoSchedule
  19. key: node-role.kubernetes.io/master
  20. status:
  21. addresses: #G
  22. - address: 172.18.0.2 #G
  23. type: InternalIP #G
  24. - address: kind-control-plane #G
  25. type: Hostname #G
  26. allocatable: ...
  27. capacity: #H
  28. cpu: "8" #H
  29. ephemeral-storage: 401520944Ki #H
  30. hugepages-1Gi: "0" #H
  31. hugepages-2Mi: "0" #H
  32. memory: 32720824Ki #H
  33. pods: "110" #H
  34. conditions:
  35. - lastHeartbeatTime: "2020-05-17T12:28:41Z"
  36. lastTransitionTime: "2020-05-03T15:09:17Z"
  37. message: kubelet has sufficient memory available
  38. reason: KubeletHasSufficientMemory
  39. status: "False"
  40. type: MemoryPressure
  41. ...
  42. daemonEndpoints:
  43. kubeletEndpoint:
  44. Port: 10250
  45. images: #I
  46. - names: #I
  47. - k8s.gcr.io/etcd:3.4.3-0 #I
  48. sizeBytes: 289997247 #I
  49. ... #I
  50. nodeInfo: #J
  51. architecture: amd64 #J
  52. bootID: 233a359f-5897-4860-863d-06546130e1ff #J
  53. containerRuntimeVersion: containerd://1.3.3-14-g449e9269 #J
  54. kernelVersion: 5.5.10-200.fc31.x86_64 #J
  55. kubeProxyVersion: v1.18.2 #J
  56. kubeletVersion: v1.18.2 #J
  57. machineID: 74b74e389bb246e99abdf731d145142d #J
  58. operatingSystem: linux #J
  59. osImage: Ubuntu 19.10 #J
  60. systemUUID: 8749f818-8269-4a02-bdc2-84bf5fa21700 #J

在清单中,对象定义的四个主要部分和节点的更重要的属性都进行了注释,以帮助您区分更重要和不太重要的字段。省略了一些行以减少清单的长度。

直接访问 API

您可能有兴趣尝试直接访问 API,而不是通过 kubectl。如前所述,Kubernetes API 是基于 Web 的,因此您可以使用 Web 浏览器或 curl 命令执行 API 操作,但 API 服务器使用 TLS,您通常需要客户端证书或令牌进行身份验证。幸运的是,kubectl 提供了一个特殊的代理来处理这个问题,允许您使用纯 HTTP 通过代理与 API 对话。

要运行代理,请执行以下命令:

  1. $ kubectl proxy

开始服务于 127.0.0.1:8001

您现在可以在 127.0.0.1:8001 使用 HTTP 访问 API。例如,要检索节点对象,请打开 URL http://127.0.0.1:8001/api/v1/nodes/kind-control-plane(将 kind-control-plane 替换为您的节点名称之一)。

现在让我们仔细看看四个主要部分中的每个字段。

Type Metadata 中的字段

如您所见,清单以 apiVersion 和 kind 字段开头,它们指定了此对象清单指定的对象的 API 版本和类型。 API 版本是用于描述此对象的模式。如前所述,一个对象类型可以与多个模式相关联,每个模式中的不同字段用于描述对象。但是,通常每种类型只存在一个模式。

前面清单中的 apiVersion 只是 v1,但您将在接下来的章节中看到,其他对象类型中的 apiVersion 包含的不仅仅是版本号。例如,对于 Deployment 对象,apiVersion 是 apps/v1。而该字段最初仅用于指定 API 版本,现在也用于指定资源所属的 API 组。节点对象属于核心 API 组,通常从 apiVersion 字段中省略。

清单中定义的对象类型由字段种类指定。前面清单中的对象类型是 Node,到目前为止,您在本书中还处理了以下类型:Deployment、Service 和 Pod。

Object Metadata 中的字段

metadata包含此对象实例的元数据。它包含实例的名称,以及标签和注释等附加属性,这些将在第 9 章中进行解释,以及诸如 resourceVersion、managedFields 和其他低级字段等字段,这些将在第 12 章中进行深入解释。

Spec 中的字段

接下来是 Spec 部分,它特定于每种对象类型。与其他对象类型相比,Node 对象相对较短。 podCIDR 字段是节点分配给 pod 的 IP 范围。在这个节点上运行的 Pod 被分配了这个范围内的 IP。 taints 字段在这一点上并不重要,但你将在第 18 章了解它。

Status 中的字段

Status 部分在不同类型的对象之间也有所不同,但其目的始终相同 - 它包含对象所代表的事物的最后观察状态。对于 Node 对象,状态显示节点的 IP 地址、主机名、提供计算资源的能力、节点的当前状况、它已经下载并现在缓存在本地的容器镜像,以及节点上运行的操作系统及 Kubernetes 组件的版本的相关信息。

了解单个对象字段

要了解有关清单中各个字段的更多信息,您可以参考 http://kubernetes.io/docs/reference/ 上的 API 参考文档或使用 kubectl explain 命令,如下所述。

使用 kubectl explain 探索 API 对象字段

kubectl 工具有一个很好的功能,它允许您从命令行查找每个对象类型(种类)的每个字段的解释。通常,您首先通过运行 kubectl explain 要求它提供对象种类的基本描述,如下所示:

  1. $ kubectl explain nodes
  2. KIND: Node
  3. VERSION: v1
  4. DESCRIPTION:
  5. Node is a worker node in Kubernetes. Each node will have a unique
  6. identifier in the cache (i.e. in etcd).
  7. FIELDS:
  8. apiVersion <string>
  9. APIVersion defines the versioned schema of this representation of an
  10. object. Servers should convert recognized schemas to the latest...
  11. kind <string>
  12. Kind is a string value representing the REST resource this object
  13. represents. Servers may infer this from the endpoint the client...
  14. metadata <Object>
  15. Standard object's metadata. More info: ...
  16. spec <Object>
  17. Spec defines the behavior of a node...
  18. status <Object>
  19. Most recently observed status of the node. Populated by the system.
  20. Read-only. More info: ...

该命令打印对象的解释并列出对象可以包含的顶级字段。

深入了解 API 对象的结构

然后,您可以更深入地查找每个特定字段下的子字段。例如,您可以使用以下命令来解释节点的 spec 字段:

  1. $ kubectl explain node.spec
  2. KIND: Node
  3. VERSION: v1
  4. RESOURCE: spec <Object>
  5. DESCRIPTION:
  6. Spec defines the behavior of a node.
  7. NodeSpec describes the attributes that a node is created with.
  8. FIELDS:
  9. configSource <Object>
  10. If specified, the source to get node configuration from The
  11. DynamicKubeletConfig feature gate must be enabled for the Kubelet...
  12. externalID <string>
  13. Deprecated. Not all kubelets will set this field...
  14. podCIDR <string>
  15. PodCIDR represents the pod IP range assigned to the node.
  16. ...

请注意顶部给出的 API 版本。如前所述,可以存在多个相同类型的版本。不同的版本可以有不同的字段或默认值。如果要显示不同的版本,请使用 —api-version 选项指定它。

如果您想查看对象的完整结构(不带描述的完整字段分层列表),请尝试 kubectl explain pods —recursive。

了解对象的 status conditions

每种对象类型的规范和状态部分中的字段集都不同,但在其中许多中都可以找到 conditions字段。它列出了对象当前所处的条件。当您需要对对象进行故障排除时,它们非常有用,因此让我们更仔细地检查它们。由于以 Node 对象为例,本节还教您如何轻松识别集群节点的问题。

  1. $ kubectl get node kind-control-plane -o yaml
  2. ...
  3. status:
  4. ...
  5. conditions:
  6. - lastHeartbeatTime: "2020-05-17T13:03:42Z"
  7. lastTransitionTime: "2020-05-03T15:09:17Z"
  8. message: kubelet has sufficient memory available
  9. reason: KubeletHasSufficientMemory
  10. status: "False"
  11. type: MemoryPressure
  12. - lastHeartbeatTime: "2020-05-17T13:03:42Z"
  13. lastTransitionTime: "2020-05-03T15:09:17Z"
  14. message: kubelet has no disk pressure
  15. reason: KubeletHasNoDiskPressure
  16. status: "False"
  17. type: DiskPressure
  18. - lastHeartbeatTime: "2020-05-17T13:03:42Z"
  19. lastTransitionTime: "2020-05-03T15:09:17Z"
  20. message: kubelet has sufficient PID available
  21. reason: KubeletHasSufficientPID
  22. status: "False"
  23. type: PIDPressure
  24. - lastHeartbeatTime: "2020-05-17T13:03:42Z"
  25. lastTransitionTime: "2020-05-03T15:10:15Z"
  26. message: kubelet is posting ready status
  27. reason: KubeletReady
  28. status: "True"
  29. type: Ready

如果您只想查看对象结构的一部分,jq 工具非常方便。例如,要显示节点的状态条件,可以运行 kubectl get node -o json | jq .status.conditions。 YAML 的等效工具是 yq,kubectl get node -o yaml | yq e ‘.status.conditions’ -。

有四个条件可以显示节点的状态。每个条件都有一个类型和一个状态字段,可以是 True、False 或 Unknown,如图所示。条件的最后一次转换原因分为面向机器和面向人的,message 是面向人的,reason 是面向机器的。 lastTransitionTime 字段指示条件何时从一种状态转移到另一种状态,而 lastHeartbeatTime 字段显示控制器上次接收到给定条件的更新的时间。
image.png
尽管它是列表中的最后一个条件,但 Ready 条件可能是最重要的,因为它表明节点是否已准备好接受新的工作负载(Pod)。其他条件(MemoryPressure、DiskPressure 和 PIDPressure)表示节点是否资源不足。如果节点开始出现异常行为,请记住检查这些条件 - 例如,如果在其上运行的应用程序开始耗尽资源和/或崩溃。

了解其他对象类型的 conditions

诸如 Node 对象中的 condition 列表也用于许多其他对象类型。前面解释的条件很好地说明了为什么大多数对象的状态由多个条件而不是单个字段表示。

条件通常是正交的,这意味着它们代表对象的不相关方面。

如果将对象的状态表示为单个字段,则随后使用新值对其进行扩展将非常困难,因为这将需要更新所有监视对象状态并基于它执行操作的客户端。一些对象类型最初使用这样一个字段,有些仍然使用,但现在大多数使用条件列表。

由于本章的重点是介绍 Kubernetes API 对象的共同特征,所以我们只关注了 conditions字段,但它远不是 Node 对象状态中唯一的字段。要探索其他内容,请使用 kubectl explain 命令,如前边栏中所述。在阅读本书这一部分的其余章节后,您应该清楚地了解那些不容易理解的领域。

作为练习,使用命令 kubectl get -o yaml 来探索到目前为止您创建的其他对象(deployments、services 和 pods)。

使用 kubectl describe 命令检查对象

为了让您对 Kubernetes API 对象的整个结构有一个正确的印象,有必要向您展示一个对象的完整 YAML 清单。虽然我个人经常使用这种方法来检查对象,但检查对象的更用户友好的方法是 kubectl describe 命令,它通常显示相同的信息,有时甚至更多。

  1. $ kubectl describe node kind-worker-2
  2. Name: kind-worker2
  3. Roles: <none>
  4. Labels: beta.kubernetes.io/arch=amd64
  5. beta.kubernetes.io/os=linux
  6. kubernetes.io/arch=amd64
  7. kubernetes.io/hostname=kind-worker2
  8. kubernetes.io/os=linux
  9. Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /run/contain...
  10. node.alpha.kubernetes.io/ttl: 0
  11. volumes.kubernetes.io/controller-managed-attach-deta...
  12. CreationTimestamp: Sun, 03 May 2020 17:09:48 +0200
  13. Taints: <none>
  14. Unschedulable: false
  15. Lease:
  16. HolderIdentity: kind-worker2
  17. AcquireTime: <unset>
  18. RenewTime: Sun, 17 May 2020 16:15:03 +0200
  19. Conditions:
  20. Type Status ... Reason Message
  21. ---- ------ --- ------ -------
  22. MemoryPressure False ... KubeletHasSufficientMemory ...
  23. DiskPressure False ... KubeletHasNoDiskPressure ...
  24. PIDPressure False ... KubeletHasSufficientPID ...
  25. Ready True ... KubeletReady ...
  26. Addresses:
  27. InternalIP: 172.18.0.4
  28. Hostname: kind-worker2
  29. Capacity:
  30. cpu: 8
  31. ephemeral-storage: 401520944Ki
  32. hugepages-1Gi: 0
  33. hugepages-2Mi: 0
  34. memory: 32720824Ki
  35. pods: 110
  36. Allocatable:
  37. ...
  38. System Info:
  39. ...
  40. PodCIDR: 10.244.1.0/24
  41. PodCIDRs: 10.244.1.0/24
  42. Non-terminated Pods: (2 in total)
  43. Namespace Name CPU Requests CPU Limits ... AGE
  44. --------- ---- ------------ ---------- ... ---
  45. kube-system kindnet-4xmjh 100m (1%) 100m (1%) ... 13d
  46. kube-system kube-proxy-dgkfm 0 (0%) 0 (0%) ... 13d
  47. Allocated resources:
  48. (Total limits may be over 100 percent, i.e., overcommitted.)
  49. Resource Requests Limits
  50. -------- -------- ------
  51. cpu 100m (1%) 100m (1%)
  52. memory 50Mi (0%) 50Mi (0%)
  53. ephemeral-storage 0 (0%) 0 (0%)
  54. hugepages-1Gi 0 (0%) 0 (0%)
  55. hugepages-2Mi 0 (0%) 0 (0%)
  56. Events:
  57. Type Reason Age From Message
  58. ---- ------ ---- ---- -------
  59. Normal Starting 3m50s kubelet, kind-worker2 ...
  60. Normal NodeAllocatableEnforced 3m50s kubelet, kind-worker2 ...
  61. Normal NodeHasSufficientMemory 3m50s kubelet, kind-worker2 ...
  62. Normal NodeHasNoDiskPressure 3m50s kubelet, kind-worker2 ...
  63. Normal NodeHasSufficientPID 3m50s kubelet, kind-worker2 ...
  64. Normal Starting 3m49s kube-proxy, kind-worker2 ...

如您所见,kubectl describe 命令显示了您之前在 Node 对象的 YAML 清单中找到的所有信息,但以更易读的形式显示。您可以看到名称、IP 地址和主机名,以及节点的条件和可用容量。

检查与节点相关的其他对象

除了 Node 对象本身存储的信息外,kubectl describe 命令还显示节点上运行的 pod 以及分配给它们的计算资源总量。下面也是与节点相关的事件列表。

这些附加信息不在 Node 对象本身中找到,而是由 kubectl 工具从其他 API 对象中收集的。例如,节点上运行的 pod 列表是通过 pods 资源检索 Pod 对象获得的。

如果您自己运行 describe 命令,则可能不会显示任何事件。这是因为只显示最近发生的事件。对于 Node 对象,除非节点存在资源容量问题,否则只有在您最近(重新)启动节点时才会看到事件。

几乎每个 API 对象类型都有与 kubectl describe关联。由于它们对于调试集群至关重要,因此在您开始探索其他对象之前,你需要好好掌握这个命令。