• Kubernetes深入理解POD(二)


    一、什么是POD

    Pod是Kubernetes最重要的基本概念,我们看到每个Pod都有一个特殊的被称为“根容器”的Pause容器。Pause容器对应的镜像属于Kubernetes平台的一部分,除了Pause容器,每个Pod还包含一个或多个紧密相关的用户业务容器。

    二、POD的生命周期

    三、pause容器

            用"kubernetes/pause"镜像为每个Pod都创建一个容器。该Pause容器用于接管Pod中所有其他容器的网络。每创建一个新的Pod,kubelet都会先创建一个Pause容器, 然后创建其他容器。"kubernetes/pause"镜像大概有270KB,是个非常小的容器镜像。

    四、初始化容器initContainers

    因为init容器具有与应用容器分离的单独镜像,所以它们启动相关代码有具有如下优势:

    • 它们可以包含并运行实用工具,但是出去安全考虑,是不建议在应用程序容器镜像中包含这些实用工具的。
    • 它们可以包含使用工具和定制化代码来安装,但是不能出现在应用程序镜像中。例如,创建镜像没必要FROM另一个镜像,只需要在安装过程中使用类似sed、awk、python或dig这样的工具。
    • 应用程序镜像可以分离出创建和部署的角色,而没必要联合它们构建一个单独镜像。
    • Init容器使用Linux namespace,所以相对应用程序容器来说具有不同的文件系统视图。因此,它能够访问secret的权限,而应用程序则不能。(分权限治理)
    • 由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。一旦前置条件满足,Pod内的所有的应用容器会并行启动。

    注意事项:

    • 在Pod启动过程中,Init容器会按顺序在网络和数据卷初始化之后启动。每个容器必须在下一个容器启动之前成功退出。
    • 如果由于运行时或失败退出,将导致容器启动失败,它会根据Pod的RestartPolicy指定的策略进行重试。如果是Never,它不会重新启动。
    • 如果Pod重启,则Init容器会重启执行。
    • init container不能设置readinessProbe探针,因为必须在它们成功运行后才能继续运行在Pod中定义的普通容器。

    五、POD重启策略

    当某个容器异常退出或者健康检查失败, kubelet将根据RestartPolicy的设置来进行相应的操作, 重启策略有Always , OnFailure, Never。

    Always:Pod一旦终止运行,无论容器是如何终止的,kubelet都将重启它。
    OnFailure:当容器终止运行非零退出时,由kubelet自动重启该容器。
    Never:不论容器运行状态如何,kubelet都不会重启该容器。

    六、imagePullPolicy镜像拉取策略

    Always: 表示每次都尝试重新拉取镜像
    IfNotPresent: 表示如果本地有镜像, 则使用本地的镜像, 本地不存在时拉取镜像
    Never: 表示仅使用本地镜像

    七、三种探针startupProbe、livenessProbe和readinessProbe

    startupProbe探针:用于判断容器内应用程序是否已经启动,如果配置了startuprobe,优先于其它两种探测支行,直到它成功为止,成功后将不再进行startupProbe探测。
    LivenessProbe探针:用于判断容器是否存活(Running状态),如果LivenessProbe探针探测到容器不健康,则kubelet将杀掉该容器,并根据容器的重启策略做相应的处理。
    如果一个容器不包含LivenessProbe探针,那么kubelet认为该容器的LivenessProbe探针返回的值永远是Success。 ReadinessProbe探针:用于判断容器服务是否可用(Ready状态),达到Ready状态的Pod才可以接收请求。对于被Service管理的Pod,Service与Pod Endpoint的关联关系
    也将基于Pod是否Ready进行设置。如果在运行过程中Ready状态变为False,则系统自动将其从Service的后端Endpoint列表中隔离出去,后续再把恢复到Ready状态的Pod加回
    后端Endpoint列表。这样就能保证客户端在访问Service时不会被转发到服务不可用的Pod实例上。

     包括三种探测方式:

    • ExecAction:在容器内部执行一个命令,如果该命令的返回码为0,则表明容器健康。
    livenessProbe:
      exec:
        command: ['test', '-e', '/tmp/live']
      initialDelaySeconds: 1       # 启动容器后进行首次健康检查的等待时间
      periodSeconds: 3             # 检测失败后重试时间
    • TCPSocketAction:通过容器的IP地址和端口号执行TCP检查,如果能够建立TCP连接,则表明容器健康。
    readinessProbe:
      tcpSocket:
        port: 80
      initialDelaySeconds: 5       # 启动容器后进行首次健康检查的等待时间
      failureThreshold: 30         # 检测失败后重试时间
      periodSeconds: 10            # 执行探测的间隔时间
    • HTTPGetAction:通过容器的IP地址、 端口号及路径调用HTTP Get方法,如果响应的状态码大于等于200且小于400,则认为容器健康。
    livenessProbe:
      httpGet:
        path: /index.html
        port: 80
      initialDelaySeconds: 1 
      periodSeconds: 3

    一些可选参数

    timeoutSeconds:探测超时的秒数。默认为1秒。
    initialDelaySeconds:启动容器后进行首次健康检查的等待时间,单位为s
    periodSeconds:检测失败后重试时间3秒
    failureThreshold:失败的容忍次数失败几次 判断为彻底失败,放弃检查并重启
    successThreshold:失败后探测成功的最小成功次数。默认为1。最小值为1。

    八、资源限制requests和limits

    • Request工作原理

    Request 的值并不代表给容器实际分配的资源大小,用于提供给调度器。调度器会检测每个节点可用于分配的资源(可分配资源减 request 之和),同时记录每个节点已经被分配的资源(节点上所有 Pod 中定义的容器 request 之和)。如发现节点剩余的可分配资源已小于当前需被调度的 Pod 的 request,则该 Pod 就不会被调度到此节点。反之,则会被调度到此节点。

    • 避免 request 与 limit 值过大

    若服务使用单副本或少量副本,且 request 及 limit 的值设置过大,使服务可分配到足够多的资源去支撑业务。则某个副本发生故障时,可能会给业务带来较大影响。当 Pod 所在节点发生故障时,由于 request 值过大,且集群内资源分配的较为碎片化,其余节点无足够可分配资源满足该 Pod 的 request,则该 Pod 无法实现漂移,无法自愈,会加重对业务的影响。

    建议尽量减小 request 及 limit,通过增加副本的方式对服务支撑能力进行水平扩容,使系统更加灵活可靠。

    resources:
      requests:
        cpu: 500m
        memory: 1024Mi
      limits:
        cpu: 1000m         # 1000m=1核CPU
        memory: 2048Mi

    九、command 容器的启动命令 

            创建 Pod 时,可以为其下的容器设置启动时要执行的命令及其参数。如果要设置命令,就填写在配置文件的 command 字段下,如果要设置命令的参数,就填写在配置文件的 args 字段下。一旦 Pod 创建完成,该命令及其参数就无法再进行更改了。参数会覆盖docker镜像中的启动命令。

    # 用shell脚本的方式执行命令
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo hello; sleep 10;done"]
    
    # 或者只写一条----------------------------------------------
    command: ["sh", "-c", "/startup.sh"]
    
    # 使用环境变量来设置参数
    env:
    - name: MESSAGE
      value: "hello world"
    command: ["/bin/echo"]
    args: ["$(MESSAGE)"]

    十、env环境变量

    env:
    - name: MESSAGE
      value: "hello world"
    command: ["/bin/echo"]
    args: ["$(MESSAGE)"]
    
    env:
    - name: POD_IP
      valueFrom:
        fieldRef:
          fieldPath: status.podIP
    
    - name: POD_NAME
      valueFrom:
        fieldRef:
          fieldPath: metadata.name

    十一、POD的调度

    在Kubernetes平台上, 我们很少会直接创建一个Pod, 在大多数情况下会通过RC、 Deployment、 DaemonSet、 Job等控制器完成对一组Pod副本的创建、 调度及全生命周期的自动控制任务。

    • 11.1 Deployment或者ReplicaSet

    主要功能之一就是自动部署一个容器应用的多份副本, 以及持续监控副本的数量, 在集群内始终维持用户指定的副本数量。

     

    # cat nginx-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: mynginx image: nginx:1.18.0 ports: - containerPort: 80 resources: requests: cpu: 100m memory: 128Mi limits: cpu: 1000m memory: 1024Mi

    • 11.2 NodeSelector:定向调度

    NodeSelector通过标签的方式,简单实现了限制Pod所在节点的方法。

    # kubectl label node k8s-node01 app=nginx     # 为k8s-node01节点打上app=nginx的标签
    
    # kubectl get node --show-labels |grep app=nginx
    k8s-node01   Ready    <none>   13d   v1.19.0   app=nginx,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,
    kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node01,kubernetes.io/os=linux # cat nginx-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: nodeSelector: # 选择node标签为app=nginx的标签进行调度 app: nginx containers: - name: mynginx image: nginx:1.18.0 ports: - containerPort: 80 resources: requests: cpu: 100m memory: 128Mi limits: cpu: 1000m memory: 1024Mi # kubectl apply -f nginx-deployment.yaml # kubectl get pod -o wide # 所有的pod都调度到了k8s-node01节点上 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-7cc69bccbc-ffn88 1/1 Running 0 45s 10.244.85.205 k8s-node01 <none> <none> nginx-deployment-7cc69bccbc-mmqgw 1/1 Running 0 42s 10.244.85.207 k8s-node01 <none> <none> nginx-deployment-7cc69bccbc-t45gg 1/1 Running 0 43s 10.244.85.206 k8s-node01 <none> <none>
    • 11.3 NodeAffinity Node亲和性调度

    是用于替换NodeSelector的全新调度策略。目前有两种节点亲和性表达。

    RequiredDuringSchedulingIgnoredDuringExecution:必须满足指定的规则才可以调度Pod到Node上( 功能与nodeSelector很像,但是使用的是不同的语法),相当于硬限制。

    PreferredDuringSchedulingIgnoredDuringExecution:强调优先满足指定规则,调度器会尝试调度Pod到Node上, 但并不强求,相当于软限制。多个优先级规则还可以设置权重(weight)值,以定义执行的先后顺序。

    # 举例
    apiVersion: v1 kind: Pod metadata: name: with
    -node-affinity spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: # 硬亲和性,要求pod在amd64节点上运行 nodeSelectorTerms: - matchExpressions: - key: beta.kubernetes.io/arch operator: In values: - amd64 preferredDuringSchedulingIgnoredDuringExecution: # 软亲和性,尽量运行在磁盘类型为ssd的节点上 - weight: 1 preference: matchExpressions: - key: disk-type operator: In values: - ssd containers: - name: with-node-affinity image: k8s.gcr.io/pause:2.0

    NodeAffinity语法支持的操作符包括In、 NotIn、 Exists、 DoesNotExist、 Gt、 Lt。
    NodeAffinity规则设置的注意事项如下:
      如果同时定义了nodeSelector和nodeAffinity,那么必须两个条件都得到满足,Pod才能最终运行在指定的Node上。
      如果nodeAffinity指定了多个nodeSelectorTerms,那么其中一个能够匹配成功即可。
      如果在nodeSelectorTerms中有多个matchExpressions,则一个节点必须满足所有matchExpressions才能运行该Pod 

    • 11.4 PodAffinity POD亲和性

    和节点亲和相同, Pod亲和与互斥的条件设置也是requiredDuringSchedulingIgnoredDuringExecution和preferredDuringSchedulingIgnoredDuringExecution。

    # 举例pod亲和性,三个pod在运行在同一个k8s节点上
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
      namespace: default
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          affinity:
            podAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
              - labelSelector:
                  matchExpressions:
                  - key: app
                    operator: In
                    values:
                    - nginx
                topologyKey: kubernetes.io/hostname  # 同一个node为一个拓扑域
          containers:
          - name: mynginx
            image: nginx:1.18.0
            ports:
            - containerPort: 80
            resources:
              requests:
                cpu: 500m
                memory: 1024Mi
              limits:
                cpu: 1000m
                memory: 2048Mi
    
    # 举例,pod反亲和性三个pod尽量运行在不同的k8s同节点上
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
      namespace: default
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          affinity:
            podAntiAffinity:
              preferredDuringSchedulingIgnoredDuringExecution:
              - weight: 100
                podAffinityTerm:
                  labelSelector:
                    matchExpressions:
                    - key: app
                      operator: In
                      values:
                      - nginx
                  topologyKey: kubernetes.io/hostname
          containers:
          - name: mynginx
            image: nginx:1.18.0
            ports:
            - containerPort: 80
            resources:
              requests:
                cpu: 500m
                memory: 1024Mi
              limits:
                cpu: 1000m
                memory: 2048Mi

    十二、污点(Taint)与容忍(Toleration)

     Taint需要和Toleration配合使用,让Pod避开那些不合适的Node。在Node上设置一个或多个Taint之后,除非Pod明确声明能够容忍这些污点, 否则无法在这些Node上运行。Toleration是Pod的属性, 让Pod能够(注意, 只是能够, 而非必须)运行在标注了Taint的Node上。

    污点(Taint)

    使用`kubectl taint `命令可以给革个Node节点设置污点,Node被设置上污点之后就和Pod之间存在一种相斥的关系,可以让Node拒绝Pod的高度执行,甚至将Node上已经存在的Pod驱逐出去。 

    # 每个污点的组成如下
    key=vavlue:effect
    # 每个污点有一个key和value作为污点标签,其中value可以为空,effec描述污点的作用。当前tain effect支持以下三个选项:
    
    NoSchedule: 表示K8s不会将Pod调度到具有该污点的Node上
    PreferNoSchedule:表示k8s将尽量避免将Pod调度到具有该污点的Node上
    NoExecute:表示K8s将不会将Pod调度到具有该污点的Node上,同时会将Node上已经存在的Pod驱逐出去。

    注:使用noexecute,k8s会直接杀死节点上的所有的pod,并在其它节点上面重新pod,如果业务都在这一个节点上业务可能会出现同时不可用的情况,建议使用for循环来杀pod。
    例:for i in `kubectl get pod -n default -l app=nginx | awk {'print $1'}`; do kubectl delete pod $i -n default; done

    命令设置

    # 设置污点
    kubectl taint node k8s-node01 key=value:NoSchedule
    
    # 查看污点
    # kubectl describe node k8s-node01 | grep Taints
    Taints:             key=value:NoSchedule
    
    # 移出污点
    kubectl taint node k8s-node01 key=value:NoSchedule-

     容忍(Tolerations)
    设置了污点的Node将根据taint的effect:NoSchedule、PreferNoSchedule、NoExecute和Pod之间产生互斥的关系,pod将在一定程度上不会调度到Node上,但我们可以在Pod上设置容忍,意思是设置了容忍的Pod将可以容忍污点的存在,可以被调度到存在污点的Node上。

    系统允许在同一个Node上设置多个Taint,也可以在Pod上设置多个Toleration。 Kubernetes调度器处理多个Taint和Toleration的逻辑顺序为: 首先列出节点中所有的Taint,然后忽略Pod的Toleration能够匹配的部分, 剩下的没有忽略的Taint就是对Pod的效果了。

    一般来说, 如果给Node加上effect=NoExecute的Taint, 那么在该Node上正在运行的所有无对应Toleration的Pod都会被立刻驱逐, 而具有相应Toleration的Pod永远不会被驱逐。 不过, 系统允许给具有NoExecute效果的Toleration加入一个可选的tolerationSeconds字段, 这个设置表明Pod可以在Taint添加到Node之后还能在这个Node上运行多久(单位为s) :

    # cat nginx19.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-3
      labels:
        app: pod-3
    spec:
      containers:
      - name: pod-3
        image: nginx:1.18.0
      tolerations:
      - key: "key"                       # 要与Node上设置的taint保持一致
        operator: "Equal"
        value: "value"                  # 要与Node上设置的taint保持一致
        effect: "NoExecute"          # 要与Node上设置的taint保持一致
        tolerationSeconds: 3600

    十三、固定节点调度nodeName

    Pod.spec.nodeName将pod直接调度到指定的node节点上,会跳过schedule的调度策略,该匹配规则是强制匹配。

    # cat nginx8.yaml 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
    spec:
      replicas: 5
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          nodeName: k8s-node01
          containers:
          - name: mynginx
            image: nginx:1.18.0
            ports:
            - containerPort: 80
            resources:
              requests:
                cpu: 100m
                memory: 128Mi
              limits:
                cpu: 1000m
                memory: 1024Mi
  • 相关阅读:
    快速幂模板
    部分有关素数的题
    POJ 3624 Charm Bracelet (01背包)
    51Nod 1085 背包问题 (01背包)
    POJ 1789 Truck History (Kruskal 最小生成树)
    HDU 1996 汉诺塔VI
    HDU 2511 汉诺塔X
    HDU 2175 汉诺塔IX (递推)
    HDU 2077 汉诺塔IV (递推)
    HDU 2064 汉诺塔III (递推)
  • 原文地址:https://www.cnblogs.com/cyleon/p/15422168.html
Copyright © 2020-2023  润新知