欢迎光临
我们一直在努力

从零搭建一个单节点 K8S 可观测实验室(七):从一次 Pod 创建过程,看懂 Kubernetes 核心原理

在前面的文章中,我们已经完成了单节点 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,并把代码构建、镜像制作和应用部署流程正式接入集群。

    赞(0)
    未经允许不得转载:171主机测评 » 从零搭建一个单节点 K8S 可观测实验室(七):从一次 Pod 创建过程,看懂 Kubernetes 核心原理
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址