K8S(十一)实战篇:资源清单运作原理解析&Pod的生命周期&探针-中间件专区论坛-技术-SpringForAll社区

K8S(十一)实战篇:资源清单运作原理解析&Pod的生命周期&探针

一、资源控制器

官方文档 工作负载资源

1. 什么是控制器?

Kubernetes中内建了很多controller (控制器),这些相当于一个状态机,用来控制Pod的具体状态和行为

RS、Deployment控制器用来控制pod的,还有一些其他控制器控制其他的资源

Pod 和控制器 你可以使用工作负载资源来创建和管理多个 Pod。 资源的控制器能够处理副本的管理、上线,并在 Pod 失效时提供自愈能力。 例如,如果一个节点失败,控制器注意到该节点上的 Pod 已经停止工作, 就可以创建替换性的 Pod。调度器会将替身 Pod 调度到一个健康的节点执行。

Pod 的分类

  • 自主式 Pod:Pod 退出了,此类型的 Pod 不会被创建
  • 控制器管理的 Pod:在控制器的生命周期里,始终要维持 Pod 的副本数目

2. 常用控制器

  • ReplicationController(旧版本)
  • ReplicaSet
  • Deployment
  • DaemonSet
  • Job/Cronjob

3. 自主式pod

# 自主式的pod: 单独定义一个pod,这个没有副本控制器管理,也没有对应deployment
# self-pod.yaml
apiVersion: v1
kind: Pod
metadata:
 name: init-pod
 labels:
   app: myapp
spec:
 containers:
 - name: myapp
   image: hub.kaikeba.com/java12/myapp:v1 # pod内部运行的容器

注意事项/总结: k8s资源对象(所有的k8s管理的资源,都叫做资源对象),都可以独立存在,但是需要根据相应原理,需求结合使用。​

可以通过命令kubectl describe pod podName 查看创建过程详情 kubectl get pod -o wide #查看pod状态详情

自主式pod没有rs、deployment,一但删掉不会重新创建

4. RC&RS

ReplicationController (RC)用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的Pod来替代;而如果异常多出来的容器也会自动回收;

在新版本的Kubernetes中建议使用Replicaset来取代ReplicationController. ReplicaSet跟 ReplicationController没有本质的不同,只是名字不一样,并且ReplicaSet支持集合式的selector;

apiVersion: extensions/v1beta1 
kind: ReplicaSet
metadata:
  name: frontend 
spec:
  replicas: 3 #3个副本
  selector:
    matchLabels: 
      tier: frontend 
  template: # 下面配置的是pod
    metadata:
      labels:
        tier: frontend
    spec:
      containers:
        - name: java-nginx #首字母不能大写
          image: hub.kaikeba.com/java12/myapp:v1
          env:
            - name: GET_HOSTS_FROM 
              value: dns
          ports:
            - containerPort: 80
      

要支持滚动更新,还需要Deployment,这里主要说明K8S的资源对象都是可以单独部署的

修改其中一个pod的标签,这样该pod就脱离原来的RS管理了,而RS会再次创建一个pod,保持副本数量: 在这里插入图片描述

由此可见RS副本控制器是通过标签维护pod的

不受RS控制的pod就是自主式pod,删除后不再重建: 在这里插入图片描述

5. Deployment

5.1 创建Deployment

Deployment为Pod和ReplicaSet提供了一个声明式定义(declarative)方法,用来替代以前的 ReplicationController来方便的管理应用。典型的应用场景包括;

  • 定义Deployment来创建Pod和ReplicaSet
  • 滚动升级和回滚应用
  • 扩容和缩容
  • 暂停和继续Deployment
#1)、部署一简单的Nginx应用
apiVersion: extensions/v1beta1 
kind: Deployment 
metadata:
  name: nginx-deployment 
spec:
  replicas: 3 #副本控制器
  template:
    metadata:
      labels:
        app: nginx 
    spec:
      containers: 
        - name: nginx 
          image: hub.kaikeba.com/java12/myapp:v1
          ports:
            - containerPort: 80

创建资源,同时把之前创建的资源删掉,避免干扰 在这里插入图片描述

退出结束,只剩下nginx的: 在这里插入图片描述

5.2 根据cpu利用率自动扩容

根据cpu利用率自动扩容:

 kubectl autoscale deployment [deployment Name] --min=[最小pod数量] --max=[最大pod数量] --cpu-percent=[根据cpu利用率]

在这里插入图片描述

设置了最小pod数为6,最大为15,需要等待一会儿才会变: 在这里插入图片描述

为什么会出现扩容效果,因为刚才的命令创建了hpa组件资源 通过hpa对象监控rs,实现pod自动扩容 在这里插入图片描述

5.3 滚动更新

演示滚动升级,为Deployment设置新版本镜像:

set image deployment [deploymentName] [containerName]=[新版本镜像路径]

在这里插入图片描述 我们知道pod的命名规则是 [deploymentName]-[ReplicaSetName]-[PodName] 图中可以看到升级后是新的RS,滚动更新的原理就是创建新的RS 回滚也是同理,回滚到之前的RS

5.4 回滚

演示回滚:

kubectl rollout undo deployment [deploymentName]

在这里插入图片描述 留意一下回滚后的RS名字,和上面的对比一下。

测试完成,清空环境: 在这里插入图片描述

Deployment更新策略

  • Deployment可以保证在升级时只有一定数量的Pod是down的。默认的,它会确保至少有比期望的Pod数量少一个是up状态(最多一个不可用)
  • Deployment同时也可以确保只创建出超过期望数量的一定数量的Pod,默认的,它会确保最多比期望的Pod数量多一个的Pod是up的(最多1个surge )

未来的Kuberentes版本中,将从1-1变成25%-25%

 kubect1 describe deployments

6. DaemonSet

#确保只运行一个副本,运行在集群中每一个节点上。(也可以部分节点上只运行一个且只有一个pod副本,如监控ssd硬盘)
# kubectl explain ds
# vim  daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata: #元数据信息,描述DaemonSet
  name: my-deamon
  namespace: default
  labels: 
    app: daemonset
spec: # RS副本控制器
  selector:
    matchLabels:
      app: my-daemonset
  template: #描述pod
    metadata:
      labels:
        app: my-daemonset
    spec:
      containers: #描述容器
      - name: daemon-app
        image: hub.kaikeba.com/java12/myapp:v1

删除其中一个pod也会自动重新创建一个: 在这里插入图片描述

7. Job

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

# 我们用Job这个资源对象来创建一个任务,我们定一个Job来执行一个倒计时的任务,定义YAML文件:
apiVersion: batch/v1
kind: Job
metadata:
  name: job-demo
spec:
  template: #描述pod
    metadata:
      name: job-demo
    spec:
      restartPolicy: Never #pod重启策略
      containers:
      - name: counter
        image: busybox #指定镜像,busybox 是网络上的镜像
        command: #容器启动后执行的命令
        - "bin/sh"
        - "-c"
        - "for i in 9 8 7 6 5 4 3 2 1; do echo $i; done"
# 创建
kubectl apply -f job.yaml
# 查询日志
kubectl logs 

注意Job的RestartPolicy(重启策略)仅支持Never和OnFailure两种,不支持Always,我们知道Job就相当于来执行一个批处理任务,执行完就结束了,如果支持Always的话是不是就陷入了死循环了?

看到多了一个job的pod,状态是Completed,READY是0/1,说明已经执行结束了 PS:执行完成后是不会主动删除pod的,但是pod中的容器已经结束了 还有一个job任务处理控制器,查看该job的日志: 在这里插入图片描述

更多查看日志命令 kubectl logs –help​​

8. cronJob

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

一个CronJob对象其实就对应crontab文件中的一行,它根据配置的时间格式周期性地运行一个Job,格式和crontab也是一样的。

crontab的格式如下:

分 时 日 月 星期 要运行的命令 第1列分钟 0~59 第2列小时 0~23) 第3列日 1~31 第4列月 1~12 第5列星期 0~7(0和7表示星期天) 第6列要运行的命令

Linux crontab 命令 | 菜鸟教程

# 现在,我们用CronJob来管理我们上面的Job任务
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: cronjob-demo
spec:
  schedule: "*/1 * * * *" #调度规则 */1 表示每分钟调度一次 
  jobTemplate: #任务模板
    spec:
      template: #描述pod
        spec:
          restartPolicy: OnFailure #pod重启策略
          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"
# 创建cronjob
kubctl apply -f cron-job.yaml
# 查询cronjob
kubectl get cronjob
# 查询jon ,cronjon会循环多个job
kubectl get job 
# 实时监控查询job 
kubectl get job -w

我们这里的Kind是CronJob了,要注意的是spec.schedule字段是必须填写的,用来指定任务运行的周期,格式就和crontab一样,另外一个字段是spec.jobTemplate, 用来指定需要运行的任务,格式当然和Job是一致的。还有一些值得我们关注的字段spec.successfulJobsHistoryLimit

在这里插入图片描述

使用镜像仓库的镜像: 在这里插入图片描述​​​​​

创建完cronjob后查看pod是没有的,因为策略是每分钟执行一次,还没到1分钟 在这里插入图片描述

等待1分钟后,查看job、pod: 在这里插入图片描述

到了指定时间后会创建pod,在pod内部进行调度

使用kubectl job -w(watche)进行监控,可以看到调用多次了 在这里插入图片描述

二、Pod’s lifecycle

1. 再次理解Pod

Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。Pods官方文档

Pod (就像在鲸鱼荚或者豌豆荚中)是一组(一个或多个) 容器; 这些容器共享存储、网络、以及怎样运行这些容器的声明。 Pod 中的内容总是并置(colocated)的并且一同调度,在共享的上下文中运行。 Pod 所建模的是特定于应用的“逻辑主机”,其中包含一个或多个应用容器, 这些容器是相对紧密的耦合在一起的。 在非云环境中,在相同的物理机或虚拟机上运行的应用类似于 在同一逻辑主机上运行的云应用。

除了应用容器,Pod 还可以包含在 Pod 启动期间运行的 Init 容器。 你也可以在集群中支持临时性容器 的情况外,为调试的目的注入临时性容器。

1.1 什么是 Pod?

除了 Docker 之外,Kubernetes 支持 很多其他容器运行时, Docker 是最有名的运行时, 使用 Docker 的术语来描述 Pod 会很有帮助。

Pod 的共享上下文包括一组 Linux 名字空间、控制组(cgroup)和可能一些其他的隔离 方面,即用来隔离 Docker 容器的技术。 在 Pod 的上下文中,每个独立的应用可能会进一步实施隔离。

就 Docker 概念的术语而言,Pod 类似于共享名字空间和文件系统卷的一组 Docker 容器。

1.2 使用 Pod

通常你不需要直接创建 Pod,甚至单实例 Pod。 相反,你会使用诸如 Deployment 或 Job 这类工作负载资源 来创建 Pod。如果 Pod 需要跟踪状态, 可以考虑 StatefulSet 资源。

这是因为 Pod 被设计成了相对临时性的、用后即抛的一次性实体。 当 Pod 由你或者间接地由 控制器 创建时,它被调度在集群中的节点上运行。 Pod 会保持在该节点上运行,直到 Pod 结束执行、Pod 对象被删除、Pod 因资源不足而被 驱逐 或者节点失效为止。

注意:重启 Pod 中的容器不应与重启 Pod 混淆。 Pod 不是进程,而是容器运行的环境。Pod 天生地为其成员容器提供了两种共享资源:网络 和 存储。 在被删除之前,Pod 会一直存在。

Kubernetes 集群中的 Pod 主要有两种用法:

  • 运行单个容器的 Pod。”每个 Pod 一个容器”模型是最常见的 Kubernetes 用例; 在这种情况下,可以将 Pod 看作单个容器的包装器,并且 Kubernetes 直接管理 Pod,而不是容器。
  • 运行多个协同工作的容器的 Pod。 Pod 可能封装由多个紧密耦合且需要共享资源的共处容器组成的应用程序。 这些位于同一位置的容器可能形成单个内聚的服务单元 —— 一个容器将文件从共享卷提供给公众, 而另一个单独的“挂斗”(sidecar)容器则刷新或更新这些文件。 Pod 将这些容器和存储资源打包为一个可管理的实体。

每个 Pod 都旨在运行给定应用程序的单个实例。如果希望横向扩展应用程序(例如,运行多个实例 以提供更多的资源),则应该使用多个 Pod,每个实例使用一个 Pod。 在 Kubernetes 中,这通常被称为 副本(Replication)。 通常使用一种工作负载资源及其控制器 来创建和管理一组 Pod 副本。

服务如何部署:

  • 1、建议一个pod中部署一个容器(通常情况下都是这样的)
  • 2、有一些业务上紧密耦合的服务,可以部署在一个容器,通信效率比较高。

2. Pod Phase

Pod 的生命周期 官方文档

Pod 的 status 属性是一个 PodStatus 对象,拥有一个 phase 字段。它简单描述了 Pod 在其生命周期的阶段。

阶段 描述
Pending(悬决) Pod 已被 Kubernetes 接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。
Running(运行中) Pod 已经绑定到了某个节点,Pod 中所有的容器都已被创建。至少有一个容器仍在运行,或者正处于启动或重启状态。
Succeeded(成功) Pod 中的所有容器都已成功终止,并且不会再重启。
Failed(失败) Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器以非 0 状态退出或者被系统终止。
Unknown(未知) 因为某些原因无法取得 Pod 的状态。这种情况通常是因为与 Pod 所在主机通信失败。

如果某节点死掉或者与集群中其他节点失联,Kubernetes 会实施一种策略,将失去的节点上运行的所有 Pod 的 phase 设置为 Failed。

3. 容器状态

Kubernetes 会跟踪 Pod 中每个容器的状态,就像它跟踪 Pod 总体上的阶段一样。 你可以使用容器生命周期回调 来在容器生命周期中的特定时间点触发事件。

一旦调度器将 Pod 分派给某个节点,kubelet 就通过 容器运行时 开始为 Pod 创建容器。 容器的状态有三种:Waiting(等待)、Running(运行中)和 Terminated(已终止)。

要检查 Pod 中容器的状态,可以使用如下命令,其输出中包含 Pod 中每个容器的状态:

kubectl describe pod <pod 名称>
  • Waiting (等待) 如果容器并不处在 Running 或 Terminated 状态之一,它就处在 Waiting 状态。 处于 Waiting 状态的容器仍在运行它完成启动所需要的操作:例如,从某个容器镜像 仓库拉取容器镜像,或者向容器应用 Secret 数据等等。 当你使用 kubectl 来查询包含 Waiting 状态的容器的 Pod 时,你也会看到一个 Reason 字段,其中给出了容器处于等待状态的原因。
  • Running(运行中) Running 状态表明容器正在执行状态并且没有问题发生。 如果配置了 postStart 回调,那么该回调已经执行且已完成。​​ 如果你使用 kubectl 来查询包含 Running 状态的容器的 Pod 时,你也会看到 关于容器进入 Running 状态的信息。
  • Terminated(已终止) 处于 Terminated 状态的容器已经开始执行并且或者正常结束或者因为某些原因失败。 如果你使用 kubectl 来查询包含 Terminated 状态的容器的 Pod 时,你会看到 容器进入此状态的原因、退出代码以及容器执行期间的起止时间。 如果容器配置了 preStop 回调,则该回调会在容器进入 Terminated 状态之前执行。​​

4. 容器重启策略

Pod 的 spec 中包含一个 restartPolicy 字段,其可能取值包括 Always、OnFailure 和 Never。默认值是 Always。

  • Always : 容器失效时,kubelet 自动重启该容器;
  • OnFailure : 容器终止运行且退出码不为0时重启;
  • Never : 不论状态为何, kubelet 都不重启该容器。

restartPolicy 适用于 Pod 中的所有容器。restartPolicy 仅针对同一节点上 kubelet 的容器重启动作。当 Pod 中的容器退出时,kubelet 会按指数回退 方式计算重启的延迟(10s、20s、40s、…),其最长延迟为 5 分钟。 一旦某容器执行了 10 分钟并且没有出现问题,kubelet 对该容器的重启回退计时器执行 重置操作。

5. 生命周期详解

pod生命周期示意图(初始化容器,post start,main container…,pre stop): 在这里插入图片描述

主容器,就是我们指定的镜像构建的容器

  • 说明:
    • 初始化容器阶段初始化pod中每一个init容器,他们是串行执行的,执行完成后就退出了
    • 启动主容器main container
    • 在main container刚刚启动之后可以执行post start命令
    • 在整个main container执行的过程中可以做两类探测:liveness probe(存活探测)和readiness probe(就绪探测)
    • 在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

6. pod init

理解 Init 容器 官方文档

6.1 理解init容器(初始化容器)

每个 Pod 中可以包含多个容器, 应用运行在这些容器里面,同时 Pod 也可以有一个或多个先于应用容器启动的 Init 容器。

Init 容器与普通的容器非常像,除了如下两点:

  • 它们总是运行到完成。
  • 每个都必须在下一个启动之前成功完成。(初始化容器是串行化过程)

如果 Pod 的 Init 容器失败,kubelet 会不断地重启该 Init 容器直到该容器成功为止。 然而,如果 Pod 对应的 restartPolicy 值为 “Never”,Kubernetes 不会重新启动 Pod。

在这里插入图片描述 图画错了,就绪探针不会重启

为 Pod 设置 Init 容器需要在 Pod 的 spec 中添加 initContainers 字段, 该字段以 Container 类型对象数组的形式组织,和应用的 containers 数组同级相邻。 Init 容器的状态在 status.initContainerStatuse 字段中以容器状态数组的格式返回 (类似 status.containerStatuses 字段)

6.2 init作用

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

  • Init 容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化代码。 例如,没有必要仅为了在安装过程中使用类似 sed、awk、python 或 dig 这样的工具而去 FROM 一个镜像来生成一个新的镜像。
  • Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。
  • 应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。
  • Init 容器能以不同于 Pod 内应用容器的文件系统视图运行。因此,Init 容器可以访问 应用容器不能访问的 Secret 的权限。
  • 由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器 提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。 一旦前置条件满足,Pod 内的所有的应用容器会并行启动。

原文地址:https://blog.csdn.net/weixin_41947378/category_10426192.html

请登录后发表评论

    没有回复内容