• kubernetes 核心技术-pod


    POD的定义

    在Kubernetes集群中,Pod是所有业务类型的基础,也是K8S管理和部署的最小单位,其他的资源对象都是用来支撑或者扩展 Pod 对象功能的,比如控制器是用来管控Pod对象的,Service或者Ingress资源对象是用来暴露Pod对象的,PersistentVolume资源对象是用来为Pod提供存储等等。

    k8s 不会直接处理容器,而是pod。pod是容器的载体,所有的容器都是在pod中被管理,一个或多个容器放在pod里作为一个单元方便管理。毕竟docker和kubernetes也不是一家公司的,如果做一个编排部署的工具,你也不可能直接去管理别人公司开发的东西,所以就把docker容器放在了pod里,在kubernetes的集群环境下,我直接管理我的pod,然后对于docker容器的操作,我把它封装在pod里,并不直接操作。

    Pod、容器与Node(工作主机)之间的关系如下图所示:

    所以,pod是一个或多个容器的组合。这些容器共享存储、网络和命名空间,以及如何运行的规范。在Pod中,所有容器都被统一安排和调度,并运行在共享的上下文中。对于具体应用而言,Pod是它们的逻辑主机,Pod包含业务相关的多个应用容器。

    如图,每一个 Pod 都有一个特殊的被称为”根容器“的 Pause容器,加上一个或多个用户自定义的容器构造而成。pause的状态代表了这一组容器的状态。

    Kubernetes在每个Pod启动时,会自动创建一个镜像为gcr.io/google_containers/pause:version的容器,所有处于该Pod中的容器在启动时都会添加诸如--net=container:pause --ipc=contianer:pause --pid=container:pause的启动参数,因此pause容器成为Pod内共享命名空间的基础。所有容器共享pause容器的IP地址,也被称为Pod IP。

    pod里多个业务容器共享pod的Ip和数据卷,即pod的两个特点。

    共享网络:

    每一个Pod都会被指派一个唯一的Ip地址,在Pod中的每一个容器共享网络命名空间,包括Ip地址和网络端口。在同一个Pod中的容器可以用locahost(127.0.0.1)进行互相通信,不同容器只要注意不要有端口冲突即可。不同的Pod有不同的IP,不同Pod内的多个容器之前通信,通常情况下使用 Pod的IP进行通信。

    共享存储:

    一个 Pod 里的多个容器可以共享存储卷,这个存储卷会被定义为 Pod 的一部分,并且可以挂载到该 Pod 里的所有容器的文件系统上。

    POD的工作方式

    1.pod模板

    K8s一般不直接创建Pod,而是通过控制器和模版配置来管理和调度。下面是一个完整的yaml格式定义的文件:

    apiVersion: v1            //版本
    kind: pod                 //类型,pod
    metadata:                 //元数据
      name: String            //元数据,pod的名字
      namespace: String       //元数据,pod的命名空间
      labels:                 //元数据,标签列表
        - name: String        //元数据,标签的名字
      annotations:            //元数据,自定义注解列表
        - name: String        //元数据,自定义注解名字
    spec:                     //pod中容器的详细定义
      containers:             //pod中的容器列表,可以有多个容器
      - name: String
        image: String         //容器中的镜像
        imagesPullPolicy: [Always|Never|IfNotPresent]//获取镜像的策略
        command: [String]     //容器的启动命令列表(不配置的话使用镜像内部的命令)
        args: [String]        //启动参数列表
        workingDir: String    //容器的工作目录
        volumeMounts:         //挂载到到容器内部的存储卷设置
        - name: String
          mountPath: String
          readOnly: boolean
        ports:                //容器需要暴露的端口号列表
        - name: String
          containerPort: int  //容器要暴露的端口
          hostPort: int       //容器所在主机监听的端口(容器暴露端口映射到宿主机的端口)
          protocol: String
        env:                  //容器运行前要设置的环境列表
        - name: String
          value: String
        resources:            //资源限制
          limits:
            cpu: Srting
            memory: String
          requeste:
            cpu: String
            memory: String
        livenessProbe:         //pod内容器健康检查的设置
          exec:
            command: [String]
          httpGet:             //通过httpget检查健康
            path: String
            port: number
            host: String
            scheme: Srtring
            httpHeaders:
            - name: Stirng
              value: String 
          tcpSocket:           //通过tcpSocket检查健康
            port: number
          initialDelaySeconds: 0//首次检查时间
          timeoutSeconds: 0     //检查超时时间
          periodSeconds: 0      //检查间隔时间
          successThreshold: 0
          failureThreshold: 0
          securityContext:      //安全配置
            privileged: falae
        restartPolicy: [Always|Never|OnFailure]//重启策略
        nodeSelector: object    //节点选择
        imagePullSecrets:
        - name: String
        hostNetwork: false      //是否使用主机网络模式,默认否
      volumes:                  //在该pod上定义共享存储卷
      - name: String
        meptyDir: {}
        hostPath:
          path: string
        secret:                 //类型为secret的存储卷
          secretName: String
          item:
          - key: String
            path: String
        configMap:             //类型为configMap的存储卷
          name: String
          items:
          - key: String
            path: String

    2.pod重启

    在Pod中的容器可能会由于异常等原因导致其终止退出,Kubernetes提供了重启策略以重启容器。重启策略对同一个Pod的所有容器起作用,容器的重启由Node上的kubelet执行。Pod支持三种重启策略,在配置文件中通过restartPolicy字段设置重启策略:

    • Always:只要退出就会重启。
    • OnFailure:只有在失败退出(exit code不等于0)时,才会重启。
    • Never:只要退出,就不再重启

    注意,这里的重启是指在Pod的宿主Node上进行本地重启,而不是调度到其它Node上。

    3.资源限制

    Kubernetes通过cgroups限制容器的CPU和内存等计算资源,包括requests(请求,调度器保证调度到资源充足的Node上)和limits(上限):

    4.健康检查

    在Pod部署到Kubernetes集群中以后,为了确保Pod处于健康正常的运行状态,Kubernetes提供了两种探针,用于检测容器的状态:

    • Liveness Probe :检查容器是否处于运行状态(running)。如果检测失败,kubelet将会杀掉容器,并根据重启策略进行下一步的操作。
    • ReadinessProbe :检查容器是否已经处于可接受服务请求的状态(ready)。如果检测失败,端点控制器将会从服务端点(与Pod匹配的)中移除容器的IP地址。

    kubelet在容器上周期性的执行探针以检测容器的健康状态,kubelet通过调用被容器实现的处理器来实现检测,在Kubernetes中有三类处理器:

    • Exec:在容器中执行一个指定的命令。如果命令的退出状态为0,则判断认为是成功的;
    • TCPSocket :在容器IP地址的特定端口上执行一个TCP检查,如果端口处于打开状态,则视为成功;
    • HTTPGet:发送一个http Get请求(ip+port+请求路径)如果返回状态吗在200-400之间则表示成功;

    健康检测的结果为下面三种情况:

    • Success :表示容器通过检测
    • Failure :表示容器没有通过检测
    • Unknown :表示检测容器失败

    POD的创建流程

    Kubernetes通过watch的机制进行每个组件的协作,每个组件之间的设计实现了解耦。

    1. 用户使用create yaml创建pod,请求给apiserver,apiserver将yaml中的属性信息(metadata)写入etcd。
    2. apiserver触发watch机制准备创建pod,信息转发给scheduler,调度器使用调度算法选择node,调度器将node信息返回给apiserver,apiserver将绑定的node信息写入etcd。
    3. apiserver又通过watch机制,调用kubelet,指定pod信息,触发docker run命令创建容器。
    4. 容器创建完成之后反馈给kubelet,kubelet又将pod的状态信息反馈给apiserver,apiserver又将pod的状态信息写入etcd。
    5. 其中kubectl get pods命令调用的是etcd中的信息。

    注意:图中有三次write至etcd:

    1. 元信息
    2. pod分配到哪个node
    3. 记录pod状态

    在整个过程中,Pod通常处于以下的五种阶段之一:

    • Pending:Pod定义正确,提交到Master,但其所包含的容器镜像还未完全创建。通常,Master对Pod进行调度需要一些时间,Node进行容器镜像的下载也需要一些时间,启动容器也需要一定时间。(写数据到etcd,调度,pull镜像,启动容器)。
    • Running:Pod已经被分配到某个Node上,并且所有的容器都被创建完毕,至少有一个容器正在运行中,或者有容器正在启动或重启中。
    • Succeeded:Pod中所有的容器都成功运行结束,并且不会被重启。这是Pod的一种最终状态。
    • Failed:Pod中所有的容器都运行结束了,其中至少有一个容器是非正常结束的(exit code不是0)。这也是Pod的一种最终状态。
    • Unknown:无法获得Pod的状态,通常是由于master无法和Pod所在的Node进行通信。

     

    POD调度方式

    Deployment或RC全自动调度:pod最终运行在哪个节点上, 完全由 Master 的 Scheduler 经过一系列算法计算得 出 ,用户无法干预调度过程和结果。

    除此之外,还有以下三种方式去影响pod的调度

    • node节点调度器
    • 亲和性调度
    • 污点容忍度

    1.node节点调度

    是最直接的调度方式,简单粗暴,所以常用在简单的集群架构中,负载的资源分类和编制不适合这种方式,
    解释:先给work节点打上标签,然后在pod的yml文件中去设置nodeSelector绑定节点,这样就能指定pod启动在设置的node节点上。
    (1)首先通过 kubectl 给 node1 打上标签

    格式:
    kubectl label nodes <node-name> <label-key>=<label-value>
    
    
    [root@master ~]# kubectl get nodes
    NAME     STATUS   ROLES    AGE   VERSION
    master   Ready    master   23d   v1.18.0
    node1    Ready    <none>   21d   v1.18.0
    node2    Ready    <none>   21d   v1.18.0
    [root@master ~]# kubectl label nodes node1 disk=ssd
    node/node1 labeled
    [root@master ~]# kubectl get nodes node1 --show-labels
    NAME    STATUS   ROLES    AGE   VERSION   LABELS
    node1   Ready    <none>   21d   v1.18.0   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disk=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=node1,kubernetes.io/os=linux
    [root@master ~]# 

    (2)通过 nodeSelector 调度 pod 到指定 node

    • Pod的定义中通过nodeSelector指定label标签,pod将会只调度到具有该标签的node之上
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
    spec:
      selector:
        matchLabels:
          app: nginx
      replicas: 1
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx:1.11
            ports:
            - containerPort: 80
          nodeSelector:
            disk: ssd

    这个例子中pod只会调度到具有 disk=ssd 标签的node1上:

    [root@master ~]# kubectl apply -f pod-test.yaml 
    deployment.apps/nginx-deployment created
    [root@master ~]# kubectl get pods -o wide
    NAME                                READY   STATUS              RESTARTS   AGE   IP           NODE    NOMINATED NODE   READINESS GATES
    nginx-deployment-6b4474784c-ld2ng   0/1     ContainerCreating   0          29s   <none>       node1   <none>           <none>
    [root@master ~]# kubectl describe pod nginx-deployment
    Name:         nginx-deployment-6b4474784c-ld2ng
    Namespace:    default
    Priority:     0
    Node:         node1/172.31.93.201
    Start Time:   Fri, 09 Apr 2021 11:44:47 +0800
    Labels:       app=nginx
                  pod-template-hash=6b4474784c
    Annotations:  <none>
    Status:       Running
    IP:           10.244.1.4
    IPs:
      IP:           10.244.1.4
    Controlled By:  ReplicaSet/nginx-deployment-6b4474784c
    Containers:
      nginx:
        Container ID:   docker://0669cc442c30510246f12495a796b2968e0b84693b7ae8c378f0d6b0556ed947
        Image:          nginx:1.11
        Image ID:       docker-pullable://nginx@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582
        Port:           80/TCP
        Host Port:      0/TCP
        State:          Running
          Started:      Fri, 09 Apr 2021 11:45:24 +0800
        Ready:          True
        Restart Count:  0
        Environment:    <none>
        Mounts:
          /var/run/secrets/kubernetes.io/serviceaccount from default-token-tdnv4 (ro)
    Conditions:
      Type              Status
      Initialized       True 
      Ready             True 
      ContainersReady   True 
      PodScheduled      True 
    Volumes:
      default-token-tdnv4:
        Type:        Secret (a volume populated by a Secret)
        SecretName:  default-token-tdnv4
        Optional:    false
    QoS Class:       BestEffort
    Node-Selectors:  disk=ssd
    Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                     node.kubernetes.io/unreachable:NoExecute for 300s
    Events:
      Type    Reason     Age        From               Message
      ----    ------     ----       ----               -------
      Normal  Scheduled  <unknown>  default-scheduler  Successfully assigned default/nginx-deployment-6b4474784c-ld2ng to node1
      Normal  Pulling    8h         kubelet, node1     Pulling image "nginx:1.11"
      Normal  Pulled     8h         kubelet, node1     Successfully pulled image "nginx:1.11"
      Normal  Created    8h         kubelet, node1     Created container nginx
      Normal  Started    8h         kubelet, node1     Started container nginx

    如果给多个node都定义了相同的标签, 则调度器会根据调度算法从这组node中挑选一个可用的node进行pod调度。
    如果指定了pod的nodeSelector条件, 且集群中不存在包含响应标签的Node, 则即使在集群中还有其它可供使用的Node,这个pod也无法被成功调度。

    2.亲和性调度

    较复杂,应用在复杂的多节点归类,资源分类管理的中大型集群中,有硬亲和,软亲和,亲和性和反亲和等概念。

    硬亲和:匹配节点上的标签(必须满足,若集群中不存在包含响应标签的Node,无法调度成功)
    软亲和:匹配节点上的标签(尝试满足,优先选择包含响应标签的Node,实在没有也能调度运行)

    • 节点亲和性(Node affinity)

    上述配置表示,该pod必须不能调度至有标签 role=master 的node节点(必须满足),最好能调度至有标签 cpu=high 的node节点(尝试满足)

    支持常用的操作符有:in  Notin  Exists  Gt  Lt  DoesNotExists

    • pod亲和性(pod affinity)与反亲和性(pod anti affinity)

    podAffinity用于调度pod可以和哪些pod部署在同一拓扑结构之下。而podAntiAffinity相反,其用于规定pod不可以和哪些pod部署在同一拓扑结构下。主要用来解决pod和pod之间的关系。

    上述配置表示,该pod不可以和solr服务的pod部署在同一拓扑结构之下(必须满足),最好不要和oltp服务的pod部署在同一拓扑结构之下(尝试满足)

    3.污点和容忍度

    无论是nodeSelector还是nodeAffinity,都是通过pod中的属性,在调度的时候实现。

    与之前两个调度方式不同,污点是给节点绑定污点(是节点的属性),作用是保护节点,不再让这个节点被scheduler选为pod启动环境。
    集群中的master就是设置了污点,所以启动任何pod都不会在master上工作,保证master的工作效率。

    查看节点的污点情况:kubectl describe node [node] | grep Taints

    [root@master ~]# kubectl describe node master |grep Taint
    Taints:             node-role.kubernetes.io/master:NoSchedule

    可见,master有一个NoSchedule的污点,污点值有三个:

    • NoSchedule:一定不被调度,对已有pod不影响
    • PreferNoSchedule: 尽量不被调度
    • NoExecute:一定不被调度,并且还会驱逐node上已有pod

    设置给node1设置污点:kubectl taint node node1 node-type=prod:NoSchedule

    [root@master ~]# kubectl taint node node1 node-type=prod:NoSchedule
    node/node1 tainted
    [root@master ~]# kubectl describe node node1 |grep Taint
    Taints:             node-type=prod:NoSchedule

     创建pod测试:

    #创建一个pod
    [root@master ~]# kubectl create deployment web --image=nginx
    deployment.apps/web created
    #复制五个
    [root@master ~]# kubectl scale deployment web --replicas=5
    deployment.apps/web scaled
    [root@master ~]# kubectl get pods -o wide
    NAME                                READY   STATUS              RESTARTS   AGE     IP           NODE    NOMINATED NODE   READINESS GATES
    web-5dcb957ccc-7qj2f                0/1     ContainerCreating   0          21s     <none>       node2   <none>           <none>
    web-5dcb957ccc-9bqz5                1/1     Running             0          89s     10.244.2.4   node2   <none>           <none>
    web-5dcb957ccc-d99vb                1/1     Running             0          21s     10.244.2.5   node2   <none>           <none>
    web-5dcb957ccc-wd7b4                0/1     ContainerCreating   0          21s     <none>       node2   <none>           <none>
    web-5dcb957ccc-xvf74                0/1     ContainerCreating   0          21s     <none>       node2   <none>           <none>

    可见,由于node1设置了污点,所有pod都被调度到了node2上。

    最后删除污点:kubectl taint node node1 node-type=prod:NoSchedule-  (注意最后面有一个-)

    [root@master ~]# kubectl describe node node1|grep Taint
    Taints:             node-type=prod:NoSchedule
    [root@master ~]# kubectl taint node node1 node-type=prod:NoSchedule-
    node/node1 untainted
    [root@master ~]# kubectl describe node node1|grep Taint
    Taints:             <none>

    所有,如果一个节点标记为 Taints ,该Taints节点不会被调度pod,除非要被调度的Pod被标识为可以容忍污点:

    就是说,即使一个节点已经被设置污点(假设是NoSchedule),如果一个pod被标识为容忍(容忍度也是NoSchedule),那么这个pod还是有可能会被调度到taint标记过的节点。

    参考文档:

    https://blog.csdn.net/weixin_42953006/article/details/106299864

    https://www.jianshu.com/p/74f53019a726

    https://www.cnblogs.com/mybxy/p/10233682.html

    https://zhuanlan.zhihu.com/p/60905652

    https://blog.csdn.net/ht9999i/article/details/108037568

  • 相关阅读:
    Mysql存储过程详解
    自动化测试——人人都可自制“呼死你”
    Apktool(1)——Apktool的安装
    Apktool(2)——使用前必须知道的apk知识
    写博是种心情
    webpack使用tree shaking的问题。及关于UglifyJs不支持ES6的解决方案。
    angular2 笔记
    angular2 content projection
    angular2aotwebpack 生产环境下编译angular2
    ionic2配置问题集
  • 原文地址:https://www.cnblogs.com/xulan0922/p/14630081.html
Copyright © 2020-2023  润新知