zoukankan      html  css  js  c++  java
  • K8S--资源控制器&Pod详解&探针

    一、资源控制器

      K8S中内建了很多的控制器,这些控制器都是用来空指Pod的具体状态和行为。从控制器的角度来说,Pod可以分为自主式Pod和控制器管理的Pod。自主式的Pod一旦退出,该类型的Pod就不会被重新创建,而控制器管理的Pod,在控制器的生命周期里,始终要维持Pod的副本数量。

      常用的控制器,在K8S--架构及基本概念中已经说过,主要有ReplicationController(旧版本)、ReplaSet、Deployment、DaemonSet、Job、CronJob,具体的概念就不再说多,直接上代码示例。

      对于RC、RS、Deployment的配置可以参见K8S--实战

    (一)DaemonSet

      DaemonSet确保全部Node上运行一个Pod副本,当有Node加入集群时,也会为他们新增一个pod,当有Node从集群中被移除时,这些pod也会被回收,删除DaemonSet将会删除其创建的所有pod。最典型的场景就是每个Pod里面都有服务在运行,需要收集服务运行日志,但是Pod是由K8S自动创建或删除的,因此需要使用DaemonSet来设定在每一个Pod中进行日志收集。

    #确保只运行一个副本,运行在集群中每一个节点上。(也可以部分节点上只运行一个且只有一个pod副本,如监控ssd硬盘)
    # kubectl explain ds
    # vim  filebeat.yaml
    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: my-deamon
      namespace: default
      labels: 
        app: daemonset
    spec:
      selector:
        matchLabels:
          app: my-daemonset
      template:
        metadata:
          labels:
            app: my-daemonset
        spec:
          containers:
          - name: daemon-app
            image: nginx:1.16

      使用:kubectl apply -f xxx.yaml执行该配置文件即可,就会在每个节点中创建一个名为my-deamon的pod。

      然后可以使用:kubectl get daemonset查看在运行的daemonset
          

      实际上,K8S自己就在用deamonSet在运行组件系统。

          

     (二)Job

      Job负责处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束。而CronJob则就是在Job上加上了时间调度。

    # 我们用Job这个资源对象来创建一个任务,我们定一个Job来执行一个倒计时的任务,定义YAML文件:
    apiVersion: batch/v1
    kind: Job
    metadata:
      name: job-demo
    spec:
      template:
        metadata:
          name: job-demo
        spec:
          restartPolicy: Never
          containers:
          - name: counter
            image: busybox
            command:
            - "bin/sh"
            - "-c"
            - "for i in 9 8 7 6 5 4 3 2 1; do echo $i; done"

      上面的配置文件是创建了一个job,并从9输出到1。

      使用命令执行配置文件: kubectl apply -f job.yaml

      查看pod:

          

       可以看到job已经执行完成,然后查看输出日志:

          

       可以看到已经正常打印。

    (三)CronJob

      CronJob其实就是在Job的基础上加上了时间调度,我们可以:在给定的时间点运行一个任务,也可以周期性地在给定时间点运行。这个实际上和我们Linux中的crontab就非常类似了。

    apiVersion: batch/v1beta1
    kind: CronJob
    metadata:
      name: cronjob-demo
    spec:
      schedule: "*/1 * * * *"
      jobTemplate:
        spec:
          template:
            spec:
              restartPolicy: OnFailure
              containers:
              - name: hello
                image: busybox
                args:
                - "bin/sh"
                - "-c"
                - "for i in 9 8 7 6 5 4 3 2 1; do echo $i; done"

      执行该配置文件: kubectl apply -f cronjob.yaml

      可以使用以下命令查看:

    # 查询cronjob
    kubectl get cronjob
    # 查询jon ,cronjon会循环多个job
    kubectl get job 
    # 实时监控查询job 
    kubectl get job -w

    二、Pod

    (一)Pod生命周期

      Pod的status属性描述了Pod处于生命周期的阶段。

    阶段 描述
    Pending Pod 已被 Kubernetes 接受,但尚未创建一个或多个容器镜像。这包括被调度之前的时间以及通过网络下载镜像所花费的时间,执行需要一段时间。
    Running Pod 已经被绑定到了一个节点,所有容器已被创建。至少一个容器正在运行,或者正在启动或重新启动。
    Succeeded 所有容器成功终止,也不会重启。
    Failed 所有容器终止,至少有一个容器以失败方式终止。也就是说,这个容器要么已非 0 状态退出,要么被系统终止。
    Unknown 由于一些原因,Pod 的状态无法获取,通常是与 Pod 通信时出错导致的。

      重启策略:

      对于Pod的重启策略,有Always、OnFailure、Never三种,默认为Always,其中Always表示容器失败时,kubectl会自动重启该容器,Onfailure表示容器终止运行且退出码不为0时重启,Never表示无论什么状态,kubectl都不会重启该容器。

      失败的容器由kubectl以五分钟为上限的指数延迟重新启动(10秒、20秒、40秒),并在成功执行十分钟后重置。

      Pod的生命周期如下图所示:

           

         流程说明:

          (1)初始化容器阶段,初始化Pod中的每一个容器,他们是串行执行的,执行完就退出了。

          (2)启动主容器main container

          (3)在main container刚刚启动之后可以执行post start命令(勾子程序)

          (4)在整个main container执行的过程中可以做两类探测:liveness probe(存活探测)和readiness probe(就绪探测)

          (5)在main container结束前可以执行pre stop命令(勾子程序)

        配置启动后勾子(post start)和终止前勾子(pre stop):

          post start:容器创建之后立即执行,如果失败了就会按照重启策略重启容器

          pre stop:容器终止前立即执行,执行完成后容器将成功终止

        可以使用以下命令查看post start和pre stop的设置格式:

    kubectl explain pod.spec.containers.lifecycle.preStop
    kubectl explain pod.spec.containers.lifecycle.postStart

    (二)Pod init

      1、init容器

      Pod能够持有多个容器,应用运行在容器里面,但是它也可能有一个或多个先于应用程序启动的init容器,init容器与普通容器非常相似,只有以下两点区别:

        (1)init容器总是运行到成功完成为止

        (2)每个init容器都必须在下一个init容器启动之前成功完成

      如果pod的init容器失败,K8S会不断的重启该Pod,直到init容器成功为止,不过也有特里,就是如果将Pod的重启策略restartPolicy设置为Never,他就不会重启了。

      2、init的作用

      因为init容器与应用程序容器的镜像是分离的,所以他们启动相关代码具有以下优势:

        (1)它们可以包含并运行实用工具,但是处于安全考虑,一般不建议在应用程序容器镜像中包含这些实用工具

        (2)他们可以包含实用工具和定制化代码来安装,但是不能出现在现有应用程序镜像中,例如创建镜像没有必要FROM另一个镜像,只需要在安装过程中使用类似sed、awk、python或dig这样的工具

        (3)应用程序镜像可以分离出创建和部署的角色,而没有必要联合他们构建一个单独的镜像。

        (4)init容器使用LinuxNamespace,所以相对应用程序来说,其具有不同文件系统视图,因此,他们能够具有访问Secret的权限,而应用程序容器则不能。

        (5)他们必须在应用程序启动之前运行完成,而应用程序是并行运行的,所以init容器能够提供一种简单的阻塞或延迟应用容器启动的方法,直到满足了一组先决条件。

      3、特殊说明

        (1)在pod启动过程中,init容器会按照顺序在网络和数据卷初始化之后启动(网络和数据卷初始化是在pause容器中),每个容器必须在下一个容器启动前成功退出

        (2)如果由于运行时或失败退出,将导致容器启动失败,它会根据Pod的restartPolicy指定的重启策略来进行处理

        (3)在所有的init容器没有成功之前,Pod将不会变成Ready状态,init容器的端口将不会在Service中进行聚集,正在初始化的Pod处于Pending状态,但应该会将Initializing状态设置为true

        (4)如果Pod重启,所有的Init容器必须重新执行

        (5)对init容器spec的修改被限制在容器的image字段,修改其他字段都不会生效,更改init容器的image字段,等价于重启了Pod

        (6)Init容器具有应用容器的所有字段,除了readinessProbe(就绪检测),因为init容器无法定义不同于完成(Completion)的就绪(readiness)之外的其他状态,这会在验证过程中强制执行。

        (7)在Pod中的每个app和init容器的名称必须唯一,与任何其他容器共享一个名称,会在验证时抛出错误。

      4、演示

      创建一个init容器的配置文件,在该配置文件中,创建了一个initPod叫init-mydb,该initpod需要执行一个连接inint-db的pod

    #init-pod.yaml
    apiVersion: v1
    kind: Pod
    metadata:
     name: init-pod
     labels:
       app: nginx
    spec:
     containers:
     - name: myapp
       image: nginx
       command: ['sh', '-c', 'echo -n "running at " && date +%T && sleep 600']
     initContainers:
     - name: init-mydb
       image: nginx
       command: ['sh', '-c', 'until nslookup init-db; do echo waiting for init-db;date +%T; sleep 2;echo; done;']

      创建:

    #创建
    kubectl apply -f init-pod.yaml
    #查看pod状态 init没成功
    kubectl get pod
    #查看log
    kubectl logs init-pod -c init-mydb

        

      使用上述命令可以看到,上面创建的容器一直连不上db,导致一直不能完成。

      然后创建db容器

    #init-db.yaml
    kind: Service
    apiVersion: v1
    metadata:
     name: init-db
    spec:
     ports:
       - protocol: TCP
         port: 80
         targetPort: 3366

      创建

    #创建svr
    kubectl create -f init-db.yaml
    #查看
    kubectl get svc
    
    #svc有ip地址,等待init容器运行成功
    kubectl get pod

      显示原来的容器已经启动成功。

      删除容器

    #删除
    kubectl delete -f init-pod.yaml
    kubectl delete -f init-db.yaml

    三、容器探针

    (一)概述  

      探针是由kubectl对容器执行的定期诊断,要执行诊断,kubelet调用由容器实现的Handler,探测的诊断结果有成功、失败和未知三种情况,探测类型有以下三种:

        1、ExecAction:在容器内执行指定命令,如果命令退出时返回码为0则认为诊断成功

        2、TCPSocketAction:对指定端口上的容器的IP地址进行TCP检查,如果端口打开,则认为诊断成功

        3、HTTPGetAction:对指定的端口和路径上的容器IP执行http get请求,如果响应状态码大于200小于400,则认为诊断成功。

      上面提到了存活探测和就绪探测,那么对于两种探测的方式做个解释:

        1、livenessProbe(存活探测):存活探测是用来探测容器是否正在运行,如果探测失败,lubelet会杀死容器,并且容器将受到重启策略的影响。如果容器不提供存活探测,则默认为状态一直为Success。

        2、readinessProbe(就绪探测):就绪探测是用来探测容器是否准备好接收服务请求,如果探测失败,端点控制器将从与Pod匹配的所有Service的端点中删除该Pod的IP地址。初始延迟之前的就绪状态默认为Failure,如果容器不提供就绪探针,则默认状态一直为Success。

    (二)就绪探针

      就绪探针配置:

    #readinessProbe-httpget
    apiVersion: v1 
    kind: Pod 
    metadata:
      name: readiness-httpget-pod 
      namespace: default
    spec:
      containers:
      - name: readiness-httpget-container 
        image: nginx
        imagePullPolicy: IfNotPresent
        readinessProbe:
          httpGet:
            port: 80
            path: /index1.html 
          initialDelaySeconds: 1
          periodSeconds: 3

      以上的配置文件表示创建一个名字为readiness-httpget-pod的就绪探针,readinessProbe的配置就是就绪探针的具体配置,首先使用的是httpget的方式访问80端口,访问路径是/index1.html,延迟一秒访问,每三秒探测一次。

      执行以上yaml文件,查看结果:

          

       可以看到,虽然这个Pod状态为Running,但是却为就绪,使用命令查看原因:

    kubectl describe pod readiness-httpget-pod

          

       可以看到是就绪探测结果为404。

      那么就为该pod创建一个/index1.html配置文件

    # 进入pod
    kubectl exec -it readiness-httpget-pod sh
    # 进入nginx默认访问目录
    cd /usr/share/nginx/html
    # 创建index1.html
     echo 'hello lcl' >> index1.html
    # 从pod中退出
    exit

      重新查看,该pod已经正常运行

        

       说明:实际生产中,访问的路径一般都是健康检查的路径,这里只是为了做个演示。

    (三)存活检测--livenessProbe-exec

      配置文件:

    apiVersion: v1 
    kind: Pod 
    metadata:
      name: liveness-exec-pod
      namespace: default 
    spec:
      containers: 
      - name: liveness-exec-container 
        image: hub.lcl.cn/library/busybox:v1
        imagePullPolicy: IfNotPresent 
        command: ["/bin/sh","-c","touch /tmp/live;sleep 60;rm -rf /tmp/live;sleep 3600"] 
        livenessProbe:
          exec:
            command: ["test","-e","/tmp/live"]
          initialDelaySeconds: 1
          periodSeconds: 3

      配置文件简单说明:

        容器(liveness-exec-container)的command命令,创建一个/tmp/live文件,然后休眠60秒,然后将该文件删除,然后再休眠3600秒

        创建了一个存活探针(livenessProbe),检测/tmp/live文件,延迟一秒开始检测,每三秒探测一次。

      执行yaml文件,查看pod运行情况

          

       可以看到,Pod在一段时间后,检测不到/tmp/live文件,自动重启。

    (四)存活检测--livenessProbe-Httpget

      yaml文件

    apiVersion: v1
    kind: Pod
    metadata:
      name: liveness-httpget-pod
      namespace: default
    spec:
      containers:
      - name: liveness-httpget-container
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80
        livenessProbe:
          httpGet:
            port: http
            path: /index.html
          initialDelaySeconds: 1
          periodSeconds: 3
          timeoutSeconds: 10

      配置文件说明:

        创建了一个存活探针(livenessProbe),使用httpget方式请求/index.html,检测/tmp/live文件,延迟3秒开始检测,每10秒探测一次。

      运行yaml文件:因为nginx默认就有index.html文件,因此pod状态正常

          

       进入pod中,将index.html删除

    # 进入容器
    kubectl exec -it liveness-httpget-pod sh
    # 切换到nginx默认访问目录
    cd /usr/share/nginx/html
    # 删除文件
    rm -f index.html

          

       可以看到pod就开始重启了。

    (五)存活检测-livenessProbe-TCP

      yaml文件

    apiVersion: v1
    kind: Pod
    metadata:
      name: probe-tcp
    spec:
      containers:
      - name: probetcp
        image: nginx
        livenessProbe:
          initialDelaySeconds: 5
          timeoutSeconds: 1
          tcpSocket:
            port: 80
          periodSeconds: 3

      配置文件说明:使用tcp检测,延迟5秒开始检测,检测超时时间为1秒,检测端口80,每3秒检测一次。

    (六)存活探测和就绪探测

      在实际生产中,一个Pod中应该同时存在就绪探测和存活探测,yaml样例如下所示

    apiVersion: v1 
    kind: Pod 
    metadata:
      name: liveness-httpget-pod 
      namespace: default 
    spec:
      containers: 
      - name: liveness-httpget-container 
        image: hub.lcl.com/library/myapp:v1 
        imagePullPolicy: IfNotPresent 
        ports:
        - name: http 
          containerPort: 80 
        readinessProbe:
          httpGet: 
            port: 80
            path: /index1.html 
          initialDelaySeconds: 1 
          periodSeconds: 3 
        livenessProbe:
          httpGet:
            port: http 
            path: /index.html 
          initialDelaySeconds: 1
          periodSeconds: 3
          timeoutSeconds: 10

    (七)勾子函数  

      在前面说Pod的生命周期中有start勾子函数和stop勾子函数,就是在启动前和停止后分别要做哪些事情,这里做个演示:

    apiVersion: v1
    kind: Pod
    metadata:
      name: lifecycle-startstop
    spec:
      containers:
      - name: lifecycle-container
        image: nginx
        lifecycle:
          postStart:
            exec:
              command: ["/bin/sh","-c","echo Hello from the postStart handler > /usr/share/message"]
          preStop:
            exec:
              command: ["/bin/sh","-c","echo Hello container stop"]

       配置文件也比较简单,就是在启动的时候输出一句话到message文件,在pod停止时,再输出一句话

      执行yaml文件,待pod运行后,进入pod,查看message文件

          

       停止的由于已经停止,就看不了~~~

      

    ------------------------------------------------------------------
    -----------------------------------------------------------
    ---------------------------------------------
    朦胧的夜 留笔~~
  • 相关阅读:
    根据时间戳获取年月日时分秒
    除法函数,乘法函数,加法函数,减法函数
    禁止鼠标点右键
    获取cookie,设置cookie,删除cookie
    解决 堆栈 出现的父对象和子对象相关联的问题 (深拷贝)
    团队展示
    用户规格说明书——结对编程
    测试与优化——结对编程
    程序开发——结对编程
    程序开发初体验
  • 原文地址:https://www.cnblogs.com/liconglong/p/15086742.html
Copyright © 2011-2022 走看看