Pod资源对象

一、概述

Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元

Pod(就像在鲸鱼荚或者豌豆荚中)是一组(一个或多个) 容器; 这些容器共享存储、网络、以及怎样运行这些容器的声明。 Pod 中的容器总是并置(colocated)的并且一同调度,在共享的上下文中运行。 Pod 所建模的是特定于应用的 “逻辑主机”,其中包含一个或多个应用容器, 这些容器相对紧密地耦合在一起。 在非云环境中,在相同的物理机或虚拟机上运行的应用类似于在同一逻辑主机上运行的云应用。

除了应用容器,Pod 还可以包含在 Pod 启动期间运行的 Init 容器。 你也可以在集群支持临时性容器的情况下, 为调试的目的注入临时性容器。

Pod 的共享上下文包括一组 Linux 名字空间、控制组(cgroup)和可能一些其他的隔离方面, 即用来隔离容器的技术。 在 Pod 的上下文中,每个独立的应用可能会进一步实施隔离。

Pod 类似于共享名字空间并共享文件系统卷的一组容器。

二、POD创建过程

第一步: ​ 客户端提交创建Pod的请求,可以通过调用API Server的Rest API接口,也可以通过kubectl命令行工具。如kubectl apply -f filename.yaml(资源清单文件) ​ 第二步: ​ apiserver接收到pod创建请求后,会将yaml中的属性信息(metadata)写入etcd。 ​ 第三步: ​ apiserver触发watch机制准备创建pod,信息转发给调度器scheduler,调度器用一组规则过滤掉不符合要求的主机,比如Pod指定了所需要的资源量,那么可用资源比Pod需要的资源量少的主机会被过滤掉。调度器使用调度算法选择node,调度器将node信息给apiserver,apiserver将绑定的node信息写入etcd。 ​ 第四步: ​ apiserver又通过watch机制,调用kubelet,指定pod信息,调用Docker API创建并启动pod内的容器。 ​ 第五步: ​ worker创建完成之后反馈给自身的kubelet, 再反馈给控制器的apiserver,apiserver又将pod的状态信息写入etcd

三、Pod资源清单详解

3.1 Pod资源清单介绍

#查看对象中包含哪些字段
[root@k8s-master01 ~]# kubectl explain pod.spec.containers

3.2 标签

标签其实就一对 key/value ,被关联到对象上,比如Pod,标签的使用我们倾向于能够表示对象的特殊特点,就是一眼就看出了这个Pod是干什么的,标签可以用来划分特定的对象(比如版本,服务类型等),标签可以在创建一个对象的时候直接定义,也可以在后期随时修改,每一个对象可以拥有多个标签,但是,key值必须是唯一的。创建标签之后也可以方便我们对资源进行分组管理。如果对pod打标签之后就可以使用标签来查看、删除指定的pod。(慎重)

在k8s中,大部分资源都可以打标签。

给pod资源打标签

#对已经存在的pod打标签
[root@k8s-master01 ~]#  kubectl label pods pod-first  release=v1
#查看标签是否打成功
[root@k8s-master01 ~]#  kubectl get pods pod-first --show-labels

查看资源标签

#查看默认名称空间下所有pod资源的标签
[root@k8s-master01 ~]# kubectl get pods --show-labels
#查看默认名称空间下指定pod具有的所有标签
[root@k8s-master01 ~]# kubectl get pods pod-first --show-labels
#列出默认名称空间下标签key是release的pod,不显示标签
[root@k8s-master01 ~]# kubectl get pods -l release
#列出默认名称空间下标签key是release、值是v1的pod,不显示标签
[root@k8s-master01 ~]# kubectl get pods -l release=v1
#列出默认名称空间下标签key是release的所有pod,并打印对应的标签值
[root@k8s-master01 ~]# kubectl get pods -L release
#查看所有名称空间下的所有pod的标签
[root@k8s-master01 ~]# kubectl get pods --all-namespaces --show-labels
#移除指定的label
[root@k8s-master01 ~]#  kubectl label pods pod-first  release-

3.3 资源限制

节点资源不足,导致调度失败

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod2
spec:
  containers:
  - name: nginx2
    image: nginx
    imagePullPolicy: IfNotPresent
    resources:
      limits:
        cpu: '8'
        memory: '8Gi'
      requests:
        cpu: '6'

#状态信息
[root@k8s-master ~]# kubectl get pod
NAME         READY   STATUS    RESTARTS   AGE
nginx-pod    1/1     Running   0          47m
nginx-pod2   0/1     Pending   0          4m14s
#排错
[root@k8s-master ~]# kubectl describe pod nginx-pod2 
.....
Events:
  Type     Reason            Age    From               Message
  ----     ------            ----   ----               -------
  Warning  FailedScheduling  4m36s  default-scheduler  0/3 nodes are available: 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }, 2 Insufficient cpu. preemption: 0/3 nodes are available: 1 Preemption is not helpful for scheduling, 2 No preemption victims found for incoming pod.

所在命名空间资源不足

#创建命名空间并设置资源限制
[root@k8s-master ~]# vim c2409.txt
apiVersion: v1
kind: Namespace
metadata:
  name: c2409
---
apiVersion: v1
kind: ResourceQuota
metadata:
  name: mem-cpu-quota
  namespace: c2409
spec:
  hard:
    requests.cpu: '2'
    requests.memory: '2Gi'
    limits.cpu: '4'
    limits.memory: '4Gi'
###创建pod
[root@k8s-master ~]# vim nginx.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod2
  namespace: c2409
spec:
  containers:
  - name: nginx2
    image: nginx
    imagePullPolicy: IfNotPresent
    resources:
      limits:
        cpu: '8'
        memory: '8Gi'
      requests:
        cpu: '6'
        memory: '2Gi'

#提交后的报错信息
[root@k8s-master ~]# kubectl apply -f nginx.yaml 
Error from server (Forbidden): error when creating "nginx.yaml": pods "nginx-pod2" is forbidden: exceeded quota: mem-cpu-quota, requested: limits.cpu=8,limits.memory=8Gi,requests.cpu=6, used: limits.cpu=0,limits.memory=0,requests.cpu=0, limited: limits.cpu=4,limits.memory=4Gi,requests.cpu=2

3.4 Pod探针

在K8S集群中,为了测试pod是否正常运行,可以通过kubelet定期对pod进行健康检查,从而保证服务正常运行。

kubelet检查机制

1、exec: 在容器内执行指定命令,当返回码为0表示检测成功。在 Kubernetes 1.20 版本之前,exec 探针会忽略 timeoutSeconds: 探针会无限期地持续运行,甚至可能超过所配置的限期,直到返回结果为止。

2、httpGet:对容器的IP和URL进行HTTP的GET请求,当响应码(状态码)为大于等于200且小于400,表示容器正常运行。

3、tcpSocket:对容器内的端口或socket进行TCP检查,如果端口成功打开,证明容器正常运行。

探针返回结果

Success:表示通过检测。

Failure:表示未通过检测。

Unknown:表示检测没有正常进行。

探针的类型

1、livenessProbe(存活探针):判断容器是否正常运行。如果存活探测失败,那么kubelet就会把老的容器删除,然后根据重启策略对容器做操作。如果容器没有存活探针,默认状态为Success。

2、readinessProbe(就绪探针):判断容器的是否就绪。比如:应用在启动时可能需要加载大量的数据或配置文件,或是启动后要依赖等待外部服务。在这种情况下,既不想杀死应用,也不想给它发送请求。这个时候就需要用到这个探针。当就绪探测失败,端点控制器将从与 Pod匹配的所有服务的端点列表中删除该 Pod 的 IP 地址(如果是用nodeport映射端口到外网,这个时候就不能访问网站了,但是容器不会被删除),初始延迟之前的就绪态的状态值默认为 Failure。 如果容器不提供就绪态探针,则默认状态为 Success。

3、startupProbe(启动探针):指示容器中的应用是否已经启动。如果提供了启动探针,则所有其他探针都会被禁用,直到此探针成功为止。如果启动探测失败,kubelet 将删除容器,而容器依其重启策略进行重启。如果容器没有提供启动探测,则默认状态为 Success。

tartupProbe 和 livenessProbe 最大的区别就是startupProbe在探测成功之后就不会继续探测了,而livenessProbe在pod的生命周期中一直在探测!

探针属性

1、(initialDelaySeconds: 5):初始化延迟时间,主要是告诉kubelet,容器启动需要的时间,当过了这个时间再进行探测,要不然容器可能还没启动就会删除了。

2、(periodSeconds: 5):探测周期间隔时间,主要是指定kubelet对容器进行探针的时间周期,也就是第一次探测结束后,等待多少时间后对容器进行探测。默认值为10秒,最小值为1秒。

3、(timeoutSeconds: 5):单次探测超时时间,指定kubelet对容器探测的最大时间,超过这个时间证明容器探测失败。默认为1秒,最小为1秒。

4、(successThreshold: 5):探测失败到成功的重试次数,当kubelet对某个容器第一次探测失败后,重新进行探测的次数,比如指定为1,那么就会直接将容器删除。如果使用的探针是livenessProbe,那么只能配置为1,最小值为1次。

5、(failureThreshold: 5):探测成功到失败的重试次数,当kubelet对某个容器进行探测过程中,允许失败的次数,当用于readinessProbe探针,默认是3次,最小值为1次。也就是说当3次探测失败后,容器会被删除。当用于startupProbe探针,如果还设置了periodSeconds时间,那么等待容器启动的时间为failureThreshold的时间乘以periodSeconds时间的值,在这段时间内,容器没有启动,那么就会删除容器。

创建Pod

[root@k8s-master01 ~]# kubectl apply -f /root/nginx/nginx_pod.yaml

四、Pod常用命令

命令 作用
创建pod kubectl create -f ymal文件
查看pod kubectl get pod [-n 名称空间] kubectl get pod -o wide
更新pod kubectl apply -f yaml文件
删除pod kubectl delete pod pod名称
进入pod中的容器 kubectl exec -it pod名称 -- shell
查看pod中容器日志 kubectl logs pod名称 -c 容器名
查看pod标签 kubectl get pod pod名称 --show-labels
修改pod标签 kubectl label pod pod名称 newkey=newvalue
查看标签为app的pod kubectl get pod -l app
查看所有名称空间标签为app的pod kubectl get pod -l app --all-namespaces
查看标签为app,值为myapp的pod kubectl get pod -l app=myapp kubectl get pod -l app=myapp --all-namespaces
查看详细信息 kubectl describe pod pod名称

五、Pod状态

  • 挂起(Pending):我们在请求创建pod时,条件不满足,调度没有完成,没有任何一个节点能满足调度条件,已经创建了pod但是没有适合它运行的节点叫做挂起,调度没有完成,处于pending的状态会持续一段时间:包括调度Pod的时间和通过网络下载镜像的时间。

  • 运行中(Running):Pod已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行。

  • 成功(Succeeded):Pod 中的所有容器都被成功终止,并且不会再重启。

  • 失败(Failed):Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。

  • 未知(Unknown):未知状态,所谓pod是什么状态是apiserver和运行在pod节点的kubelet进行通信获取状态信息的,如果节点之上的kubelet本身出故障,那么apiserver就连不上kubelet,得不到信息了,就会看Unknown

六、排障

常用的排障命令

#查看 Pod 的配置是否正确
[root@k8s-master01 ~]# kubectl get pod <pod-name> -o yaml 
#查看 Pod 的事件
[root@k8s-master01 ~]# kubectl describe pod <pod-name> 
#查看容器日志
[root@k8s-master01 ~]# kubectl logs <pod-name> [-c <container-name>] 
#进入容器查看
[root@k8s-master01 ~]#kubectl exec -it <pod-name>  -- /bin/bash

常见故障归类

1、Pod状态 一直处于 Pending

Pending 说明 Pod 还没有调度到某个 Node 上面。可以通过 kubectl describe pod <pod-name> 命令查看到当前 Pod 的事件,进而判断为什么没有调度。可能的原因包括:
资源不足,集群内所有的 Node 都不满足该 Pod 请求的 CPU、内存、GPU 等资源
HostPort 已被占用,通常推荐使用 Service 对外开放服务端口

2、Pod状态 一直处于 Waiting或者Pod状态 一直处于 ContainerCreating

首先还是通过 kubectl describe pod <pod-name> 命令查看到当前 Pod 的事件。可能的原因包括:
镜像拉取失败,比如配置了镜像错误、Kubelet 无法访问镜像、私有镜像的密钥配置错误、镜像太大,拉取超时等
CNI 网络错误,一般需要检查 CNI 网络插件的配置,比如无法配置 Pod 、无法分配 IP 地址
容器无法启动,需要检查是否打包了正确的镜像或者是否配置了正确的容器参数

3、Pod状态 处于 ImagePullBackOff

这也是我们测试环境常见的,通常是镜像拉取失败。这种情况可以使用 docker pull <image> 来验证镜像是否可以正常拉取。
或者docker images | grep <images>查看镜像是否存在(系统有时会因为资源问题自动删除一部分镜像)

4、Pod状态 处于 CrashLoopBackOff

CrashLoopBackOff 状态说明容器曾经启动了,但可能又异常退出了。此时可以先查看一下容器的日志
kubectl logs --previous
这里可以发现一些容器退出的原因,比如:
容器进程退出
健康检查失败退出

5、Pod状态 处于 Error

通常处于 Error 状态说明 Pod 启动过程中发生了错误。常见的原因包括
依赖的 ConfigMap、Secret 或者 PV 等不存在
请求的资源超过了管理员设置的限制,比如超过了 LimitRange 等
违反集群的安全策略,比如违反了 PodSecurityPolicy 等
容器无权操作集群内的资源,比如开启 RBAC 后,需要为 ServiceAccount 配置角色绑定

6、Pod状态 一直处于 Terminating或者Pod状态 处于 Unknown

从 v1.5 开始,Kubernetes 不会因为 Node 失联而删除其上正在运行的 Pod,而是将其标记为 Terminating 或 Unknown 状态。想要删除这些状态的 Pod 有三种方法:
1)从集群中删除该 Node。使用公有云时,kube-controller-manager 会在 VM 删除后自动删除对应的 Node。而在物理机部署的集群中,需要管理员手动删除 Node(如 kubectl delete node <node-name>。
2)Node 恢复正常。Kubelet 会重新跟 kube-apiserver 通信确认这些 Pod 的期待状态,进而再决定删除或者继续运行这些 Pod。
3)用户强制删除。用户可以执行 kubectl delete pods <pod> --grace-period=0 --force 强制删除 Pod。除非明确知道 Pod 的确处于停止状态(比如 Node 所在 VM 或物理机已经关机),否则不建议使用该方法。
特别是 StatefulSet 管理的 Pod,强制删除容易导致脑裂或者数据丢失等问题。

7、Pod状态 处于 Evicted

出现这种情况,多见于系统内存或硬盘资源不足,可df-h查看docker存储所在目录的资源使用情况,如果百分比大于85%,就要及时清理下资源,尤其是一些大文件、docker镜像。清除状态为Evicted的pod:kubectl get pods | grep Evicted | awk '{print $1}' | xargs kubectl delete pod删除所有状态异常的pod:kubectl delete pods $(kubectl get pods | grep -v Running | cut -d ' ' -f 1)删除集群中没有在使用的docker镜像(慎用):docker system prune -a查看pod对应的服务(镜像)版本:kubectl --server=127.0.0.1:8888 get rc -o yaml | grep image: |uniq | sort | grep ecs-core附:删除某类历史镜像(仅保留当前使用的)docker images | grep ecs-core | grep -v `docker images | grep ecs-core -m 1 | awk '{print $2}'` | awk '{print $3}' | xargs docker rmi -f

常见状态

CrashLoopBackOff                                容器退出,kubelet正在将它重启
InvalidImageName                                无法解析镜像名称
ImageInspectError                                无法校验镜像
ErrImageNeverPul                                策略禁止拉取镜像
ImagePullBackOff                                 正在重试拉取
RegistryUnavailable                              连接不到镜像中心
ErrImagePull                                         通用的拉取镜像出错
CreateContainerConfigError                 不能创建kubelet使用的容器配置
CreateContainerError                           创建容器失败
m.internalLifecycle.PreStartContainer  执行hook报错
RunContainerError                                启动容器失败
PostStartHookError                               执行hook报错
ContainersNotInitialized                        容器没有初始化完毕
ContainersNotReady                            容器没有准备完毕
ContainerCreating                                容器创建中
PodInitializing                             pod 初始化中
DockerDaemonNotReady                    docker还没有完全启动
NetworkPluginNotReady                      网络插件还没有完全启动
Evicted                                  即驱赶的意思,意思是当节点出现异常时,kubernetes将有相应的机制驱赶该节点上的Pod。 多见于资源不足时导致的驱赶。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐