当前位置:   article > 正文

Kubernetes资源编排系列之一: Pod YAML篇_yaml resource

yaml resource

作者:周虚(应金挺)

SREWorks的开源吸引了大量用户来尝试部署和使用我们的产品,其中不乏一些初次接触Kubernetes的朋友。随着SREWorks云原生运维平台使用的持续深入,部分用户对于其中的原理和概念还存在一些困惑。因此,我们特推出 《Kubernetes资源编排系列》 ,从底层的Pod YAML开始,逐步递进地讲解相关内容,希望能够解答大家对于Kubernetes的一些疑问,让用户对于云原生相关技术有更深入的了解。

1.Pod整体结构

Pod YAML的整体结构,可以初步分为Resource(资源)、Object(元数据)、Spec(规范)、Status(状态)。 本文将会围绕这四部分一一展开。

  • Resource:定义资源类型与版本, 作为从Rest API中获取资源必带的属性。
  • Object:资源的元数据属性,明确资源的基本标识。
  • Spec / Status:
    • Spec:定义资源的期望状态,包括用户提供的配置、系统扩展的默认值,以及周边系统初始化或者更改值(scheduler、hpa等)。

    • Status:定义资源的当前状态,从而基于Spec定义的申明式配置,使pod不断朝期望状态靠近。

2.Resource(资源)-Rest API

k8s资源按照Scope可以分为Namespace资源、Cluster资源,Namespace在k8s可以认为是软租户的效果,实现资源层面的隔离,Pod资源就是属于Namespace资源,而Namespace不光体现在YAML参数中,也表现在k8s Rest API中。

Rest API的整体结构,以Pod举例

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: test-pod
  5. namespace: default

基于上述YAML,可以明确出namespace为default, name为test-pod的Pod资源对象,也就是明确出Pod为Namespace资源,该Pod资源对象对应的apiVersion为v1,后续k8s自内联相关的Group为/api,自然而然,我们就将该对象的数据分离出来了:

  • group:api
  • apiVersion:v1
  • kind:Pod
  • name:test-pod
  • namespace:default

基于上述的数据展示,apiserver自然而然会相应的注册出下列rest api,

  • /api/{apiVersion}/{kind}:该kind下的所有资源列表
  • /api/{apiVersion}/namespace/{namespace}/{kind}/:该kind下当前namespace的所有资源列表
  • /api/{apiVersion}/namespace/{namespace}/{kind}/{name}:该kind下当前namespace且名为name的资源
  • /api/{apiVersion}/namespace/{namespace}/{kind}/{name}/{subresource}:该kind下当前namespace且名为name的资源下子资源操作

后续基于扩展,我们就需要明确出method,这样一个真正完整的Rest API就诞生了。

3.Object(元数据)

在rest api中明确了Resource的kind、apiVersion, 也确定了Object的namespace、name,作为凡是k8s资源对象都会引用的公共结构,自然也存在很多公共机制供使用。

  1. metadata:
  2. annotations:
  3. alibabacloud.com/owner: testdemo
  4. k8s.aliyun.com/pod-eni: "true"
  5. creationTimestamp: "2022-06-02T07:21:36Z"
  6. deleteTimestamp: "2022-06-02T07:22:51Z"
  7. labels:
  8. app: taihao-app-cn-shanghai-pre-cloud-resource
  9. pod-template-hash: 5bbb759f78
  10. name: testdemo-5bbb759f78-27v88
  11. namespace: default
  12. ownerReferences:
  13. - apiVersion: apps/v1
  14. blockOwnerDeletion: true
  15. controller: true
  16. kind: ReplicaSet
  17. name: testdemo-5bbb759f78
  18. uid: 9c3f268a-c0d1-4038-bb2b-b92928f45e3d
  19. resourceVersion: "60166035"
  20. uid: e4236960-8be2-41bf-ac44-e7460378afbb

观察上述YAML,我们将其整理一下,有这样一些字段: 

  • namespace:常规来说,Namespace资源才会使用该资源对象
  • name:代表资源实例名称
  • uid:是资源的唯一标识,可以区别已删除与重新创建的同名资源实例
  • resourceVersion:是k8s的内部版本,具备时间属性,基于此就能明确该资源对是什么时候发生改变的,也是保证k8s list-watch核心机制
  • creationTimestamp: 资源实例创建时间
  • deleteTimestamp: 资源实例删除时间,后续会在pod的生命周期内讲到对该字段应用
  • ownerReferences: 资源从属对象,从上面yaml可知,该Pod资源从属于名为testdemo-5bb759f78, ownerReferences内部是没有namespace参数,也就是ownerReferences不允许跨namespace, 将资源由下到上能够建立起来
  • labels :标签, k8s内的服务发现以及相应的软关联,都是围绕label运作的,比如testdemo-5bb759f78 replicaset 的labelselector(标签筛选器)能够筛选到当前Pod的label,保证两者关联由上到下的建立
  • annotations: 注释,通常来说会是作为额外字段供应给周边系统使用,比如当前k8s.aliyun.com/pod-eni="true"是提供网络系统使用

label & labelSelector

Deployment 会根据自己的labelseletor:app=taihao-app-cluster 以及计算出podtemplate的hash lable:pod-template-hash: 5b8b879786 , 筛选出出符合的replicaset, replicaset再根据自己的labelselector 去筛选出符合的pods, 相应的服务发现service,也是通过labelselector去筛选出符合的Pod

Owner & GC(垃圾回收)

基于Pod的metadata.ownerReferences找寻到对应的replicaset,replicaset基于自身的metadata.ownerReferences 找寻到deploy;当deployment被删除后,基于原有owner构建的树状,回收原有的rs与pod。

Deploy & Replicaset

基于label&labelselector,明确了从上到下的筛选归纳;基于owner&GC,明确了关联资源的回收流程。

  1. apiVersion: apps/v1
  2. kind: ReplicaSet
  3. metadata:
  4. generation: 1
  5. labels:
  6. app: testdemo
  7. pod-template-hash: bcd889947
  8. name: testdemo-bcd889947
  9. namespace: taihao
  10. ownerReferences:
  11. - apiVersion: apps/v1
  12. blockOwnerDeletion: true
  13. controller: true
  14. kind: Deployment
  15. name: testdemo
  16. uid: 1dddc849-c254-4cf5-aec8-9e1c2b5e65af
  17. spec:
  18. replicas: 1
  19. selector:
  20. matchLabels:
  21. app: testdemo
  22. pod-template-hash: bcd889947
  23. template:
  24. metadata:
  25. creationTimestamp: null
  26. labels:
  27. app: testdemo
  28. pod-template-hash: bcd889947
  29. spec:
  30. containers:
  31. - args:
  32. - -c
  33. - sleep 1000000
  34. command:
  35. - sh
  36. image: centos:7
  37. imagePullPolicy: IfNotPresent
  38. name: testdemo
  39. status:
  40. fullyLabeledReplicas: 1
  41. observedGeneration: 1
  42. replicas: 1

replicaset.spec.replicas: 实例数,rs控制下的Pod个数

replicaset.spec.selector:基于label 筛选出对应的Pod

replicaset.spec.template:replicaset创建的Pod会基于podtemplate

replicaset.status:replicaset 当前管理Pod的状态

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. labels:
  5. app: testdemo
  6. name: testdemo
  7. spec:
  8. replicas: 1
  9. revisionHistoryLimit: 10
  10. selector:
  11. matchLabels:
  12. app: testdemo
  13. strategy:
  14. rollingUpdate:
  15. maxSurge: 25%
  16. maxUnavailable: 25%
  17. type: RollingUpdate
  18. template:
  19. metadata:
  20. creationTimestamp: null
  21. labels:
  22. app: testdemo
  23. spec:
  24. containers:
  25. - args:
  26. - -c
  27. - sleep 1000000
  28. command:
  29. - sh
  30. image: centos:7
  31. imagePullPolicy: IfNotPresent
  32. name: testdemo
  33. status:
  34. availableReplicas: 1
  35. observedGeneration: 2
  36. readyReplicas: 1
  37. replicas: 2
  38. unavailableReplicas: 1
  39. updatedReplicas: 1

deploy.spec.replicas: deploy期望的pod实例格式

deploy.spec.revisionHistoryLimit:deploy 管理replicaset的保留三个月

deploy.spec.selector:deploy 筛选符合标签

deploy.spec.strategy:deploy的升级策略

deploy.template:deploy基于此模版要创建的pod格式

4.Spec(规范)

Spec作为Pod的期望状态,一定程度上也覆盖了Pod完整生命周期的逻辑,Pod的生命周期分为以下阶段

  • Pending:代表Pod处于未调度阶段
  • Creating:节点上的kubelet已经发现了Pod,处于创建阶段
  • Running:至少一个容器运行完毕,kubelet这会发起健康监测
  • Terminating:Pod处于删除状态,kubelet开始回收容器
  • Terminated: Pod 销毁完成

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不允许调度到该节点上

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

  1. spec:
  2. containers:
  3. - image: testdemo:v1
  4. imagePullPolicy: Always
  5. name: test-config
  6. imagePullSecrets:
  7. - name: image-regsecret

imagePullSecrets: 拉取镜像的密钥,保证能够拉取image:testdemo:v1,尤其在镜像库是私有库的阶段

imagePullPolicy:镜像拉取策略

  • Always:总是拉取镜像
  • IfNotPresent:本地若有则使用本地镜像,不进行拉取
  • Never:只使用本地镜像,不拉取

containers

注意这个containers用的是复数,可以填多个容器镜像: 比如可以放 nginx 和 业务容器。这样做的好处是可以尽量减少业务容器中与业务无关的代码或进程。

container涉及很多配置,其中有涉及到volume、env、dnsconfig、host等基础配置

  1. spec:
  2. containers:
  3. - env:
  4. - name: TZ
  5. value: Asia/Shanghai
  6. image: testdemo:v1
  7. name: taihao-app-cn-shanghai-pre-share
  8. volumeMounts:
  9. - mountPath: /home/admin
  10. name: test-config
  11. readOnly: true
  12. dnsConfig:
  13. nameservers:
  14. - 100.100.1.1
  15. - 100.100.2.1
  16. options:
  17. - name: ndots
  18. value: "3"
  19. - name: timeout
  20. value: "3"
  21. - name: attempts
  22. value: "3"
  23. searches:
  24. - default.svc.cluster.local
  25. - svc.cluster.local
  26. - cluster.local
  27. hostAliases:
  28. - hostnames:
  29. - kubernetes
  30. - kubernetes.default
  31. - kubernetes.default.svc
  32. - kubernetes.default.svc.cluster.local
  33. ip: 1.1.1.1
  34. volumes:
  35. - configMap:
  36. defaultMode: 420
  37. name: test-config
  38. name: test-config

env:配置Pod的环境变量

dnsConfig:配置Pod的域名解析

hostALiases:配置/etc/hosts文件内容

volume/volumeMount: 配置文件挂载到容器内,也可以配置文件存储系统挂载到容器内

postStart

  1. containers:
  2. - image: testdemo:v1
  3. imagePullPolicy: Always
  4. lifecycle:
  5. postStart:
  6. exec:
  7. command:
  8. - /bin/sh
  9. - -c
  10. - sleep 5

当前poststart demo 是发起command命令,也可以发起http请求,主要作用可以作为资源部署以及环境准备。

Pod生命周期: Running

在Pod running阶段的时候,Pod就迎来对其健康的检查,当前kubelet 提供三种方式判定

  • readiness:检查Pod是否为健康
  • liveness:件看Pod是否正常,若检查失败,则重启容器
  • readinessGate:提供给第三方组件健康验证,第三方组件验证不过,则Pod不为健康
  1. spec:
  2. readinessGates:
  3. - conditionType: TestPodReady
  4. containers:
  5. - image: testdemo:v1
  6. imagePullPolicy: Always
  7. livenessProbe:
  8. failureThreshold: 3
  9. initialDelaySeconds: 45
  10. periodSeconds: 5
  11. successThreshold: 1
  12. tcpSocket:
  13. port: 8080
  14. timeoutSeconds: 1
  15. readinessProbe:
  16. failureThreshold: 3
  17. httpGet:
  18. path: /actuator/health
  19. port: 8989
  20. scheme: HTTP
  21. initialDelaySeconds: 25
  22. periodSeconds: 3
  23. successThreshold: 1
  24. 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

  1. status:
  2. conditions:
  3. - lastProbeTime: null
  4. lastTransitionTime: "2022-07-05T09:16:07Z"
  5. status: "false"
  6. type: TestPodReady

当该condition.status为false时,则Pod就会一直是不健康,哪怕readiness检查通过,直到第三方系统去操作更新Pod该condition.status为true,才可以将Pod变为健康,这样就可以接入更多的Pod健康指标。

Pod生命周期: Terminating

client 在发起请求删除Pod的时候,实际上是配置

pod.metadata.deletionTimestamp,kubelet感知到后,开始进行Pod回收流程

整个Pod的回收周期,常规来说preStop—>SIGTERM—>SIGKILL

  1. lifecycle:
  2. preStop:
  3. exec:
  4. command:
  5. - /bin/sh
  6. - -c
  7. - sleep 5

当kubelet进行preStop后,开始发起SIGTERM给容器内进程,若超过总默认耗时30S(metadata.DeletionGracePeriodSeconds),则强制发起SIGKILL给容器,也就是prestop+SIGTERM总耗时不允许超过30s。

5.Status(状态)

  1. status:
  2. conditions:
  3. - lastProbeTime: null
  4. lastTransitionTime: "2022-07-05T09:16:07Z"
  5. status: "True"
  6. type: TestPodReady
  7. - lastProbeTime: null
  8. lastTransitionTime: "2022-07-05T09:16:07Z"
  9. status: "True"
  10. type: Initialized
  11. - lastProbeTime: null
  12. lastTransitionTime: "2022-07-05T09:16:14Z"
  13. status: "True"
  14. type: Ready
  15. - lastProbeTime: null
  16. lastTransitionTime: "2022-07-05T09:16:14Z"
  17. status: "True"
  18. type: ContainersReady
  19. - lastProbeTime: null
  20. lastTransitionTime: "2022-07-05T09:16:07Z"
  21. status: "False"
  22. type: ContainerDiskPressure
  23. - lastProbeTime: null
  24. lastTransitionTime: "2022-07-05T09:16:07Z"
  25. status: "True"
  26. type: PodScheduled
  27. containerStatuses:
  28. - containerID: containerd://xxxxx
  29. image: docker.io/library/testdemo:v1
  30. imageID: docker.io/library/centos@sha256:xxxx
  31. lastState: {}
  32. name: zxtest
  33. ready: true
  34. restartCount: 0
  35. started: true
  36. state:
  37. running:
  38. startedAt: "2022-07-05T09:16:13Z"
  39. hostIP: 21.1.96.23
  40. phase: Running
  41. podIP: 10.11.17.172
  42. podIPs:
  43. - ip: 10.11.17.172
  44. qosClass: Guaranteed
  45. startTime: "2022-07-05T09:16:07Z"

基于上述YAML样例,将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的魅力在于不仅仅是拉起一个工作负载,而是能够召之即来挥之即去地编排海量工作负载。

后续文章均会发布在我们的公众号“阿里智能运维”上,请大家持续关注~也欢迎大家在公众号后台留言想了解的内容和感兴趣的相关话题,与SREWorks团队进行交流。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/613981
推荐阅读
相关标签
  

闽ICP备14008679号