关于运维:Kubernetes资源编排系列之一-Pod-YAML篇

作者:周虚(应金挺)
SREWorks的开源吸引了大量用户来尝试部署和应用咱们的产品,其中不乏一些首次接触Kubernetes的敌人。随着SREWorks云原生运维平台应用的继续深刻,局部用户对于其中的原理和概念还存在一些困惑。因而,咱们特推出 《Kubernetes资源编排系列》 ,从底层的Pod YAML开始,逐渐递进地解说相干内容,心愿可能解答大家对于Kubernetes的一些疑难,让用户对于云原生相干技术有更深刻的理解。

1.Pod整体构造

Pod YAML的整体构造,能够初步分为Resource(资源)、Object(元数据)、Spec(标准)、Status(状态)。 本文将会围绕这四局部一一开展。

  • Resource:定义资源类型与版本, 作为从Rest API中获取资源必带的属性。
  • Object:资源的元数据属性,明确资源的根本标识。
  • Spec / Status:
  1. Spec:定义资源的冀望状态,包含用户提供的配置、零碎扩大的默认值,以及周边零碎初始化或者更改值(scheduler、hpa等)。
  2. Status:定义资源的以后状态,从而基于Spec定义的申明式配置,使pod一直朝冀望状态凑近。

2.Resource(资源)-Rest API

k8s资源依照Scope能够分为Namespace资源、Cluster资源,Namespace在k8s能够认为是软租户的成果,实现资源层面的隔离,Pod资源就是属于Namespace资源,而Namespace不光体现在YAML参数中,也体现在k8s Rest API中。
Rest API的整体构造,以Pod举例

apiVersion: v1
kind: Pod
metadata:
  name: test-pod
  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资源对象都会援用的公共构造,天然也存在很多公共机制供应用。

metadata:
  annotations:
    alibabacloud.com/owner: testdemo
    k8s.aliyun.com/pod-eni: "true"
  creationTimestamp: "2022-06-02T07:21:36Z"
  deleteTimestamp: "2022-06-02T07:22:51Z"
  labels:
    app: taihao-app-cn-shanghai-pre-cloud-resource
    pod-template-hash: 5bbb759f78
  name: testdemo-5bbb759f78-27v88
  namespace: default
  ownerReferences:
  - apiVersion: apps/v1
    blockOwnerDeletion: true
    controller: true
    kind: ReplicaSet
    name: testdemo-5bbb759f78
    uid: 9c3f268a-c0d1-4038-bb2b-b92928f45e3d
  resourceVersion: "60166035"
  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,明确了关联资源的回收流程。

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  generation: 1
  labels:
    app: testdemo
    pod-template-hash: bcd889947
  name: testdemo-bcd889947
  namespace: taihao
  ownerReferences:
  - apiVersion: apps/v1
    blockOwnerDeletion: true
    controller: true
    kind: Deployment
    name: testdemo
    uid: 1dddc849-c254-4cf5-aec8-9e1c2b5e65af
spec:
  replicas: 1
  selector:
    matchLabels:
      app: testdemo
      pod-template-hash: bcd889947
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: testdemo
        pod-template-hash: bcd889947
    spec:
      containers:
      - args:
        - -c
        - sleep 1000000
        command:
        - sh
        image: centos:7
        imagePullPolicy: IfNotPresent
                name: testdemo
status:
  fullyLabeledReplicas: 1
  observedGeneration: 1
  replicas: 1

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

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

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

replicaset.status:replicaset 以后治理Pod的状态

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: testdemo
  name: testdemo
spec:
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: testdemo
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: testdemo
    spec:
      containers:
      - args:
        - -c
        - sleep 1000000
        command:
        - sh
        image: centos:7
        imagePullPolicy: IfNotPresent
        name: testdemo
status:
  availableReplicas: 1
  observedGeneration: 2
  readyReplicas: 1
  replicas: 2
  unavailableReplicas: 1
  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

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申请,次要作用能够作为资源部署以及环境筹备。

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衰弱指标。

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。

5.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"

基于上述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团队进行交换。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理