kubernetes 官方文档整理,k8s入门教程笔记整理---6、Pod

8 Pod

8.1 Pod

  • Pod是k8s中创建和管理得、最小的可部署计算单元
  • Pod是一组容器;这些容器共享存储、网路、声明。在共享得上下文中运行(命名空间、控制组),特定于应用得“逻辑主机”。除了应用容器还可以包含init容器。Init 容器会在启动应用容器之前运行并完成。
  • Pod通常不直接创建,而是通过使用工作负载资源创建得。对于单个容器得pod,pod可以看作容器的包装器;对于多容器的pod,pod封装由多个紧密耦合且需要共享资源的容器组成
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80
  • 很少在k8s直接创建pod,一般间接的由控制器创建,被调度在集群的节点上运行,直到pod结束执行、pod对象被删除、因资源不足被驱逐、节点失效为止
  • pod操作系统 .spec.os.name,取windows或linux,目前k8s仅支持这两种
  • pod和控制器 使用工作负载来创建和管理多个pod。deployment、statefulset、daemonset
  • pod模板,通常工作负载使用pod模板(PodTemplate)来创建pod并管理他们
apiVersion: batch/v1
kind: Job
metadata:
  name: hello
spec:
  template:
    # 这里是 Pod 模板
    spec:
      containers:
      - name: hello
        image: busybox:1.28
        command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
      restartPolicy: OnFailure
    # 以上为 Pod 模板
  • kubelet并不直接检测或管理pod模板相关的细节
  • pod共享存储,pod可以设置一组共享的存储卷,pod中所有容器都可访问该共享卷,从而允许容器共享数据
  • pod联网,每个pod在每个地址族获得一个唯一的IP地址。pod中每个容器共享网络ns,包括IP地址、网络端口。pod内的容器可以通过localhost通信
    在一个pod内,他们也能通过SystemV信号量和POSIX共享内存这类标准的进程间通信方式互相通信。
  • 静态pod,直接由kubelet管理,不需要APIServer看到他们,失效时由kubelet重启。静态pod不能引用其他API对象
  • 容器探针 Probe,由kubelet对容器进行定期诊断。ExecAction(容器运行时执行)、TCPSocketAction(kubelet执行)、HTTPGetActionkubelet执行()

8.2 Pod的生命周期

Pod起始于Pending阶段,如果至少有一个主要容器正常启动,则进入Running,之后取决于pod中是否由容器以失败状态结束而进入Succeed或Failed阶段
kubelet能够重启容器以处理一些失效场景。在k8s API中,Pod包含规约部分和实际状态部分,还包含了Conditions。

8.2.1 Pod生命周期

  • Pod被认为是相对临时性的实体,Pod会被创建、赋予一个唯一的ID—UID,并被调度到节点,在pod终止或删除之前一直运行在该节点
  • 如果节点down掉了,调度到该节点的pod也被计划在给定超时期限后被删除
  • Pod没有自愈能力。k8s使用一种高级抽象来管理Pod实例–控制器。在通过控制器删除并重建pod时,UID会发生改变,代表是一个全新的pod
  • Pod阶段,Pod的status中包含一个phase,代表生命周期的阶段
    • Pending—悬决:Pod被k8s系统接收,但是有一个或多个容器尚未创建。此阶段包括等待Pod被调度的时间和下载镜像的时间
    • Running—运行中:Pod已经绑定到了某个节点,Pod中所有容器被创建。至少有一个容器处于运行、启动、重启的状态
    • Succeeded—成功:Pod中容器已经成功终止,不会重启,常见于job中
    • Failed—失败:Pod中所有容器已终止,至少有一个容器因为失败终止。也就是说,容器以非0状态退出或被系统终止
    • Unkonwn—未知:因为某些原因无法取得Pod的状态。通常是因为Pod所在主机通信失败

    比较特殊的Terminating(终止)。这个并不是Pod阶段之一,他被赋予一个体面终止的期限,默认为30s。可以用–force来强制终止Pod

  • 容器状态,k8s会跟踪pod中每个容器的状态,可以用容器生命之前回调来在容器生命周期特定时间点触发事件。一旦调度器将Pod分派给某个节点,kubelet通过容器运行时开始为Pod创建容器,
    容器状态有三种,可以通过kubectl describe pod 来查看
    • Waiting—等待:处于waiting状态的容器仍在运行它完成启动所需的操作,Reason字段给出了等待的原因
    • Running—运行中:标识容器正在执行并没有问题发生。如果配置了postStart,那么该回调已完成。
    • Terminated—已终止:已经开始正在结束或因为某些原因失败,如果配置了preStop,会在Terminated之前执行

8.2.2 容器重启策略

Pod的spec包含一个restartPolicy字段,取值为Always(默认)、OnFailure、Never。
仅针对于kubelet的容器重启动作,当pod中的容器退出时,kubelet会按指数回退方式计算重启的延迟(10s、20s、40s),最长为5分钟
一旦某容器执行了10分钟没出现问题,kubelet对该容器的重启回退倒计时执行重置操作。

8.2.3 Pod状况

status.conditions数组里包含了一些状况的测试

status:
  conditions:
  - lastProbeTime: null
    lastTransitionTime: "2023-08-10T09:34:14Z"
    status: "True"
    type: Initialized #所有Init容器已完成
  - lastProbeTime: null
    lastTransitionTime: "2023-08-17T03:06:02Z"
    status: "True"
    type: Ready #Pod可以为请求提供服务,并且已经添加到对应服务的负载均衡池中
  - lastProbeTime: null 
    lastTransitionTime: "2023-08-17T03:06:02Z"
    status: "True"
    type: ContainersReady #Pod中所有容器已就绪
  - lastProbeTime: null
    lastTransitionTime: "2023-08-10T09:34:14Z"
    status: "True"
    type: PodScheduled #Pod已被调度到某节点
    #还有PodHasNetwork 这个代表Pod沙箱被成功创建并配置了网络(Alpha特性,必须被显示启用)
  - lastProbeTime: 上次探测pod状态的时间戳
    lastTransitionTime: Pod上次状态转换的时间戳
    status: 状态是否适用取True False Unkonwn
    reason: 机器可读的、驼峰编码的文字,表述上次状况变化的原因
    message: 人类可读的,给出上次状态转换的详细信息
    type: PodScheduled #Pod已被调度到某节点

8.2.4 Pod就绪态

你的应用可以向PodStatus中注入外的反馈或信号:Pod Readiness。设置Pod spec的readinessGates列表,为kubelet提供一组额外的状况工期评估Pod就绪态
就绪状态:Pod中所有容器都已就绪、readinessGates中所有状况都为True值

8.2.4.1 Pod网络就绪 PodHasNetwork

在Pod被调度到某节点后–>被kubelet接受并挂载所需的卷—>kubelet和容器运行时(使用CRI)为pod生成运行时沙箱并配置网络—>(启用了PodHasNetworkCondition会修改PodHasNetwork来报告Pod状态)—>kubelet拉取容器镜像和创建容器
PodHasNetwork为false,可能由于pod早期,kubelet还没开始使用容器运行时设置沙箱或在Pod生命周期末期,节点重启Pod未被驱逐。

  • 对于带有init容器的pod,kubelet会在init容器完成后更新Initialized为true(发生在运行时成功创建沙箱和配置网络后)
  • 对于没有init容器的pod,kubelet会在创建沙箱和配置网络前将Initialized设为true
8.2.4.2 Pod调度就绪态 Pod schedulingGates

通过Pod的.spec.schedulingGates来控制Pod是否进入调度就绪态
schedulingGates,为一个字符串列表,每个字符串文字都被视为Pod在被认可调度之前应满足的标准。

apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  schedulingGates:
  - name: foo
  - name: bar
  containers:
  - name: pause
    image: registry.k8s.io/pause:3.6
8.2.4.3 容器探针

probe是由kubelet对容器执行的定期判断。有四种机制可以用来检查容器

四种机制

  • exec 在容内执行指定命令。命令返回码为0则认定成功。特殊的,该种探针涉及创建、复制多个进程,有可能增加CPI负载
  • grpc 使用gRPC执行远程调用。目标应该实现gRPC健康检查。响应为SERVING则判定成功
  • httpGet 对容器所在IP地址指定端口和路径执行HTTP GET亲贵,响应码为200~400,不包括400,则认定成功
  • tcpSocket 对容器的IP地址指定端口执行TCP检查,端口打开,则认定成功

结果

  • Success:通过
  • Failure:失败
  • Unkonwn:未知,不采取行动

三种探针类型

  • livenessProbe 存活探针,代表容器是否正在运行。如果检测失败,那么kubelet会杀死容器。
    容器种进程在遇到问题或不健康的情况下自行崩溃,那么就不必要提供存活探针,kubelet将根据重启策略自行修复
  • readinessProbe 就绪探针,代表容器是否准备好提供服务。如果就绪探针失败,那么端点控制器将从与Pod匹配的所有服务端点列表删除该Pod的IP地址。
    如果要尽在探测成功才开始向Pod发送请求流量,那么需要使用就绪探针。希望容器能够自行进入维护状态。对后端服务有严格的依赖性,可以同时实现存活和就绪探针。
  • startupProbe 启动探针,代表容器中的应用是否已经启动。在启动探针检测时其他探针会被静默,如果启动探针未通过,则kubelet也会杀死容器
    如果你的容器需要在启动期间加载大型数据、配置文件或执行迁移,也就是说需要较长时间才能完成启动的Pod来说,需要使用启动探针 ,启动时间超过intialDelaySeconds + failureThreshold * periodSeconds
8.2.4.4 Pod的终止

pod代表的其实是在节点上运行的进程,当你请求删除Pod时,集群会记录并追踪Pod的体面终止。
通常情况下,容器运行时发送一个TERM信号到每个容器的主进程。一旦超过体面终止期限,容器运行时会向所有剩余进程发送KILL信号
之后Pod将从APIServer上移除

示例

  • 1、使用kubelet手动删除pod,pod的体面终止期限默认是30秒
  • 2、APIServer种的Pod更新,记录Pod最终终止时间。此时Pod显示为Terminating状态。
  • 3、kubelet看到终止时间,那么执行关闭pod。如果定义了preStop,会先回调该逻辑,接下来触发容器运行时发送TERM信号给每个容器中的进程
  • 4、在kubelet启动Pod和体面关闭逻辑的同时,会找到Pod关联的Service,并从相应的Endpoint移除
  • 5、超出宽限期限,kubelet触发强制关闭过程。容器运行时会向Pod所有容器内仍在运行的进程发送SIGKILL信号。kubelet也会清理隐藏的pause容器
  • 6、kubelet将Pod转换到终止阶段,kubelet触发从APIServer删除Pod对象的逻辑,并设置体面终止期限为0
8.2.4.5 强制终止Pod

强制删除可能会带来某种破坏,默认情况所有删除操作都有30秒的宽限期限,kubelet delete支持–grace-period=。如果为0代表宽限时间为0秒
加上–force,代表立即强制删除,如果Pod仍运行于某节点上,强制删除操作将会触发kubelet立即执行清理操作

8.2.4.5 Pod的垃圾收集

对于已失败的Pod来说,API对象仍然会留在APIServer上,Pod的垃圾收集器(PodGC)是控制平面的控制器,
会在Pod个数超出所配置的阈值时删除已终止的Pod(Succeed或Failed状态)
此外PodGC会清理以下Pod

  • 1、孤儿Pod - 绑定到不存在的节点
  • 2、计划外终止的Pod
  • 3、终止过程中的Pod,当启用NodeOutOfServiceVolumnDetach特性门控时,绑定到有node.kubernetes.io/out-of-service污点的未就绪节点
    若启用PodDisruptionConditions特性门控,在清理Pod的同时,如果处于非终止状态,PodGC也会将他们标记为失败。在清理孤儿Pod时还会添加Pod干扰状况

8.3 Init 容器

  • 一种特殊容器,在Pod内的应用容器启动之前运行,主要特点是总是能运行到完成。可以用于包含一些应用镜像中不存在的实用工具和安装脚本
  • init容器可以有多个,如果是多个init容器,那么按照定义的顺序执行,每个都必须在下一个启动之前完成
  • 当Init容器失败时,kubelet会不断重启该Init容器直到运行成功。如果restartPolicy为Never,Init容器失败,那么Pod为失败
  • 为Pod设置Init容器需要在PodSpec中添加initContainers字段,在statusContainerStatues展示状态
  • init容器支持普通应用容器的全部字段和特性,包括资源限制、数据卷、安全特性等,但不支持lifecycle、探针

8.3.1 使用Init容器

特点:

  • 1、Init容器可以包含工具或个性化代码,例如sed、awk、python等工具,而不用FROM一个新镜像
  • 2、Init容器能以不同的文件系统视图运行,因此可以赋予访问应用容器不能访问的Secret权限
  • 3、由于Init容器必须在应用容器启动前运行完成,因此Init容器提供了一种机制来阻塞或延迟应用容器启动。之后应用容器会并行启动
  • 4、init容器可以安全的运行实用程序或自定义代码

示例:

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app.kubernetes.io/name: MyApp
spec:
  containers:
  - name: myapp-container
    image: busybox:1.28
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
  initContainers:
  - name: init-myservice
    image: busybox:1.28
    command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
  - name: init-mydb
    image: busybox:1.28
    command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]

8.3.2 具体行为

在Pod启动过程中,每个Init容器都会在网络和数据卷初始化后由kubelet按顺序启动—>init容器启动或运行失败,会根据restartPolicy策略重试
—>在Init容器全部未成功前,Pod不会变成Ready状态—>Pod重启,init容器重新执行。

8.3.3 容器内的资源共享

  • init容器上定义的limit或request的最大值,作为Pod有效初始request/limit。未指定代表无限制
  • Pod有效QoS层,和Init容器和应用容器的一样

8.4 干扰(Disruptions)

8.4.1 自愿干扰和非自愿干扰

Pod不会消失,除非有人(控制器或用户)将其销毁,或者出现了不可避免的软硬件错误
非自愿干扰:不可避免的情况,例如:节点硬件故障,删除虚拟机、内核错误、节点消失、节点资源不足导致Pod被驱逐
自愿干扰:手动操作或控制器操作,例如:删除deploy、更新deploy、直接删除pod、drain节点、hpa扩缩

8.4.2 减轻非自愿干扰

确保pod有充足的资源,使用多副本负载,使用反亲和性或跨区域扩展应用。

8.4.3 干扰预算

可以为每个应用创建一个PDB(PodDisruptionBudget),PDB将限制宕机的Pod数量,代表可以容忍的最小副本数量

8.4.4 Pod干扰状况

特性门控:启用PodDisruptionConditions,启用后会给Pod添加一个DisruptionTarget,用来表明Pod因干扰被删除,reason中包括

  • PreemptionByScheduler Pod被调度器抢占,目的是接受优先级更高的新Pod
  • DeletionByTaintManager Pod不能容忍NoExecute污点而被控制器删除
  • EvictionByEvictionAPI Pod已被标记为通过k8s API驱逐
  • DeletionByPodGC 绑定到不再存在的Pod被Pod垃圾收集清除
  • TerminationByKubelet Pod由于节点压力驱逐或节点体面关闭而被kubelet终止

8.5 临时容器

临时容器是:一种特殊的容器,在现有Pod中临时运行,以便完成用户发起的操作,例如故障排查。
因为Pod是一次性且可替换的,Pod一旦创建就无法将容器加入到Pod中。
临时容器的特点

  • 临时容器和其他容器的不同之处在于,缺少对资源或执行的保证,永远不会自动重启。
  • 用ContainerSpec描述,许多字段不兼容,端口配置不支持例如port、存活探针、就绪探针等;不支持资源预留和限制等。
  • 临时容器是使用API中的一种特殊的ephemeralcontainers处理器进行创建的,而不是直接添加到pod.spec上,因此不能直接kubectl edit来添加临时容器
  • 将临时容器添加到Pod后,将不能修改或删除临时容器
    使用临时容器来调试 kubectl debug -it nginx --image=busybox:1.28 --target=nginx
    –target 参数指定另一个容器的进程命名空间

8.6 Pod QoS 类

服务质量Qos类,k8s根据为Pod中的容器指定的资源约束为每个Pod设置QoS类,
k8s依赖这种分类决定优先驱逐哪些Pod,主要基于资源请求和限制。
可选的QoS类为BestEffort(优先驱逐)、Burstable(其次)、Guaranteed(最后驱逐)

  • BestEffort : Pod中所有容器都没内存limit、内存request、CPU limit、CPU request。
  • Burstable : Pod中至少有一个容器指定了request或limit
  • Guaranteed : Pod中每个容器都必须有内存limit、request,cpu limit request。并且内存limit==内存request。cpu limit == cpu request

独立于k8s的QoS类

  • 所有超过limit的容器都会被kubelet杀死并重启,但是不会重启pod,只会重启容器
  • 容器超出了request,所在节点面临资源压力,那么该pod会被成为驱逐的候选对象。
  • Pod的request等于容器request的和,Pod的limit等于容器limit的和
  • kube-scheduler选择要抢占的Pod时不考虑QoS。抢占是当集群没有足够的资源来运行Pod时会发生抢占

8.7 用户命名空间

用户命名空间将容器内运行的用户和主机的用户隔离开来。用户在容器内拥有较高权限,但是在主机没有操作特权,可以用来防止节点被Pod破坏,防止容器逃逸。

用户命名空间是一个linux功能,允许将容器中的用户映射到主机的不通用户,Pod通过pod.spec.hostUsers设置为false来选择使用用户命名空间

kubelet将挑选Pod所映射的主机UID/GID,pod.spec的runAsUser、runAsGroup、fsGroup总是指的是容器内的用户,UID/GID在0~65535内。

创建Pod时,默认会使用几个新的命名空间进行隔离:一个网络命名空间来隔离容器网络,一个PID命名空间来隔离进程视图,一个用户命名空间隔离容器中的用户和节点的用户。

限制:
当Pod使用用户命名空间时,不允许Pod使用其他主机命名空间,如果你设置了hostUsers:false
那么你不能设置hostNetwork: true、hostIPC: true、hostPID: true,
如果使用卷,只能使用以下卷类型:configmap、secret、projected、downwardAPI、emptyDir

示例: 你需要节点的操作系统为Linux、启用UserNamespacesSupport特性门控

apiVersion: v1
kind: Pod
metadata:
  name: userns
spec:
  hostUsers: false
  containers:
  - name: shell
    command: ["sleep", "infinity"]
    image: debian

8.8 Downward API

Downward API 允许容器在不使用k8s客户端或API服务器的情况下获得自己或集群的信息。
例如想获取Pod或容器字段,有两种方法:

  • 1、作为环境变量
  • 2、在位downwardAPI卷中的文件。这两种方式统称为Downward API

可用字段

只有部分k8s API字段可以通过Downward API使用。

  • 使用fieldRef传递Pod级字段的信息。
    • 以下字段环境变量,downwardAPI卷都可使用
      • metadata.name pod的名称
      • metadata.namespace pod的ns
      • metadata.uid pod的uid
      • metadata.annotations[‘’] pod的某个注解的值 例如 metadata.annotation[‘myanno’]
      • metadata.labels[‘’] pod的某个标签的值 例如 metadata.labels[‘myanno’]
    • 以下只能使用环境变量,不能作为downwardAPI卷
      • spec.serviceAccountName Pod的服务账号名称
      • spec.nodeName Pod运行时所处的节点名称
      • status.hostIP 所在节点的主IP
      • status.hostIPs hostIP的双协议栈版本
      • status.podIP Pod的主IP
      • status.podIPs 双协议栈版本
    • 以下只能使用downwardAPI卷fieldRef获得,不能作为环境变量
      • metadata.labels 全部标签
      • metadata.annotations 全部注解
  • 使用resourceFieldRef传递来自Container级字段的信息。
    • resource: limits.cpu 容器的 CPU 限制值。注意 如果没配置将显示节点可使用cpu最大值
    • resource: requests.cpu 容器的 CPU 请求值
    • resource: limits.memory 容器的内存限制值 注意 如果没配置将显示节点可使用内存最大值
    • resource: requests.memory 容器的内存请求值
    • resource: limits.hugepages-*容器的巨页限制值
    • resource: requests.hugepages-*容器的巨页请求值
    • resource: limits.ephemeral-storage 容器的临时存储的限制值
    • resource: requests.ephemeral-storage 容器的临时存储的请求值
      示例:
#通过环境变量的方式挂载downwardAPI
apiVersion: v1
kind: Pod
metadata:
  name: dapi-envars-fieldref
spec:
  containers:
    - name: test-container
      image: registry.k8s.io/busybox
      command: [ "sh", "-c"]
      args:
      - while true; do
          echo -en '\n';
          printenv MY_NODE_NAME MY_POD_NAME MY_POD_NAMESPACE;
          printenv MY_POD_IP MY_POD_SERVICE_ACCOUNT;
          sleep 10;
        done;
      env:
        - name: MY_NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        - name: MY_POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: MY_POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: MY_POD_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        - name: MY_POD_SERVICE_ACCOUNT
          valueFrom:
            fieldRef:
              fieldPath: spec.serviceAccountName
  restartPolicy: Never
#通过卷的方式挂载downwardAPI
apiVersion: v1
kind: Pod
metadata:
  name: kubernetes-downwardapi-volume-example
  labels:
    zone: us-est-coast
    cluster: test-cluster1
    rack: rack-22
  annotations:
    build: two
    builder: john-doe
spec:
  containers:
    - name: client-container
      image: registry.k8s.io/busybox
      command: ["sh", "-c"]
      args:
      - while true; do
          if [[ -e /etc/podinfo/labels ]]; then
            echo -en '\n\n'; cat /etc/podinfo/labels; fi;
          if [[ -e /etc/podinfo/annotations ]]; then
            echo -en '\n\n'; cat /etc/podinfo/annotations; fi;
          sleep 5;
        done;
      volumeMounts:
        - name: podinfo
          mountPath: /etc/podinfo #通过downwardAPI挂载在/etc/podinfo/ 下有两个文件 labels、annotations
  volumes:
    - name: podinfo
      downwardAPI:
        items:
          - path: "labels"
            fieldRef:
              fieldPath: metadata.labels
          - path: "annotations"
            fieldRef:
              fieldPath: metadata.annotations
  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

琰玥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值