四、 Spec(规范)
Spec作为Pod的期望状态,一定程度上也覆盖了Pod完整生命周期的逻辑,Pod的生命周期分为以下阶段:
• Pending:代表Pod处于未调度阶段
• Creating:节点上的kubelet已经发现了Pod,处于创建阶段
• Running:至少一个容器运行完毕,kubelet这会发起健康监测
• Terminating:Pod处于删除状态,kubelet开始回收容器
• Terminated:Pod销毁完成
1. Pod生命周期:Pending
Pod资源创建完毕后,处于还未调度阶段,这个时候scheduler(调度器)基于pod yaml本身的配置与节点资源状态情况,来进行调度。
scheduler会去分析PodYAML,将其中的策略提取出来,与节点组中的节点配置进行匹配,若匹配成功后,会选出最佳节点,重新修改pod yaml,将spec.nodeName更新掉,完成整个调度环节。
资源策略
资源策略表明Pod运行需要的资源情况,以demo为例,Pod需要2核4G的资源,那么调度过去的节点也需要有2核4G的资源剩余,Pod才能运行在该节点上。
节点标签筛选策略
节点标签筛选策略,筛选节点是否存在topology.kubernetes.io/region:cn-hangzhou。
亲和策略
亲和策略,有节点亲和与Pod亲和(Pod所在节点优先调度),常规来说可以优先满足亲和的节点上,当前例子就是节点亲和,满足标签disk-type=aaa或者disk-type=bbb。
污点策略
污点策略,当节点上配置了污点,若Pod没有容忍该污点的策略,则Pod不允许调度到该节点上。
2. Pod生命周期:Creating
当Pod调度完毕后,开始创建阶段,Kubelet会基于pod.spec期望状态来创建出Pod;Kubelet在创建Pod阶段,总共大致经历以下过程:
• Group配置:主要是为了容器配置cgroup,里面涉及了对容器资源限制,比如不允许超过cpu、memory配置,这里涉及到Pod的qos级别判定。
• 初始化环境配置:主要是对相关Pod数据存储目录进行配置,涉及到volume,则会去引用CSI协议,也会去获取镜像secret,为了后续拉取镜像进行准备工作。
• 创建pause容器:创建pause容器,该容器主要是为了后续配置容器网络,配置容器网络会去调用CNI。
• 创建Pod容器:基于imagesecret拉取业务镜像,在创建Pod容器阶段,也会将相应的Pod YAML配置传输进去,在启动Pod容器完毕后,会基于poststart进行相关的回调。
上述阶段,会相关选择部分关键概念进行详细说明。
image
spec: containers: - image: testdemo:v1 imagePullPolicy: Always name: test-config imagePullSecrets: - name: image-regsecret
|
imagePullSecrets:拉取镜像的密钥,保证能够拉取image:testdemo:v1,尤其在镜像库是私有库的阶段。
imagePullPolicy:镜像拉取策略。
• Always:总是拉取镜像。
• IfNotPresent:本地若有则使用本地镜像,不进行拉取。
• Never:只使用本地镜像,不拉取。
containers
注意这个containers用的是复数,可以填多个容器镜像:比如可以放nginx和业务容器。这样做的好处是可以尽量减少业务容器中与业务无关的代码或进程。
container涉及很多配置,其中有涉及到volume、env、dnsconfig、host等基础配置。
spec: containers: - env: - name: TZ value: Asia/Shanghai image: testdemo:v1 name: taihao-app-cn-shanghai-pre-share volumeMounts: - mountPath: /home/admin name: test-config readOnly: true dnsConfig: nameservers: - 100.100.1.1 - 100.100.2.1 options: - name: ndots value: "3" - name: timeout value: "3" - name: attempts value: "3" searches: - default.svc.cluster.local - svc.cluster.local - cluster.local hostAliases: - hostnames: - kubernetes - kubernetes.default - kubernetes.default.svc - kubernetes.default.svc.cluster.local ip: 1.1.1.1 volumes: - configMap: defaultMode: 420 name: test-config name: test-config
|
env:配置Pod的环境变量。
dnsConfig:配置Pod的域名解析。
hostALiases:配置/etc/hosts文件内容。
volume/volumeMount:配置文件挂载到容器内,也可以配置文件存储系统挂载到容器内。
postStart
containers: - image: testdemo:v1 imagePullPolicy: Always lifecycle: postStart: exec: command: - /bin/sh - -c - sleep 5
|
当前poststart demo是发起command命令,也可以发起http请求,主要作用可以作为资源部署以及环境准备。
3. Pod生命周期:Running
在Pod running阶段的时候,Pod就迎来对其健康的检查,当前kubelet提供三种方式判定:
• readiness:检查Pod是否为健康。
• liveness:件看Pod是否正常,若检查失败,则重启容器。
• readinessGate:提供给第三方组件健康验证,第三方组件验证不过,则Pod不为健康。
spec: readinessGates: - conditionType: TestPodReady containers: - image: testdemo:v1 imagePullPolicy: Always livenessProbe: failureThreshold: 3 initialDelaySeconds: 45 periodSeconds: 5 successThreshold: 1 tcpSocket: port: 8080 timeoutSeconds: 1 readinessProbe: failureThreshold: 3 httpGet: path: /actuator/health port: 8989 scheme: HTTP initialDelaySeconds: 25 periodSeconds: 3 successThreshold: 1 timeoutSeconds: 1
|
readiness与liveness检查参数都是一致的。
• httpGet/tcpSocket:都是检查方式,一种是http请求验证,一种是tcpSocket,其中也有exec执行命令,以及grpc形式验证。
• initialDelaySeconds:延迟多久开始检查,原因在于容器启动的时候,通常需要过段时间进行验证。
• periodSeconds:检验时间周期。
• failureThreshold:连续几次失败,则代表这轮检验失败。
• successThreshold:连续几次成功,则代表这轮检验成功。
• timeoutSeconds:代表检验超时时间,若检验在该配置时间内没有返回,则认为检验失败。
readiness、liveness虽然参数不一样,但对检验的结果行为不一致。
• readiness默认状态下为false,也就是Pod为不健康,直到检查通过,才将Pod变为健康。
• liveness默认状态下为true,不会在刚开始就将Pod重启,只有等检查不通过后,才会进行容器重启操作。
readinessGate是Pod健康的扩展,kubelet会基于此,默认在pod.status.conditions上配置对应的condition,比如当前例子readinessGate为conditionType:TestPodReady,则相应就会有conditions。
status: conditions: - lastProbeTime: null lastTransitionTime: "2022-07-05T09:16:07Z" status: "false" type: TestPodReady
|
当该condition.status为false时,则Pod就会一直是不健康,哪怕readiness检查通过,直到第三方系统去操作更新Pod该condition.status为true,才可以将Pod变为健康,这样就可以接入更多的Pod健康指标。
4. Pod生命周期:Terminating
client在发起请求删除Pod的时候,实际上是配置pod.metadata.deletionTimestamp,kubelet感知到后,开始进行Pod回收流程
整个Pod的回收周期,常规来说preStop—>SIGTERM—>SIGKILL
lifecycle: preStop: exec: command: - /bin/sh - -c - sleep 5
|
当kubelet进行preStop后,开始发起SIGTERM给容器内进程,若超过总默认耗时30S(metadata.DeletionGracePeriodSeconds),则强制发起SIGKILL给容器,也就是prestop+SIGTERM总耗时不允许超过30s。
五、 Status(状态)
status: conditions: - lastProbeTime: null lastTransitionTime: "2022-07-05T09:16:07Z" status: "True" type: TestPodReady - lastProbeTime: null lastTransitionTime: "2022-07-05T09:16:07Z" status: "True" type: Initialized - lastProbeTime: null lastTransitionTime: "2022-07-05T09:16:14Z" status: "True" type: Ready - lastProbeTime: null lastTransitionTime: "2022-07-05T09:16:14Z" status: "True" type: ContainersReady - lastProbeTime: null lastTransitionTime: "2022-07-05T09:16:07Z" status: "False" type: ContainerDiskPressure - lastProbeTime: null lastTransitionTime: "2022-07-05T09:16:07Z" status: "True" type: PodScheduled containerStatuses: - containerID: containerd://xxxxx image: docker.io/library/testdemo:v1 imageID: docker.io/library/centos@sha256:xxxx lastState: {} name: zxtest ready: true restartCount: 0 started: true state: running: startedAt: "2022-07-05T09:16:13Z" hostIP: 21.1.96.23 phase: Running podIP: 10.11.17.172 podIPs: - ip: 10.11.17.172 qosClass: Guaranteed startTime: "2022-07-05T09:16:07Z"
|
基于上述,将Pod status状态拆建出来:
• Conditions:conditions是作为一种更详尽的状态报告,其本身也是一种扩展机制,其他的扩展字段也可以放入其中,比如可以表明网络状况,其中readinessGate就是这种扩展机制的表现,但决定Pod是否ready,永远只看type:Ready是否为true。
• containerStatuses:Pod内各容器的状态。
• hostIP:Pod所在节点ip地址。
• phase:Pod的生命周期状态:
。 Pending:代表Pod有一个容器或者多个容器还未运行,其中包括Pod调度到节点之前以及拉取镜像。
。 Running:代表Pod已绑定到节点上,至少有一个容器运行或在重启。
。 Successed:代表Pod所有容器已终止。
。 Failed:代表Pod内至少有一个容器终止失败。
。 Unknown:代表无法获取Pod状态。
• podIP/podIPs:Pod的IP地址,假如有ipv4、ipv6,则可以在podIPs上配置。
• qosClass:代表kubernetes服务等级:
。 Guaranteed:resource.requests与resource.limits一致。
。 Burstable:resource.requests与resource.limits不一致。
。 BestEffort:没有配置resource.requests与resource.limits。
• startTime:启动时间
通过对Pod四个部分拆解,我们基本搞清了一个Pod在k8s下的“从哪里来”这个问题。本系列的后续的文章会对“到哪里去”这个问题继续展开:Kubernetes的魅力在于不仅仅是拉起一个工作负载,而是能够召之即来挥之即去地编排海量工作负载。