
作者:Jamie Hannaford
翻译:bbbmj(才云)
校对:bot(才云)
源代码解释版( 强烈建议阅读): https://github.com/bbbmj/what-happens-when-k8s
想象一下,当你想在 Kubernetes 集群部署 Nginx 时,你会执行以下命令:

几秒后,你将看到三个 Nginx Pod 分布在集群 Worker 节点上。这相当神奇,但它背后究竟发生了什么?Kubernetes 最为人称道的地方是,它通过用户友好的 API 处理跨基础架构的工作负载部署,通过简单的抽象隐藏其背后的复杂性。但是,为了充分理解它为我们提供的价值,我们需要理解它的原理。本文将带领你充分了解从客户端到 Kubelet 请求的完整生命周期,并在必要时通过源代码解释它到底是什么。
Kubectl
验证和生成器
首先,当我们按下回车执行命令后,Kubectl 会执行客户端验证,以确保非法请求(如创建不支持的资源或使用格式错误的镜像名称)快速失败,并不会发送给 kube-apiserver——即通过减少不必要的负载来提高系统性能。
验证通过后, Kubectl 开始封装它将发送给 kube-apiserver 的 HTTP 请求。在 Kubernetes 中,访问或更改状态的所有尝试都通过 kube-apiserver 进行,后者又与 etcd 进行通信。Kubectl 客户端也不例外。为了构造 HTTP 请求, Kubectl 使用生成器(generators),这是一种负责序列化的抽象。
你可能没有注意到,通过执行 kubectl run
,除了运行 Deployment
,我们还能利用指定参数 --generator
来部署其他工作负载。
如果没有指定 --generator
参数的值, Kubectl 会自动推断资源的类型,具体如下:
- 具有
--restart-policy=Always
的资源被视为 Deployment; - 具有
--restart-policy=OnFailure
的资源被视为 Job; - 具有
--restart-policy=Never
的资源被视为 Pod。
Kubectl 还将确定是否需要触发其他操作,例如记录命令(用于部署或审计),或者此命令是否是 dry run。
当 Kubectl 判断出要创建一个 Deployment 后,它将使用 DeploymentV1Beta1 generator
配合我们提供的参数,生成一个运行时对象(Runtime Object)。
API Group 和版本协商
这里值得指出的是, Kubernetes 使用的是一个分类为 API Group 的版本化 API。它旨在对资源进行分类,以便于推理。
同时,它还为单个 API 提供了更好的版本化方案。例如,Deployment 的 API Group 为 apps
,其最新版本为 v1
。这也是我们为什么需要在 Deployment manifests 顶部指定 apiVersion: apps/v1
的原因。
回归正文, Kubectl 生成运行时对象之后,就开始为它查找合适的 API Group 和版本,然后组装一个知道该资源各种 REST 语义的版本化客户端。
这个发现阶段被称为版本协商(version negotiation),这时 Kubectl 会扫描 remote API 上的 /apis
路径以检索所有可能的 API Group。
由于 kube-apiserver 在 /apis
路径中公开其 OpenAPI 格式的 scheme 文档,客户端可以借此轻松找到匹配的 API。
为了提高性能, Kubectl 还将 OpenAPI scheme 缓存到 ~/.kube/cache/discovery
目录。如果要了解 API 发现的完整过程,你可以试着删除该目录并在运行 Kubectl 命令时将 -v
参数的值设为最大,然后你就可以在日志中看到所有试图找到这些 API 版本的 HTTP 请求。最后一步才是真正地发送 HTTP 请求。一旦请求获得成功的响应, Kubectl 将会根据所需的输出格式打印 success message。
客户端验证
我们在上文中没有提到的一件事是客户端身份验证(这是在发送 HTTP 请求之前处理的),现在让我们来看看。
为了成功发送请求, Kubectl 需要先进行身份验证。用户凭据一般存储在 kubeconfig
文件中,但该文件可以存储在其他不同位置。为了定位到它,我们可以执行以下操作:
- 如果指定参数
--kubeconfig
,那么采用该值; - 如果指定环境变量
$KUBECONFIG
,那么采用该值; - 否则查看默认的目录,如
~/.kube
,并使用找到的第一个文件。
解析文件后,它会确定当前要使用的上下文、当前指向的集群以及当前与用户关联的所有身份验证信息。如果用户提供了额外的参数(例如 --username
),则这些值优先,并将覆盖 kubeconfig 中指定的值。
一旦有了上述信息, Kubectl 就会填充客户端的配置,以便它能够适当地修饰 HTTP 请求:
- x509 证书使用
tls.TLSConfig
发送(包括 CA 证书); - bearer tokens 在 HTTP 请求头 Authorization 中发送;
- 用户名和密码通过 HTTP 基础认证发送;
- OpenID 认证过程是由用户事先手动处理的,产生一个像 bearer token 一样被发送的 token。

kube-apiserver
认证
我们的请求已经发送成功,接下来呢?kube-apiserver!
kube-apiserver 是客户端和系统组件用来持久化和检索集群状态的主要接口。为了执行其功能,它需要能够验证请求是否合法,这个过程被称为认证 (