在前面的文章中,我们已经完成了单节点 Kubernetes 集群的搭建,并逐步接入了:
-
Prometheus
-
Grafana
-
Loki
-
Fluent Bit
-
Tempo
-
OpenTelemetry Collector
现在,我们已经可以观察 Kubernetes 的指标、日志和链路追踪。
但还有一个问题:
当我们执行一条
kubectl命令时,Kubernetes 内部究竟发生了什么?
例如:
kubectl create deployment nginx --image=nginx
几秒钟之后,一个 Nginx Pod 就运行起来了。
看起来似乎是 kubectl 创建了 Pod。
但实际上,kubectl 并没有直接创建容器,甚至没有直接创建 Pod。
在这条命令背后,API Server、etcd、Scheduler、Controller Manager、Kubelet、Container Runtime 和 CNI 等多个组件依次参与,最终才让 Nginx 容器真正运行起来。
这一篇,我们就沿着这条命令的执行过程,把 Kubernetes 的核心组件串起来。

一、先看 Kubernetes 的整体分工
在分析 Pod 创建过程之前,可以先把 Kubernetes 集群分成两部分:
Kubernetes 集群
├── Control Plane
│ ├── API Server
│ ├── etcd
│ ├── Scheduler
│ └── Controller Manager
│
└── Node
├── Kubelet
├── Container Runtime
├── CNI
└── Pod
其中,Control Plane 负责做决策:
-
用户想要什么
-
集群应该达到什么状态
-
Pod 应该运行在哪个节点
-
少了 Pod 是否需要补回来
Node 则负责真正执行:
-
下载镜像
-
创建容器
-
配置网络
-
启动 Pod
-
汇报运行状态
可以简单理解为:
Control Plane 负责发号施令,Node 负责落地执行。


二、我们执行了什么命令
首先创建一个单独的命名空间:
kubectl create namespace production
然后执行:
kubectl create deployment nginx \
--image=nginx \
-n production
查看资源:
kubectl get deployment,pod -n production
可能看到:
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx 1/1 1 1 20s
NAME READY STATUS RESTARTS AGE
pod/nginx-5869d7778c-xxxxx 1/1 Running 0 20s
表面上,我们只创建了一个 Deployment。
但 Kubernetes 实际上生成了这样一条资源链:
Deployment
↓
ReplicaSet
↓
Pod
↓
Container
可以执行下面的命令验证:
kubectl get deployment,replicaset,pod -n production
你会看到 Deployment、ReplicaSet 和 Pod 三种资源。

需要注意:
kubectl create deployment创建的是 Deployment,而不是直接创建 Pod。
真正负责创建 Pod 的,是 Kubernetes 内部的控制器。
三、第一步:kubectl 把请求发送给 API Server
当我们执行:
kubectl create deployment nginx \
--image=nginx \
-n production
kubectl 会根据本机的 kubeconfig 找到 Kubernetes API Server。
通常使用的配置文件是:
~/.kube/config
可以查看当前连接的集群:
kubectl config current-context
也可以查看 API Server 地址:
kubectl cluster-info
kubectl 会把我们的命令转换成一个 Deployment 对象,大致相当于下面这份 YAML:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: production
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
然后通过 Kubernetes API,把这个对象发送给 API Server。

这里有一个非常重要的概念:
几乎所有 Kubernetes 操作,都要经过 API Server。
无论是:
-
kubectl -
Scheduler
-
Controller Manager
-
Kubelet
-
各种 Operator
-
第三方控制器
它们通常都不会直接修改 etcd,而是通过 API Server 读取或更新集群状态。
因此,API Server 可以看作 Kubernetes 的统一入口。
四、API Server 做了什么
API Server 收到 Deployment 创建请求后,不会立刻创建容器。
它首先要处理一系列检查。
1. 认证
API Server 首先确认:
你是谁?
例如:
-
客户端证书
-
ServiceAccount Token
-
OIDC Token
-
其他认证方式
在 kubeadm 安装的集群中,管理员通常通过 kubeconfig 中的客户端证书访问集群。
2. 鉴权
确认身份之后,还要判断:
你有没有权限创建 Deployment?
这通常由 RBAC 控制。
例如可以执行:
kubectl auth can-i create deployment -n production
如果返回:
yes
说明当前用户有权限。

3. Admission Control
接下来,API Server 还会经过准入控制器。
准入控制器可以:
-
修改资源
-
补充默认值
-
检查资源是否合法
-
拒绝不符合安全策略的请求
例如:
-
是否允许使用特权容器
-
是否满足资源限制要求
-
是否符合命名空间策略
-
是否需要自动注入 Sidecar
经过这些步骤后,Deployment 对象才会被接受。
五、第二步:Deployment 被保存到 etcd
请求验证通过后,API Server 会把 Deployment 的状态保存到 etcd。
etcd 是一个分布式键值数据库,用于保存 Kubernetes 集群状态。
其中包括:
-
Deployment
-
ReplicaSet
-
Pod
-
Service
-
ConfigMap
-
Secret
-
Node
-
Namespace
-
资源状态和元数据
可以把 etcd 理解成:
Kubernetes 的集群数据库。
但需要注意,普通组件一般不会直接访问 etcd。
通常只有 API Server 直接读写 etcd。
整体关系是:
kubectl
↓
API Server
↓
etcd
而不是:
kubectl
↓
etcd
如果 etcd 中的数据全部丢失,那么 Kubernetes 即使节点上的容器还暂时运行着,也会失去对整个集群状态的管理能力。
所以在生产环境中,etcd 的备份非常重要。


六、Kubernetes 的核心:期望状态与实际状态
Deployment 被写入 etcd 后,里面记录的是用户的期望:
replicas: 1
它表达的意思不是:
立即执行一次创建 Pod 的命令。
而是:
我希望集群中始终存在一个符合模板定义的 Pod。
这就是 Kubernetes 最核心的设计思想之一:
期望状态:应该有 1 个 Nginx Pod
实际状态:现在有 0 个 Nginx Pod
差异:少了 1 个
操作:创建 1 个 Pod
Kubernetes 会持续比较:
期望状态
↓
实际状态
↓
发现差异
↓
执行修正
这个过程通常被称为:
Reconciliation Loop,也就是调谐循环。
Kubernetes 并不是把命令执行一次就结束,而是不断检查实际状态是否符合期望状态。

七、第三步:Controller Manager 创建 ReplicaSet
Deployment 保存成功后,API Server 会向客户端返回创建成功。
但是这时 Pod 可能还没有出现。
Controller Manager 中运行着许多控制器,其中 Deployment Controller 会持续关注 Deployment 资源。
它发现:
存在 Deployment nginx
期望副本数为 1
但对应的 ReplicaSet 还不存在
于是 Deployment Controller 创建一个 ReplicaSet。
执行:
kubectl get replicaset -n production
可能看到:
NAME DESIRED CURRENT READY AGE
nginx-5869d7778c 1 1 1 1m
ReplicaSet 的名字通常由:
Deployment 名称 + Pod 模板哈希
组成。
因此可能是:
nginx-5869d7778c
Deployment 本身主要负责:
-
管理版本
-
管理滚动升级
-
管理回滚
-
创建和切换 ReplicaSet
ReplicaSet 负责:
- 保证指定数量的 Pod 存在

可以简单理解为:
Deployment 管版本
ReplicaSet 管数量
Pod 负责实际运行
八、第四步:ReplicaSet Controller 创建 Pod
ReplicaSet 创建之后,ReplicaSet Controller 会发现:
期望 Pod 数量:1
实际 Pod 数量:0
于是它通过 API Server 创建一个 Pod 对象。
这时,etcd 中已经出现了 Pod 的定义。
但是这个 Pod 还不能立即运行。
执行:
kubectl get pod -n production -o wide
在创建过程很慢时,可能短暂看到:
NAME READY STATUS NODE
nginx-5869d7778c-xxxxx 0/1 Pending <none>
这里最值得注意的是:
NODE: <none>
这表示 Pod 已经创建出来了,但还没有决定运行在哪个节点。

此时 Pod 只是一个保存在 Kubernetes API 中的对象,还没有真正对应到任何正在运行的容器。
九、第五步:Scheduler 为 Pod 选择节点
Scheduler 持续观察所有还没有绑定节点的 Pod。
它发现这个 Nginx Pod:
spec.nodeName 为空
于是开始为它选择合适的节点。
Scheduler 的调度大致分成两个阶段。
1. 过滤
先排除不满足条件的节点,例如:
-
CPU 或内存不足
-
节点不可调度
-
不满足 Node Selector
-
不满足亲和性规则
-
存在无法容忍的污点
-
端口冲突
-
存储卷无法挂载
2. 评分
在剩余节点中进行评分,例如考虑:
-
资源是否均衡
-
Pod 是否应该分散
-
亲和性和反亲和性
-
镜像是否已经存在
-
自定义调度规则
最后,Scheduler 选择一个分数较高的节点。
在我们的单节点实验室中,通常只有一个可用节点,所以选择过程比较简单。
可以查看节点:
kubectl get nodes
例如:
NAME STATUS ROLES AGE VERSION
vbox-ubuntu24-server Ready control-plane 10d v1.xx.x
Scheduler 选中节点后,会通过 API Server 更新 Pod 的绑定信息。

Pod 中会出现:
spec:
nodeName: vbox-ubuntu24-server
从这一刻开始,这个 Pod 就归该节点负责了。

十、第六步:Kubelet 发现属于自己的 Pod
每个 Kubernetes 节点上都运行着 Kubelet。
Kubelet 可以理解为节点上的 Kubernetes 管理代理。
它会持续通过 API Server 关注:
有没有 Pod 被调度到我这个节点?
当 Kubelet 发现 Nginx Pod 的 nodeName 是自己时,就开始执行 Pod 的实际创建过程。
Kubelet 主要负责:
-
获取 Pod 定义
-
请求 Container Runtime 创建容器
-
挂载 Volume
-
配置 Secret 和 ConfigMap
-
执行健康检查
-
重启失败的容器
-
向 API Server 汇报状态
但 Kubelet 自己并不直接负责运行容器。
它需要调用 Container Runtime。
十一、第七步:Container Runtime 创建容器
Kubelet 通过 CRI,也就是 Container Runtime Interface,与容器运行时通信。
常见的容器运行时包括:
-
containerd
-
CRI-O
-
Docker 配合 cri-dockerd
我们的实验室采用的是:
Kubelet
↓ CRI
cri-dockerd
↓
Docker Engine
可以查看 Kubelet 的运行时端点:
sudo grep containerRuntimeEndpoint \
/var/lib/kubelet/config.yaml
在我们的环境中,大致是:
unix:///var/run/cri-dockerd.sock

Kubelet 会要求容器运行时完成以下工作:
-
创建 Pod Sandbox
-
准备 Pod 网络命名空间
-
拉取 Nginx 镜像
-
创建容器
-
启动容器
如果本地没有镜像,容器运行时会执行类似:
docker pull nginx
的操作。
因此,如果无法访问镜像仓库,Pod 可能进入:
ErrImagePull
或者:
ImagePullBackOff
可以通过下面的命令查看原因:
kubectl describe pod \
-l app=nginx \
-n production
十二、Pod 到底是什么
很多初学者会把 Pod 和容器混为一谈。
实际上,Pod 并不等于容器。
Pod 是 Kubernetes 中最小的调度单位。
一个 Pod 中可以包含:
-
一个业务容器
-
多个业务容器
-
Sidecar 容器
-
Init Container
同一个 Pod 内的容器共享:
-
网络命名空间
-
Pod IP
-
端口空间
-
部分存储卷
-
生命周期
例如:
Pod
├── Nginx 容器
└── 日志 Sidecar 容器
这两个容器可以通过:
localhost
互相访问。
不过大多数简单应用,一个 Pod 中通常只有一个主要容器。
在本例中:
Pod
└── Nginx Container
Pod 是 Kubernetes 管理和调度的对象,而容器是真正运行应用程序的地方。
十三、第八步:CNI 为 Pod 配置网络
容器要运行,还需要网络。
Kubernetes 本身定义了网络模型,但通常不会直接实现具体的 Pod 网络。
具体网络配置由 CNI 插件完成。
CNI 的全称是:
Container Network Interface
常见的 CNI 插件包括:
-
Flannel
-
Calico
-
Cilium
-
Weave Net
我们的单节点实验室使用 Flannel。
当 Kubelet 和容器运行时创建 Pod Sandbox 时,会调用 CNI 插件,为 Pod 完成网络配置。
通常包括:
-
创建虚拟网卡
-
把网卡放入 Pod 网络命名空间
-
给 Pod 分配 IP 地址
-
设置路由
-
设置宿主机网络连接
-
配置跨节点通信
可以查看 Pod IP:
kubectl get pod -n production -o wide
可能看到:
NAME IP NODE
nginx-5869d7778c-xxxxx 10.244.0.8 vbox-ubuntu24-server
其中:
10.244.0.8
就是由集群网络分配给 Pod 的地址。
需要注意:
Pod IP 通常不是长期稳定的。
Pod 被删除并重新创建后,IP 很可能变化。
因此,业务访问通常不应该直接依赖 Pod IP,而应该通过 Service。

十四、第九步:Pod 进入 Running 状态
容器成功启动后,Kubelet 会不断检查容器状态。
随后通过 API Server 更新 Pod Status。
状态变化可能是:
Pending
↓
ContainerCreating
↓
Running
执行:
kubectl get pod -n production -w
可以实时观察 Pod 状态变化。
当看到:
READY STATUS
1/1 Running
表示:
-
Pod 已经被调度到节点
-
Pod 网络已经配置完成
-
Nginx 镜像已经准备好
-
容器已经启动
-
容器处于就绪状态
到这里,一次完整的 Deployment 创建流程才基本结束。


十五、把整个创建流程串起来
现在把整个过程连起来:
1. 用户执行 kubectl create deployment
↓
2. kubectl 向 API Server 发送请求
↓
3. API Server 完成认证、鉴权和准入检查
↓
4. Deployment 被保存到 etcd
↓
5. Deployment Controller 发现新的 Deployment
↓
6. Deployment Controller 创建 ReplicaSet
↓
7. ReplicaSet Controller 创建 Pod
↓
8. Scheduler 为 Pod 选择节点
↓
9. Kubelet 发现 Pod 被分配到本节点
↓
10. Kubelet 调用 Container Runtime
↓
11. Container Runtime 创建 Pod Sandbox 和容器
↓
12. CNI 为 Pod 配置网络
↓
13. Container Runtime 启动 Nginx
↓
14. Kubelet 将 Pod 状态更新为 Running
这里没有任何一个组件独自完成全部工作。
Kubernetes 是依靠多个组件共同协作,让集群逐渐达到期望状态。

十六、删除 Pod 后,为什么它又回来了
现在可以做一个非常直观的实验。
先查看 Pod:
kubectl get pod -n production
然后删除它:
kubectl delete pod \
-l app=nginx \
-n production
再次查看:
kubectl get pod -n production -w
你会发现旧 Pod 被删除后,很快又出现了一个新 Pod。
这是因为我们删除的只是 Pod,而 Deployment 和 ReplicaSet 仍然存在。
ReplicaSet Controller 看到:
期望副本数:1
实际副本数:0
于是重新创建一个 Pod。
这就是 Kubernetes 的自愈能力。
但严格来说,并不是旧 Pod"复活"了。
实际发生的是:
旧 Pod 被删除
↓
ReplicaSet 发现副本数不足
↓
创建一个新的 Pod
新的 Pod 通常具有:
-
新的 Pod 名称
-
新的 Pod UID
-
可能不同的 Pod IP
十七、Deployment 为什么不直接管理 Pod
可能有人会问:
Deployment 为什么还要经过 ReplicaSet,不能直接创建 Pod 吗?
主要原因是版本管理和滚动更新。
假设我们修改镜像:
kubectl set image deployment/nginx \
nginx=nginx:1.27-alpine \
-n production
Deployment 会为新的 Pod 模板创建一个新的 ReplicaSet。
大致过程是:
旧 ReplicaSet
├── 旧 Pod
└── 旧 Pod
新 ReplicaSet
├── 新 Pod
└── 新 Pod
在滚动更新过程中,Deployment 会逐步:
-
增加新 ReplicaSet 的副本
-
减少旧 ReplicaSet 的副本
-
保证服务尽量不中断
可以查看滚动更新状态:
kubectl rollout status deployment/nginx \
-n production
也可以查看历史:
kubectl rollout history deployment/nginx \
-n production
如果新版本存在问题,还可以回滚:
kubectl rollout undo deployment/nginx \
-n production
所以:
Deployment
↓ 管理版本
ReplicaSet
↓ 管理副本数量
Pod
↓ 运行应用
Container
这样的分层设计,为滚动升级和回滚提供了基础。


十八、Service 什么时候参与
到目前为止,我们执行的命令只创建了 Deployment:
kubectl create deployment nginx --image=nginx
它不会自动创建 Service。
虽然 Pod 已经拥有 IP,但 Pod IP 并不稳定。
为了给应用提供一个稳定的访问入口,需要创建 Service:
kubectl expose deployment nginx \
--port=80 \
--target-port=80 \
-n production
查看 Service:
kubectl get service -n production
可能看到:
NAME TYPE CLUSTER-IP PORT(S)
nginx ClusterIP 10.96.31.20 80/TCP
Service 提供了一个相对稳定的:
-
名称
-
ClusterIP
-
端口
Service 并不是一台真正的代理服务器,也不是一个普通 Pod。
它更像是一组访问规则。
Service 会通过 Label Selector 找到后端 Pod。
可以查看:
kubectl describe service nginx -n production
其中可能包含:
Selector: app=nginx
Endpoints: 10.244.0.8:80
关系如下:
Service nginx
↓ 根据 Label Selector 查找
Pod app=nginx
↓
Nginx Container
只要新的 Pod 仍然带有:
app: nginx
这个 Label,Service 就可以把流量发送给它。
即使 Pod 被替换、IP 发生变化,Service 的访问入口仍然可以保持稳定。

十九、Service 如何找到 Pod
Service 本身依靠标签选择器匹配 Pod。
可以查看 Deployment 的标签:
kubectl get pod \
-n production \
--show-labels
例如:
NAME LABELS
nginx-5869d7778c-xxxxx app=nginx,pod-template-hash=5869d7778c
Service 的选择器是:
app=nginx
因此它会匹配这个 Pod。
Kubernetes 还会维护对应的 EndpointSlice。
查看:
kubectl get endpointslice -n production
它记录了当前可用后端 Pod 的地址。
整体关系是:
Service
↓
EndpointSlice
↓
Pod IP
当 Pod 被替换后,EndpointSlice Controller 会自动更新后端地址。
所以应用不需要关心 Pod IP 是否变化。
二十、CoreDNS 什么时候参与
创建 Pod 本身并不一定需要 CoreDNS。
但是当 Pod 需要通过名称访问 Service 时,CoreDNS 就会参与。
在 Kubernetes 中,Service 通常会获得类似这样的 DNS 名称:
nginx.production.svc.cluster.local
其中:
nginx
是 Service 名称。
production
是 Namespace。
svc.cluster.local
是 Kubernetes 集群中的 Service DNS 域。
我们可以创建一个临时 Pod 进行验证:
kubectl run test-client \
--image=busybox:1.36 \
--restart=Never \
-n production \
-- sh -c 'sleep 3600'
查看 DNS 解析:
kubectl exec test-client \
-n production \
-- nslookup nginx
访问 Nginx:
kubectl exec test-client \
-n production \
-- wget -qO- http://nginx
这里的:
http://nginx
并不是访问某个名为 nginx 的 Pod。
它实际访问的是名为 nginx 的 Service。

大致过程是:
test-client Pod
↓ 查询 nginx
CoreDNS
↓ 返回 Service ClusterIP
nginx Service
↓ 转发到后端
nginx Pod
CoreDNS 负责名称解析,但它不负责真正转发业务流量。
它解决的是:
nginx 这个名称对应哪个 IP?

二十一、CNI、CoreDNS 和 Service 的区别
这三个组件经常被混在一起。
可以这样区分。
CNI:负责网络连通
CNI 负责:
-
给 Pod 分配 IP
-
配置虚拟网卡
-
配置路由
-
让 Pod 之间能够通信
它解决的问题是:
Pod 的网络怎么建立?
CoreDNS:负责名称解析
CoreDNS 负责:
-
把 Service 名称解析为 ClusterIP
-
提供集群内部 DNS 服务
它解决的问题是:
nginx 这个名字对应哪个地址?
Service:提供稳定访问入口
Service 负责:
-
提供稳定的 ClusterIP 和端口
-
根据 Label 找到后端 Pod
-
把流量送往可用 Pod
它解决的问题是:
Pod IP 会变化,应用应该通过什么入口访问?
三者串起来就是:
应用访问 http://nginx
↓
CoreDNS 解析 nginx
↓
得到 Service ClusterIP
↓
Service 选择后端 Pod
↓
通过 CNI 建立的网络到达 Pod

二十二、API Server、Controller 和 Kubelet 都在循环
理解 Kubernetes 时,最重要的一点是:
Kubernetes 不是一条从头执行到尾的脚本。
它更像是一组不断运行的控制循环。
Deployment Controller
不断检查:
Deployment 是否有正确的 ReplicaSet
ReplicaSet Controller
不断检查:
实际 Pod 数量是否等于期望副本数
Scheduler
不断检查:
是否存在尚未分配节点的 Pod
Kubelet
不断检查:
分配到本节点的 Pod 是否真的在运行
EndpointSlice Controller
不断检查:
Service 后面的 Pod 地址是否发生变化
每个组件只负责自己的一小部分。
它们通过 API Server 观察和更新资源状态,最终让整个集群逐渐达到期望状态。
二十三、控制面并不会直接启动容器
从整个过程可以看到:
-
API Server 不启动容器
-
etcd 不启动容器
-
Scheduler 不启动容器
-
Controller Manager 也不启动容器
真正与容器运行相关的是:
Kubelet
↓
Container Runtime
控制面主要负责:
-
保存期望状态
-
创建资源对象
-
选择节点
-
修正状态差异
节点负责:
-
拉取镜像
-
创建容器
-
配置网络
-
执行健康检查
-
汇报状态
这也是为什么即使 API Server 暂时不可用,已经运行的容器可能仍然继续运行。
但是控制面不可用期间:
-
无法创建新资源
-
无法调度新 Pod
-
无法完成新的控制操作
-
集群状态无法正常协调
二十四、Pod 创建失败时,应该从哪里排查
理解了创建流程之后,故障排查就不再只是反复执行 kubectl get pod。
可以根据 Pod 停在哪个阶段判断问题。
Pod 一直 Pending
可能原因:
-
没有可用节点
-
CPU 或内存不足
-
Taint 无法容忍
-
Node Selector 不匹配
-
PVC 无法绑定
-
Scheduler 无法找到合适节点
查看:
kubectl describe pod <pod-name> \
-n production
重点看 Events。
Pod 一直 ContainerCreating
可能原因:
-
镜像正在下载
-
CNI 配置失败
-
Volume 挂载失败
-
Container Runtime 异常
查看:
kubectl describe pod <pod-name> \
-n production
也可以检查 Kubelet:
sudo journalctl -u kubelet -n 100
Pod 出现 ImagePullBackOff
说明镜像下载失败。
常见原因:
-
镜像名称错误
-
镜像仓库无法访问
-
私有仓库未配置凭据
-
网络或 DNS 异常
Pod 出现 CrashLoopBackOff
说明容器已经启动,但应用反复崩溃。
查看日志:
kubectl logs <pod-name> \
-n production
如果容器已经重启,可以查看上一次日志:
kubectl logs <pod-name> \
-n production \
--previous
理解 Pod 创建链路后,排查思路可以变成:
对象有没有创建?
↓
有没有完成调度?
↓
Kubelet 有没有收到?
↓
镜像有没有拉取成功?
↓
CNI 有没有配置成功?
↓
容器有没有启动?
↓
应用为什么退出?
二十五、通过事件观察 Kubernetes 的动作
Kubernetes 中很多创建、调度和启动过程都会记录为 Event。
可以执行:
kubectl get events \
-n production \
--sort-by=.metadata.creationTimestamp
可能看到:
Scheduled
Pulling
Pulled
Created
Started
它们分别表示:
Scheduled
Pod 已经被调度到节点
Pulling
正在拉取容器镜像
Pulled
镜像拉取完成
Created
容器已经创建
Started
容器已经启动
这是观察 Pod 创建过程最直观的方法之一。
也可以重新创建 Deployment,并实时观察:
kubectl delete deployment nginx -n production
然后在一个终端中执行:
kubectl get pod -n production -w
另一个终端重新创建:
kubectl create deployment nginx \
--image=nginx \
-n production
同时查看事件:
kubectl get events \
-n production \
--sort-by=.metadata.creationTimestamp
这样就能看到从创建到运行的完整过程。
二十六、在可观测系统中,这些组件意味着什么
前面我们已经安装了 Prometheus、Grafana、Loki 和 Tempo。
现在再回头看,会更容易理解为什么 Kubernetes 可观测性需要覆盖多个层次。
API Server
可以观察:
-
API 请求数量
-
请求延迟
-
错误率
-
认证和鉴权异常
etcd
可以观察:
-
请求延迟
-
数据库大小
-
Leader 状态
-
磁盘写入性能
Scheduler
可以观察:
-
调度延迟
-
调度成功次数
-
调度失败次数
-
Pending Pod 数量
Controller Manager
可以观察:
-
控制器调谐次数
-
调谐失败情况
-
工作队列长度
Kubelet
可以观察:
-
Pod 启动状态
-
容器运行状态
-
节点资源
-
Volume 和网络异常
Container Runtime
可以观察:
-
镜像拉取
-
容器启动
-
容器退出
-
Runtime 错误
应用 Pod
可以观察:
-
CPU
-
内存
-
请求量
-
错误率
-
日志
-
Trace
因此,Kubernetes 可观测性不是只看一张 CPU 曲线。
真正完整的可观测链路应该覆盖:
用户请求
↓
API Server
↓
控制器与调度器
↓
Kubelet
↓
Container Runtime
↓
Pod
↓
应用
二十七、本次实验资源清理
实验完成后,删除临时测试 Pod:
kubectl delete pod test-client \
-n production \
--ignore-not-found
删除 Nginx Service:
kubectl delete service nginx \
-n production \
--ignore-not-found
删除 Deployment:
kubectl delete deployment nginx \
-n production \
--ignore-not-found
确认资源已经删除:
kubectl get deployment,replicaset,pod,service \
-n production
如果 production 命名空间后续不再使用,也可以删除:
kubectl delete namespace production
不过如果后续文章还要继续在 production 命名空间中部署应用,可以保留该命名空间。


二十八、总结
执行:
kubectl create deployment nginx --image=nginx
看起来只是一条简单命令。
但 Kubernetes 内部实际经历了:
kubectl
↓
API Server
↓
etcd
↓
Deployment Controller
↓
ReplicaSet Controller
↓
Scheduler
↓
Kubelet
↓
Container Runtime
↓
CNI
↓
Pod
如果再创建 Service,并通过名称访问应用,还会涉及:
CoreDNS
↓
Service
↓
EndpointSlice
↓
Pod
其中:
-
API Server 是统一入口
-
etcd 保存集群状态
-
Controller Manager 维护期望状态
-
Scheduler 选择运行节点
-
Kubelet 管理节点上的 Pod
-
Container Runtime 创建和运行容器
-
CNI 配置 Pod 网络
-
Pod 是 Kubernetes 的最小调度单位
-
Deployment 管理版本和更新
-
ReplicaSet 保证 Pod 副本数量
-
Service 提供稳定访问入口
-
CoreDNS 提供集群内部名称解析
Kubernetes 最核心的并不是"启动容器"。
它真正重要的能力是:
用户只需要声明期望状态,Kubernetes 会通过一组持续运行的控制循环,让实际状态不断接近期望状态。
理解这一点之后,Deployment、滚动发布、自愈、自动扩缩容和声明式管理就不再是彼此独立的功能。
它们本质上都是同一种机制的不同表现。
下一篇,我们将在这个 Kubernetes 实验室中安装 Jenkins,并把代码构建、镜像制作和应用部署流程正式接入集群。