跳转至

Kubernetes集群核心概念 Pod

什么是工作负载

工作负载(workload)是在kubernetes集群中运行的应用程序。无论你的工作负载是单一服务还是多个一同工作的服务构成,在kubernetes中都可以使用pod来运行它。

workloads 分为 pod 与 controllers,pod 与控制器之间通过 label-selector 相关联,是唯一的关联方式

pod 通过控制器实现应用的运行,如何伸缩,升级等

在 pod yaml 中指定 pod 标签

定义标签
labels: 
  app: nginx

controllers 在集群中管理 pod

选择标签
selector:
  matchLabels:
  app: nginx

image-20240329171548120

pod 介绍

pod 定义与分类

参考链接: https://kubernetes.io/zh/docs/concepts/workloads/pods/

Pod 定义

  • Pod(豌豆荚) 是Kubernetes集群管理(创建、部署)与调度的最小计算单元,表示处于运行状态的一组容器。
  • Pod不是进程,而是容器运行的环境。
  • 一个Pod可以封装一个容器或多个容器(主容器或sidecar边车容器)
  • 一个pod内的多个容器之间共享部分命名空间,例如:Net Namespace,UTS Namespace,IPC Namespace及存储资源
  • 用户pod默认会被调度运行在node节点之上(不运行在master节点上,但也有例外情况)
  • pod内的IP不是固定的,集群外不能直接访问pod

Pod 分类

  • 静态 Pod: 也称之为“无控制器管理的自主式pod”,直接由特定节点上的 kubelet 守护进程管理, 不需要API 服务器看到它们,尽管大多数 Pod 都是通过控制面(例如,Deployment) 来管理的,对于静态 Pod 而言,kubelet 直接监控每个 Pod,并在其失效时重启之。

  • 控制器管理的 pod: 控制器可以控制pod的副本数,扩容与裁剪,版本更新与回滚等

查看 pod

pod 是一种计算资源,可以通过 kubectl get pod 命令来查看

查看 pod
kubectl get pod # pod 或 pods都可以,不指定 namespace,默认是名为 default 的namespace
kubectl get pod -n kube-system  # 指定查看命名空间的 pod

pod 的 YAML 资源清单格式

YAML格式查找帮助

kubectl explain namespace
kubectl explain pod
kubectl explain pod.spec
kubectl explain pod.spec.containers
# yaml格式的pod定义文件完整内容:
apiVersion: v1       #必选,api版本号,例如v1
kind: Pod           #必选,Pod
metadata:           #必选,元数据
  name: string       #必选,Pod名称
  namespace: string    #Pod所属的命名空间,默认在default的namespace
  labels:            # 自定义标签
    name: string     #自定义标签名字
  annotations:        #自定义注释列表
    name: string
spec:         #必选,Pod中容器的详细定义(期望)
  containers:      #必选,Pod中容器列表
  - name: string     #必选,容器名称
    image: string    #必选,容器的镜像名称
    imagePullPolicy: [Always | Never | IfNotPresent] #获取镜像的策略 Alawys表示下载镜像 IfnotPresent表示优先使用本地镜像,否则下载镜像,Nerver表示仅使用本地镜像
    command: [string]    #容器的启动命令列表,如不指定,使用打包时使用的启动命令
    args: [string]     #容器的启动命令参数列表
    workingDir: string     #容器的工作目录
    volumeMounts:    #挂载到容器内部的存储卷配置
    - name: string     #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
      mountPath: string    #存储卷在容器内mount的绝对路径,应少于512字符
      readOnly: boolean    #是否为只读模式
    ports:       #需要暴露的端口库号列表
    - name: string     #端口号名称
      containerPort: int   #容器需要监听的端口号
      hostPort: int    #容器所在主机需要监听的端口号,默认与Container相同
      protocol: string     #端口协议,支持TCP和UDP,默认TCP
    env:       #容器运行前需设置的环境变量列表
    - name: string     #环境变量名称
      value: string    #环境变量的值
    resources:       #资源限制和请求的设置
      limits:      #资源限制的设置
        cpu: string    #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
        memory: string     #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
      requests:      #资源请求的设置
        cpu: string    #Cpu请求,容器启动的初始可用数量
        memory: string     #内存清求,容器启动的初始可用数量
    livenessProbe:     #对Pod内个容器健康检查的设置,当探测无响应几次后将自动重启该容器,检查方法有exec、httpGet和tcpSocket,对一个容器只需设置其中一种方法即可
      exec:      #对Pod容器内检查方式设置为exec方式
        command: [string]  #exec方式需要制定的命令或脚本
      httpGet:       #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
        path: string
        port: number
        host: string
        scheme: string
        HttpHeaders:
        - name: string
          value: string
      tcpSocket:     #对Pod内个容器健康检查方式设置为tcpSocket方式
         port: number
       initialDelaySeconds: 0  #容器启动完成后首次探测的时间,单位为秒
       timeoutSeconds: 0   #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
       periodSeconds: 0    #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
       successThreshold: 0
       failureThreshold: 0
       securityContext:
         privileged:false
    restartPolicy: [Always | Never | OnFailure] # Pod的重启策略,Always表示一旦不管以何种方式终止运行,kubelet都将重启,OnFailure表示只有Pod以非0退出码退出才重启,Nerver表示不再重启该Pod
    nodeSelector: obeject  # 设置NodeSelector表示将该Pod调度到包含这个label的node上,以key:value的格式指定
    imagePullSecrets:    #Pull镜像时使用的secret名称,以key:secretkey格式指定
    - name: string
    hostNetwork: false     #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
    volumes:       #在该pod上定义共享存储卷列表
    - name: string     #共享存储卷名称 (volumes类型有很多种)
      emptyDir: {}     #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
      hostPath: string     #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
        path: string     #Pod所在宿主机的目录,将被用于同期中mount的目录
      secret:      #类型为secret的存储卷,挂载集群与定义的secret对象到容器内部
        scretname: string  
        items:     
        - key: string
          path: string
      configMap:     #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
        name: string
        items:
        - key: string
          path: string

pod 创建与验证

创建一个名为 pod-hello 的 pod

  1. 编写 yaml 文件
    pod-hello.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: hello
      namespace: default
    spec:
      containers:
      - name: hello
        image: busybox:1.28
        command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
      restartPolicy: OnFailure
    
  2. 通过 yaml 文件创建 pod
    [root@k8smaster001 pod]# kubectl apply -f pod-hello.yaml 
    pod/hello created
    

查看 Pod 信息

查看 pod 信息

[root@k8smaster001 pod]# kubectl get pod
NAME                               READY   STATUS    RESTARTS       AGE
hello                              1/1     Running   0              2m24s

查看 pod 详细信息

[root@k8smaster001 pod]# kubectl get pods -o wide
NAME                               READY   STATUS    RESTARTS       AGE     IP              NODE           NOMINATED NODE   READINESS GATES
hello                              1/1     Running   0              2m32s   10.244.35.25    k8sworker002   <none>           <none>

查看描述 pod 详细信息

[root@k8smaster001 pod]# kubectl describe pod hello
Events:
Type    Reason     Age    From               Message
----    ------     ----   ----               -------
Normal  Scheduled  3m50s  default-scheduler  Successfully assigned default/hello to k8sworker002
Normal  Pulled     3m49s  kubelet            Container image "busybox:1.28" already present on machine
Normal  Created    3m49s  kubelet            Created container hello
Normal  Started    3m49s  kubelet            Started container hello

查看 pod 日志

[root@k8smaster001 pod]# kubectl logs hello
Hello, Kubernetes!

删除 Pod

单个 pod 删除

  1. 指定 pod 名称删除

    [root@k8smaster001 pod]# kubectl delete pod hello
    pod "hello" deleted
    

  2. 指定文件删除

    [root@k8smaster001 pod]# kubectl delete -f pod-hello.yaml
    pod "hello" deleted
    

多个 pod 删除

  1. 指定多个 pod 名称
    [root@k8smaster001 pod]# kubectl delete pod pod-1 pod-2 pod-3 ...
    

Pod 镜像拉取策略

镜像拉取策略由 imagePullPolicy 参数控制,有以下三种

策略 解释
Always 不管本地有没有镜像,都要从仓库中下载镜像
Never 从来不从仓库下载镜像, 只用本地镜像,本地没有就算了
IfNotPresent 如果本地存在就直接使用, 不存在才从仓库下载
  • 当镜像标签版本是latest,默认策略就是Always

  • 如果指定特定版本默认拉取策略就是IfNotPresent。

pod 的标签

为pod设置label,用于控制器通过label与pod关联

  1. 查看pod的标签
    [root@k8smaster001 pod]# kubectl get pod --show-labels
    NAME    READY   STATUS    RESTARTS   AGE   LABELS
    hello   1/1     Running   0          96s   <none>
    
  2. 打标签,再查看
    [root@k8smaster001 pod]# kubectl label pod hello env=test zone=A region=china
    pod/hello labeled
    [root@k8smaster001 pod]# kubectl get pod hello --show-labels
    NAME    READY   STATUS    RESTARTS   AGE     LABELS
    hello   1/1     Running   0          3m42s   env=test,region=china,zone=A
    
  3. 通过等值关系标签查询
    [root@k8smaster001 pod]# kubectl get pod -l region=china
    NAME    READY   STATUS    RESTARTS   AGE
    hello   1/1     Running   0          4m27s
    
  4. 通过集合关系标签查询
    [root@k8smaster001 pod]# kubectl get pod -l "env in (test,prod)"
    NAME    READY   STATUS    RESTARTS   AGE
    hello   1/1     Running   0          5m14s
    
  5. 删除标签后再验证
    [root@k8smaster001 pod]# kubectl label pod hello env- region- zone- 
    pod/hello unlabeled
    [root@k8smaster001 pod]# kubectl get pod hello --show-labels
    NAME    READY   STATUS    RESTARTS   AGE     LABELS
    hello   1/1     Running   0          6m44s   <none>
    

总结

  • pod 的 abel 与 node 的 label 操作方式相同
  • node 的 label 用于 pod 调度到指定 label 的 node 节点
  • pod 的 label 用于 controller 关联控制的 pod
  1. 编写 yaml 文件
    pod-hello-labels.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: hello
      namespace: default
      labels:
        env: test
        app: hello       # 直接在原来的yaml里加上多个标签
    spec:
      containers:
      - name: hello
        image: busybox:1.28
        command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
      restartPolicy: OnFailure
    
  2. 通过 yaml 文件创建 pod

    [root@k8smaster001 pod]# kubectl apply -f pod-hello.yaml 
    pod/hello created
    

  3. 验证标签

    [root@k8smaster001 pod]# kubectl get pod hello --show-labels
    NAME    READY   STATUS    RESTARTS   AGE   LABELS
    hello   1/1     Running   0          4s    app=hello,env=test
    

pod资源限制

  1. 编写 两个 yaml 文件
pod-memory-1.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: pod-memory
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-memory1
  namespace: pod-memory
spec:
  containers:
  - name: c1
    image: polinux/stress
    imagePullPolicy: IfNotPresent
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "100Mi"
    command: ["stress"]                 # 启动容器时执行的命令
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]  # 产生1个进程分配150M内存1秒后释放
pod-memory-2.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: pod-memory
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-memory2
  namespace: pod-memory
spec:
  containers:
  - name: c2
    image: polinux/stress
    imagePullPolicy: IfNotPresent
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "150Mi"
    command: ["stress"]                 # 启动容器时执行的命令
    args: ["--vm", "1", "--vm-bytes", "300M", "--vm-hang", "1"]  # 产生1个进程分配300M内存1秒后释放
  1. 通过 yaml 文件创建 pod

    [root@k8smaster001 pod]# kubectl apply -f pod-memory-1.yaml pod-memory-2.yaml
    

  2. 验证标签

    [root@k8smaster001 pod]# kubectl get pod -n pod-memory
    NAME          READY   STATUS             RESTARTS      AGE
    pod-memory1   1/1     Running            0             4m13s
    pod-memory2   0/1     OOMKilled          5 (23s ago)   4m11s
    

查看发现 pod-memory2 这个 pod 状态变为 OOMKilled ,因为内存不足显示 Container 被杀死

pod 包含多个容器

  1. 编写 yaml 文件
pods.yaml
apiVersion: v1
kind: Pod
metadata:
  name: hello
  namespace: default
spec:
  containers:
  - name: hello1
    image: busybox:1.28
    command: ['sh', '-c', 'echo "Hello, I am pod1 !" && sleep 3600']
  - name: hello2
    image: busybox:1.28
    command: ['sh', '-c', 'echo "Hello, I am pod2 !" && sleep 3600']
  1. 通过 yaml 文件创建 pod yaml [root@k8smaster001 pod]# kubectl apply -f pods.yaml pod/hello created

  2. 验证标签 yaml [root@k8smaster001 pod]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES hello 2/2 Running 0 26s 10.244.35.28 k8sworker002 <none> <none>

对 pod 里的容器进行操作

命令帮助

[root@k8smaster001 pod]# kubectl exec --help

不用交互直接执行命令

格式为: kubectl exec pod名 -c 容器名 -- 命令

Note

  • -c 容器名为可选项,如果是 1 个 pod 中 1 个容器,则不用指定;
  • 如果是 1 个 pod 中多个容器,不指定默认为第 1 个。
[root@k8smaster001 pod]# kubectl exec hello -c hello1 --  touch /aaa
[root@k8smaster001 pod]# kubectl exec hello -c hello2 --  ls /aaa
ls: /aaa: No such file or directory

不指定容器名,则默认为pod里的第1个容器

[root@k8smaster001 pod]# kubectl exec hello  --  ls /aaa
Defaulted container "hello1" out of: hello1, hello2
/aaa

和容器交互操作

和 docker exec 一样

[root@k8smaster001 pod]# kubectl exec -it hello -c hello1 -- sh 
/ # ls /aaa 
/aaa
/ # exit

验证pod中多个容器网络共享

  1. 编写 yaml 文件
pod-nginx-network.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-network
spec:
  containers:
  - name: c1
    image: nginx:1.15-alpine

  - name: c2
    image: nginx:1.15-alpine
  1. 通过 yaml 文件创建 pod

    [root@k8smaster001 pod]# kubectl apply -f pod-nginx-network.yaml 
    pod/nginx-network created
    

  2. 查看 pod 信息与状态

    [root@k8smaster001 pod]# kubectl describe pod  nginx-network
    Events:
      Type    Reason     Age   From               Message
      ----    ------     ----  ----               -------
      Normal  Scheduled  45s   default-scheduler  Successfully assigned default/nginx-network to k8sworker002
      Normal  Pulling    45s   kubelet            Pulling image "nginx:1.15-alpine"
      Normal  Pulled     2s    kubelet            Successfully pulled image "nginx:1.15-alpine" in 42.162s (42.162s including waiting)
      Normal  Created    2s    kubelet            Created container c1
      Normal  Started    2s    kubelet            Started container c1
      Normal  Pulled     2s    kubelet            Container image "nginx:1.15-alpine" already present on machine
      Normal  Created    2s    kubelet            Created container c2
      Normal  Started    2s    kubelet            Started container c2
    

[root@k8smaster001 pod]# kubectl get pod
NAME            READY   STATUS             RESTARTS      AGE
nginx-network   1/2     CrashLoopBackOff   2 (15s ago)   82s
# 有一个启动失败,因为一个 pod 中两个容器是共用网络的,所以不能两个都占用 80 端口
通过查找容器日志,得到如下的报错,端口被占用

[root@k8smaster001 pod]# kubectl logs nginx-network -c c2
2024/03/29 11:44:54 [emerg] 1#1: bind() to 0.0.0.0:80 failed (98: Address in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address in use)
2024/03/29 11:44:54 [emerg] 1#1: bind() to 0.0.0.0:80 failed (98: Address in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address in use)
2024/03/29 11:44:54 [emerg] 1#1: bind() to 0.0.0.0:80 failed (98: Address in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address in use)
2024/03/29 11:44:54 [emerg] 1#1: bind() to 0.0.0.0:80 failed (98: Address in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address in use)
2024/03/29 11:44:54 [emerg] 1#1: bind() to 0.0.0.0:80 failed (98: Address in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address in use)
2024/03/29 11:44:54 [emerg] 1#1: still could not bind()
nginx: [emerg] still could not bind()

调度约束方法 node 节点选择器

node 节点选择器

Note

  • 我们在创建 pod 资源的时候,pod 会根据 schduler 进行调度,那么默认会调度到随机的一个工作节点,如果我们想要 pod 调度到指定节点或者调度到一些具有相同特点的 node 节点,怎么办呢?

  • 可以使用 pod 中的 nodeName 或者 nodeSelector 字段指定要调度到的 node 节点

给节点添加标签

  1. 列出你的集群中的节点, 包括这些节点上的标签:

    kubectl get nodes --show-labels

  2. 从你的节点中选择一个,为它添加标签:

    kubectl label nodes <your-node-name> disktype=ssd

    注意

    '<your-node-name>' 是你选择的节点的名称。

  3. 验证你选择的节点确实带有 disktype=ssd 标签:

    kubectl get nodes --show-labels | grep disktype=ssd

    image-20240110182508041

    注意

    在前面的输出中,你可以看到 linuxnbg-1 节点有 disktype=ssd 标签。

创建一个将被调度到你选择的节点的 nodeSelector

此 Pod 配置文件描述了一个拥有节点选择器 disktype: ssd 的 Pod。这表明该 Pod 将被调度到有 disktype=ssd 标签的节点。

nodeSelector.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  nodeSelector:
    disktype: ssd
  1. 使用该配置文件创建一个 Pod,该 Pod 将被调度到你选择的节点上:

    kubectl apply -f nodeSelector.yaml

  2. 验证 Pod 确实运行在你选择的节点上:

    kubectl get pod nginx --output=wide

    image-20240110185357725

创建一个会被调度到特定节点上的 nodeName

  • 可以通过设置 nodeName 将某个 Pod 调度到特定的节点。

  • nodeName 是比亲和性或者 nodeSelector 更为直接的形式。nodeName 是 Pod 规约中的一个字段。如果 nodeName 字段不为空,调度器会忽略该 Pod, 而指定节点上的 kubelet 会尝试将 Pod 放到该节点上。 使用 nodeName 规则的优先级会高于使用 nodeSelector 或亲和性与非亲和性的规则。

nodeName.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeName: linuxnbg-1 # 调度 Pod 到特定的节点
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  1. 使用此配置文件来创建一个 Pod,该 Pod 将只能被调度到定义的 linuxnbg-1 节点

    kubectl apply -f nodeName.yaml

  2. 验证 Pod 确实运行在你选择的节点上:

    kubectl get pod nginx --output=wide

    image-20240110190714997

pod 的生命周期

容器启动

  1. pod中的容器在创建前,有初始化容器(init container)来进行初始化环境
  2. 初化完后,主容器(main container)开始启动

  3. 主容器启动后,有一个post start的操作(启动后的触发型操作,或者叫启动后钩子)

  4. post start后,就开始做健康检查

    • 第一个健康检查叫存活状态检查(liveness probe ),用来检查主容器存活状态的

    • 第二个健康检查叫准备就绪检查(readiness probe),用来检查主容器是否启动就绪

容器终止

  1. 可以在容器终止前设置pre stop操作(终止前的触发型操作,或者叫终止前钩子)
  2. 当出现特殊情况不能正常销毁pod时,大概等待30秒会强制终止
  3. 终止容器后还可能会重启容器(视容器重启策略而定)。

容器重启策略

  • Always:表示容器挂了总是重启,这是默认策略

  • OnFailures:表示容器状态为错误时才重启,也就是容器正常终止时不重启

  • Never:表示容器挂了不予重启

  • 对于Always这种策略,容器只要挂了,就会立即重启,这样是很耗费资源的。所以Always重启策略是这么做的:第一次容器挂了立即重启,如果再挂了就要延时10s重启,第三次挂了就等20s重启...... 依次类推

生命周期相关介绍

  • Pod 遵循预定义的生命周期,起始于 Pending 阶段, 如果至少其中有一个主要容器正常启动,则进入 Running,之后取决于 Pod 中是否有容器以失败状态结束而进入 Succeeded 或者 Failed 阶段。

  • 在 Pod 运行期间,kubelet 能够重启容器以处理一些失效场景。 在 Pod 内部,Kubernetes 跟踪不同容器的状态并确定使 Pod 重新变得健康所需要采取的动作。

  • 在 Kubernetes API 中,Pod 包含规约部分和实际状态部分。 Pod 对象的状态包含了一组 Pod 状况(Conditions)。 如果应用需要的话,你也可以向其中注入自定义的就绪态信息。

  • Pod 在其生命周期中只会被调度一次。 一旦 Pod 被调度(分派)到某个节点,Pod 会一直在该节点运行,直到 Pod 停止或者被终止

Pod生命周期是指从Pod创建开始到终止退出的整个过程,其中包含了一些重要的流程和操作。

以下是Pod生命周期中的几个关键流程:

  • 初始化init容器:除了主容器外,你可以在Pod中定义一些初始化容器(init container)。这些容器在主容器启动之前运行,用于执行初始化任务,例如数据库初始化、数据加载等。

  • 创建主容器 containers:Pod创建时,主容器会被创建并启动。主容器通常是应用程序容器,负责运行你的应用程序。

  • 启动后钩子:在主容器启动之后,你可以定义一些启动后的钩子(postStart hook)。这些钩子是容器内的可执行命令或脚本,用于在容器启动后执行特定的操作,例如数据初始化、配置加载等。

  • 存活性探测:为了确保Pod内的容器正常运行,Kubernetes提供了存活性探测(liveness probe)机制。通过定义存活性探测,系统可以检测容器是否处于活动状态。如果探测失败,Kubernetes可以采取相应的行动,例如重启容器或重新调度Pod。

  • 就绪性探测:就绪性探测(readiness probe)用于确定容器是否已准备好接收流量。通过定义就绪性探测,Kubernetes可以确保只有在容器准备好之后才将流量引导到该容器。这有助于确保应用程序在完全就绪之前不会接收到流量。

  • 停止前钩子:在Pod终止之前,你可以定义一些停止前的钩子(preStop hook)。这些钩子是容器内的可执行命令或脚本,用于在容器终止之前执行特定的操作,例如保存状态、清理资源等。

image-20240115104922019

image-20240115104948799

Pod 的 status 字段是一个 PodStatus 对象,其中包含一个 phase 字段。

  • Pod 的阶段(Phase)是 Pod 在其生命周期中所处位置的简单宏观概述。 该阶段并不是对容器或 Pod 状态的综合汇总,也不是为了成为完整的状态机。
  • Pod 阶段的数量和含义是严格定义的,下面是 phase 可能的值:
取值 描述
Pending(悬决) Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。
Running(运行中) Pod 已经绑定到了某个节点,Pod 中所有的容器都已被创建。至少有一个容器仍在运行,或者正处于启动或重启状态。
Succeeded(成功) Pod 中的所有容器都已成功终止,并且不会再重启。
Failed(失败) Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器以非 0 状态退出或者被系统终止。
Unknown(未知) 因为某些原因无法取得 Pod 的状态。这种情况通常是因为与 Pod 所在主机通信失败。

说明

image-20240115105122167

1564985023369

  • 当一个 Pod 被删除时,执行一些 kubectl 命令会展示这个 Pod 的状态为 Terminating(终止)。 这个 Terminating 状态并不是 Pod 阶段之一。 Pod 被赋予一个可以体面终止的期限,默认为 30 秒。 你可以使用 --force 参数来强制终止 Pod。

  • 如果某节点死掉或者与集群中其他节点失联,Kubernetes 会实施一种策略,将失去的节点上运行的所有 Pod 的 phase 设置为 Failed。

  1. 用户通过 kubectl 或其他api客户端提交应用资源清单文件(yaml格式)需要创建的pod信息给 apiServer 发送 create pod 请求

  2. api server接收到pod创建请求后,生成一个包含创建信息资源清单文件。

  3. apiserver 将资源清单文件中信息写入etcd数据库,然后返回确认信息至客户端

  4. apiServer 开始反映 etcd 中的 pod 对象的变化,其它组件使用 watch 机制来跟踪检查 apiServer 上的变动

  5. Scheduler启动后会一直 watch API Server,获取 podSpec.NodeName为空的Pod,即判断pod.spec.Node == null? 若为null,表示这个Pod请求是新的,需要创建,因此先进行调度计算(共计2步:1、过滤不满足条件的,2、选择优先级高的),找到合适的node

  6. Scheduler 将结果信息更新至 apiServer。

  7. apiserver 将信息在 etcd 数据库中更新分配结果:pod.spec.Node = nodeA (设置一个具体的节点)

  8. kubelet 进程通过 API Server ,查看 etcd 数据库(kubelet通过API Server的WATCH接口监听Pod信息,如果监听到新的pod副本被调度绑定到本节点)监听到 apiServer 返回的 kube-scheduler 产生的 Pod 绑定事件后获取对应的 Pod 清单,然后调用(被选中node)本机中的Container Runtime - docker-api 初始化 volume、分配IP、下载image镜像,创建容器并启动服务。并将创建后的结果返回到给api server

  9. apiServer 将接收到的pod状态信息更新 etcd 数据库中数据状态。

  • 用户向apiServer发送删除pod对象的命令 kubectl delete pods

  • apiServcer 中的 pod 对象信息会随着时间的推移而更新,在宽限期内(默认30s),pod被视为dead

  • 将pod标记为terminating状态

  • kubelet 在监控到 pod 对象转为 terminating 状态的同时启动 pod 关闭过程

  • endpoints 控制器监控到 pod 对象的关闭行为时将其从所有匹配到此端点的 service 资源的端点列表中移除

  • 如果当前 pod 对象定义了 preStop 钩子处理器,则在其标记为 terminating 后即会以同步的方式启动执行

  • pod 对象中的容器进程收到 (TERM) 停止信号

  • 宽限期结束后,若pod中还存在仍在运行的进程,那么pod对象会收到 (SIGKILL) 立即终止的信号

  • kubelet 请求 apiServer 将此 pod 资源的宽限期设置为0从而完成删除操作,此时pod对于用户已不可见

Kubernetes 会跟踪 Pod 中每个容器的状态,就像它跟踪 Pod 总体上的阶段一样。 你可以使用容器生命周期回调 来在容器生命周期中的特定时间点触发事件

  • 一旦调度器将 Pod 分派给某个节点,kubelet 就通过容器运行时开始为 Pod 创建容器。容器的状态有三种:Waiting(等待)、Running(运行中)和 Terminated(已终止)。

  • 要检查 Pod 中容器的状态,你可以使用 kubectl describe pod <pod 名称>。 其输出中包含 Pod 中每个容器的状态。

Waiting (等待)

如果容器并不处在 RunningTerminated 状态之一,它就处在 Waiting 状态。 处于 Waiting 状态的容器仍在运行它完成启动所需要的操作:例如, 从某个容器镜像仓库拉取容器镜像,或者向容器应用 Secret 数据等等。 当你使用 kubectl 来查询包含 Waiting 状态的容器的 Pod 时,你也会看到一个 Reason 字段,其中给出了容器处于等待状态的原因。

Running(运行中)

Running 状态表明容器正在执行状态并且没有问题发生。 如果配置了 postStart 回调,那么该回调已经执行且已完成。 如果你使用 kubectl 来查询包含 Running 状态的容器的 Pod 时, 你也会看到关于容器进入 Running 状态的信息。

Terminated(已终止)

处于 Terminated 状态的容器已经开始执行并且或者正常结束或者因为某些原因失败。 如果你使用 kubectl 来查询包含 Terminated 状态的容器的 Pod 时, 你会看到容器进入此状态的原因、退出代码以及容器执行期间的起止时间。

如果容器配置了 preStop 回调,则该回调会在容器进入 Terminated 状态之前执行

pod在整个生命周期中有非常多的用户行为:

  • 1、初始化容器完成初始化
  • 2、主容器启动后可以做启动后钩子
  • 3、主容器结束前可以做结束前钩子
  • 4、在主容器运行中可以做一些健康检测,如liveness probe,readness probet