k8s学习-工作负载1

网友投稿 304 2022-09-10

k8s学习-工作负载1

容器组

Pod(容器组)是 Kubernetes 中最小的可部署单元。一个 Pod(容器组)包含了一个应用程序容器(某些情况下是多个容器)、存储资源、一个唯一的网络 IP 地址、以及一些确定容器该如何运行的选项。Pod 容器组代表了 Kubernetes 中一个独立的应用程序运行实例,该实例可能由单个容器或者几个紧耦合在一起的容器组成。

Docker 是 Kubernetes Pod 中使用最广泛的容器引擎;Kubernetes Pod 同时也支持其他类型的容器引擎。

Kubernetes 集群中的 Pod 存在如下两种使用途径:

一个 Pod 中只运行一个容器。"one-container-per-pod" 是 Kubernetes 中最常见的使用方式。此时,您可以认为 Pod 容器组是该容器的 wrapper,Kubernetes 通过 Pod 管理容器,而不是直接管理容器。一个 Pod 中运行多个需要互相协作的容器。您可以将多个紧密耦合、共享资源且始终在一起运行的容器编排在同一个 Pod 中,可能的情况有:

Content management systems, file and data loaders, local cache managers 等log and checkpoint backup, compression, rotation, snapshotting 等data change watchers, log tailers, logging and monitoring adapters, event publishers 等proxies, bridges, adapters 等controllers, managers, configurators, and updaters

每一个 Pod 容器组都是用来运行某一特定应用程序的一个实例。如果您想要水平扩展您的应用程序(运行多个实例),您运行多个 Pod 容器组,每一个代表应用程序的一个实例。Kubernetes 中,称其为 replication(复制副本)。Kubernetes 中 Controller(控制器)负责为应用程序创建和管理这些复制的副本。

Pod管理多个容器

Pod 的设计目的是用来支持多个互相协同的容器,是的他们形成一个有意义的服务单元。一个 Pod 中的多个容器很自然就可以随 Pod 被一起调度到集群中的同一个物理机或虚拟机上。Pod 中的容器可以:

共享资源、依赖互相通信相互协商何时以何种方式结束运行

​将多个容器运行于同一个容器组中是一种相对高级复杂的使用方法。只有在的容器相互之间紧密耦合是,才应该使用这种方式

某些 Pod 除了使用 app container (工作容器)以外,还会使用 init container (初始化容器),初始化容器运行并结束后,工作容器才开始启动。

Pod 为其成员容器提供了两种类型的共享资源:网络和存储

网络 Networking

每一个 Pod 被分配一个独立的 IP 地址。Pod 中的所有容器共享一个网络名称空间:

同一个 Pod 中的所有容器 IP 地址都相同同一个 Pod 中的不同容器不能使用相同的端口,否则会导致端口冲突同一个 Pod 中的不同容器可以通过 localhost:port 进行通信同一个 Pod 中的不同容器可以通过使用常规的进程间通信手段

不同 Pod 上的两个容器如果要通信,必须使用对方 Pod 的 IP 地址 + 对方容器的端口号 进行网络通信

存储 Storage

Pod 中可以定义一组共享的数据卷。Pod 中所有的容器都可以访问这些共享数据卷,以便共享数据。Pod 中数据卷的数据也可以存储持久化的数据,使得容器在重启后仍然可以访问到之前存入到数据卷中的数据。

使用容器组

应该尽量避免在 Kubernetes 中直接创建单个 Pod。因为在 Kubernetes 的设计中 Pod 是一个相对来说存活周期短暂,且随时会丢弃的实体。在 Pod 被创建后(您直接创建,或者间接通过 Controller 创建),将被调度到集群中的一个节点上运行。Pod 将一直保留在该节点上,直到 Pod 以下情况发生:

Pod 中的容器全部结束运行Pod 被删除由于节点资源不够,Pod 被驱逐节点出现故障(例如死机)

Pod 本身并不能自愈(self-healing)。如果一个 Pod 所在的 Node (节点)出现故障,或者调度程序自身出现故障,Pod 将被删除;同理,当因为节点资源不够或节点维护而驱逐 Pod 时,Pod 也将被删除。Kubernetes 通过引入 Controller(控制器)的概念来管理 Pod 实例。在 Kubernetes 中,更为推荐的做法是使用 Controller 来管理 Pod,而不是直接创建 Pod。

容器组和控制器

用户应该始终使用控制器来创建 Pod,而不是直接创建 Pod,控制器可以提供如下特性:

水平扩展(运行 Pod 的多个副本)rollout(版本更新)self-healing(故障恢复)例如:当一个节点出现故障,控制器可以自动地在另一个节点调度一个配置完全一样的 Pod,以替换故障节点上的 Pod。

在 Kubernetes 中,广泛使用的控制器有:

DeploymentStatefulSetDaemonSet

控制器通过其中配置的 Pod Template 信息来创建 Pod。

Pod Template

Pod Template 是关于 Pod 的定义,但是被包含在其他的 Kubernetes 对象中(例如 Deployment、StatefulSet、DaemonSet 等控制器)。控制器通过 Pod Template 信息来创建 Pod。正是由于 Pod Template 的存在,Kuboard 可以使用一个工作负载编辑器来处理不同类型的控制器。

终结pod

Pod 代表了运行在集群节点上的进程,而进程的终止有两种方式:

gracefully terminate (优雅地终止)直接 kill,此时进程没有机会执行清理动作

当用户发起删除 Pod 的指令时,Kubernetes 需要:

让用户知道 Pod 何时被删除确保删除 Pod 的指令最终能够完成

Kubernetes 收到用户删除 Pod 的指令后:

记录强制终止前的等待时长(grace period)向 Pod 中所有容器的主进程发送 TERM 信号一旦等待超时,向超时的容器主进程发送 KILL 信号删除 Pod 在 API Server 中的记录

举个例子:

用户通过 Kuboard 或者 kubectl 发起删除 Pod 的指令,默认 grace period (等待时长)为30秒Pod 的最大存活时间被更新,超过此存活时间,将被认为是“dead”Pod 的状态变更为 “Terminating”(与步骤 3 同时)Kubelet 识别出 Pod 的状态是 “Terminating”并立刻开始关闭 Pod 的过程如果 Pod 中的某个容器定义了 preStop hook,该钩子程序将被在容器内执行,如果 preStop hook 的执行超过了 grace period (等待时长),步骤二将被执行(并拥有额外的 2 秒等待时长)向容器的主进程发送 TERM 信号(与步骤 3 同时)将 Pod 从 Service 的 endpoint 列表中移除(Service 不再将请求路由到该 Pod)。一旦超过 grace period(等待时长),向 Pod 中的任何仍在运行的进程发送 KILL 信号Kubelet 将 Pod 从 API Server 中删除,Kuboard / kubectl 上不再显示该 Pod

默认情况下,删除 Pod 的 grace period(等待时长)是 30 秒。用户可以通过 kubectl delete 命令的选项 --grace-period= 自己指定 grace period(等待时长)。如果您要强制删除 Pod,您必须为 kubectl delete 命令同时指定两个选项 --grace-period=0 和 --force

生命周期

Pod phase

Pod phase 代表其所处生命周期的阶段。Pod phase 并不是用来代表其容器的状态,也不是一个严格的状态机

phase 的可能取值有:

Phase

描述

Pending

Kubernetes 已经创建并确认该 Pod。此时可能有两种情况:

  • Pod 还未完成调度(例如没有合适的节点)
  • 正在从 docker registry 下载镜像

    Running

    该 Pod 已经被绑定到一个节点,并且该 Pod 所有的容器都已经成功创建。其中至少有一个容器正在运行,或者正在启动/重启

    Succeeded

    Pod 中的所有容器都已经成功终止,并且不会再被重启

    Failed

    Pod 中的所有容器都已经终止,至少一个容器终止于失败状态:容器的进程退出码不是 0,或者被系统 kill

    Unknown

    因为某些未知原因,不能确定 Pod 的状态,通常的原因是 master 与 Pod 所在节点之间的通信故障

    Pod conditions

    每一个 Pod 都有一个数组描述其是否达到某些指定的条件

    字段名

    描述

    type

    type 是最重要的字段,可能的取值有:

    • PodScheduled:Pod 已被调度到一个节点
    • Ready:Pod 已经可以接受服务请求,应该被添加到所匹配 Service 的负载均衡的资源池
    • Initialized:Pod 中所有初始化容器已成功执行
    • Unschedulable:不能调度该 Pod(缺少资源或者其他限制)
    • ContainersReady:Pod 中所有容器都已就绪

            status

            能的取值有:

            • True
            • False
            • Unknown

                reason

                Condition 发生变化的原因,使用一个符合驼峰规则的英文单词描述

                message

                Condition 发生变化的原因的详细描述,human-readable

                lastTransitionTime

                Condition 发生变化的时间戳

                lastProbeTime

                上一次针对 Pod 做健康检查/就绪检查的时间戳

                容器的检查

                Probe 是指 kubelet 周期性地检查容器的状况。有三种类型的 Probe:

                ExecAction:在容器内执行一个指定的命令。如果该命令的退出状态码为 0,则成功TCPSocketAction:探测容器的指定 TCP 端口,如果该端口处于 open 状态,则成功HTTPGetAction:探测容器指定端口/路径上的 HTTP Get 请求,如果 HTTP 响应状态码在 200 到 400(不包含400)之间,则成功

                Probe 有三种可能的结果:

                Success:容器通过检测Failure:容器未通过检测Unknown:检测执行失败,此时 kubelet 不做任何处理

                Kubelet 可以在两种情况下对运行中的容器执行 Probe:

                就绪检查 readinessProbe:确定容器是否已经就绪并接收服务请求。如果就绪检查失败,kubernetes 将该 Pod 的 IP 地址从所有匹配的 Service 的资源池中移除掉。健康检查 livenessProbe:确定容器是否正在运行。如果健康检查失败,kubelete 将结束该容器,并根据 restart policy(重启策略)确定是否重启该容器。

                健康检查/就绪检查条件

                如果容器中的进程在碰到问题时可以自己 crash,您并不需要执行健康检查;kubelet 可以自动的根据 Pod 的 restart policy(重启策略)执行对应的动作如果您希望在容器的进程无响应后,将容器 kill 掉并重启,则指定一个健康检查 liveness probe,并同时指定 restart policy(重启策略)为 Always 或者 OnFailure如果您想在探测 Pod 确实就绪之后才向其分发服务请求,请指定一个就绪检查 readiness probe。此时,就绪检查的内容可能和健康检查相同。就绪检查适合如下几类容器:

                初始化时需要加载大量的数据、配置文件启动时需要执行迁移任务其他

                容器的状态

                一旦pod被调度到节点上,kubelet便开始使用容器引擎(通常是docker)创建容器。容易有三种可能的状态:

                Waiting:容器的初始状态。处于 Waiting 状态的容器,仍然有对应的操作在执行,例如:拉取镜像、应用 Secrets等。Running:容器处于正常运行的状态。容器进入 Running 状态之后,如果指定了 postStart hook,该钩子将被执行。Terminated:容器处于结束运行的状态。容器进入 Terminated 状态之前,如果指定了 preStop hook,该钩子将被执行。

                重启策略

                定义 Pod 或工作负载时,可以指定 restartPolicy,可选的值有:

                Always (默认值)OnFailureNever

                restartPolicy 将作用于 Pod 中的所有容器。kubelete 将在五分钟内,按照递延的时间间隔(10s, 20s, 40s ......)尝试重启已退出的容器,并在十分钟后再次启动这个循环,直到容器成功启动,或者 Pod 被删除。

                容器组的存活期

                通常,如果没有人或者控制器删除 Pod,Pod 不会自己消失。只有一种例外,那就是 Pod 处于 Scucceeded 或 Failed 的 phase,并超过了垃圾回收的时长(在 kubernetes master 中通过 terminated-pod-gc-threshold 参数指定),kubelet 自动将其删除。

                初始化容器

                Pod 可以包含多个工作容器,也可以包含一个或多个初始化容器,初始化容器在工作容器启动之前执行。

                初始化容器与工作容器完全相同,除了如下几点:

                初始化容器总是运行并自动结束kubelet 按顺序执行 Pod 中的初始化容器,前一个初始化容器成功结束后,下一个初始化容器才开始运行。所有的初始化容器成功执行后,才开始启动工作容器如果 Pod 的任意一个初始化容器执行失败,kubernetes 将反复重启该 Pod,直到初始化容器全部成功(除非 Pod 的 restartPolicy 被设定为 Never)初始化容器的 Resource request / limits 处理不同,请参考Resources初始化容器不支持就绪检查 readiness probe,因为初始化容器必须在 Pod ready 之前运行并结束

                使用初始化容器

                初始化容器可以指定不同于工作容器的镜像,这使得初始化容器相较于直接在工作容器中编写启动相关的代码更有优势:

                初始化容器可以包含工作容器中没有的工具代码或者自定义代码。例如:您无需仅仅为了少量的 setup 工作(使用 sed, awk, python 或 dig 进行环境设定)而重新从一个基础镜像制作另外一个镜像初始化容器可以更安全地执行某些使工作容器变得不安全的代码应用程序的镜像构建者和部署者可以各自独立地工作,而无需一起构建一个镜像初始化容器相较于工作容器,可以以另外一个视角处理文件系统。例如,他们可以拥有访问 Secrets 的权限,而工作容器却不一定被授予该权限初始化容器在任何工作容器启动之前结束运行,这个特性使得我们可以阻止或者延迟工作容器的启动,直到某些前提条件得到满足。一旦前提条件满足,所有的工作容器将同时并行启动。

                初始化容器的行为

                Pod 的启动时,首先初始化网络和数据卷,然后按顺序执行每一个初始化容器。任何一个初始化容器都必须成功退出,才能开始下一个初始化容器。如果某一个容器启动失败或者执行失败,kubelet 将根据 Pod 的 restartPolicy 决定是否重新启动 Pod。只有所有的初始化容器全都执行成功,Pod 才能进入 ready 状态。初始化容器的端口是不能够通过 kubernetes Service 访问的。Pod 在初始化过程中处于 Pending 状态,并且同时有一个 type 为initializing​ status 为True​ 的Condition如果 Pod 重启,所有的初始化容器也将被重新执行。您可以重启、重试、重新执行初始化容器,因此初始化容器中的代码必须是幂等的。具体来说,向 emptyDir 写入文件内容的代码应该考虑到该文件已经存在的情况。请参考幂等 获得更多信息您可以组合使用就绪检查和 activeDeadlineSecondsKuboard 暂不支持,以防止初始化容器始终失败。Pod 中不能包含两个同名的容器(初始化容器和工作容器也不能同名)。

                Resources

                在确定初始化容器的执行顺序以后,以下 resource 使用规则将适用:

                所有初始化容器中最高的 resource request/limit 是最终生效的 request/limit对于 Pod 来说,最终生效的 resource request/limit 是如下几个当中较高的一个:

                所有工作容器某一个 resource request/limit 的和最终生效的初始化容器的 request/limit 的和

                Kubelet 依据最终生效的 request/limit 执行调度,这意味着,在执行初始化容器时,就已经为 Pod 申请了其资源需求

                Pod 重启的原因

                Pod 重启时,所有的初始化容器都会重新执行,Pod 重启的原因可能有:

                用户更新了 Pod 的定义,并改变了初始化容器的镜像

                改变任何一个初始化容器的镜像,将导致整个 Pod 重启改变工作容器的镜像,将只重启该工作容器,而不重启 Pod

                Pod 容器基础设施被重启(例如 docker engine),这种情况不常见,通常只有 node 节点的 root 用户才可以执行此操作Pod 中所有容器都已经结束,restartPolicy 是 Always,且初始化容器执行的记录已经被垃圾回收,此时将重启整个 Pod

                理解POD的状态

                如果 Pod 的状态以 Init: 开头,表示该 Pod 正在执行初始化容器。下表描述了 Debug 初始化容器的过程中,一些可能出现的 Pod 状态:

                配置初始化容器

                ​​创建一个Pod,该Pod包含一个应用程序容器(工作容器)和一个初始化容器(Init Container)。初始化容器执行结束之后,应用程序容器(工作容器)才开始启动。

                Pod 的配置文件如下:

                apiVersion: v1kind: Podmetadata: name: init-demospec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: workdir mountPath: /usr/share/nginx/html # These containers are run during pod initialization initContainers: - name: install image: busybox command: - wget - "-O" - "/work-dir/index.html" - volumeMounts: - name: workdir mountPath: "/work-dir" dnsPolicy: Default volumes: - name: workdir emptyDir: {}

                常见容器问题排查

                状态机制

                因为 K8S 的设计是面向状态机的,它里面通过 yaml 的方式来定义的是一个期望到达的一个状态,而真正这个 yaml 在执行过程中会由各种各样的 controller来负责整体的状态之间的一个转换。

                开始它处在一个 pending 的状态,那接下来可能会转换到类似像 running,也可能转换到 Unknown,甚至可以转换到 failed。然后,当 running 执行了一段时间之后,它可以转换到类似像 successded 或者是 failed,然后当出现在 unknown 这个状态时,可能由于一些状态的恢复,它会重新恢复到 running 或者 successded 或者是 failed 。

                其实 K8s 整体的一个状态就是基于这种类似像状态机的一个机制进行转换的,而不同状态之间的转化都会在相应的 K8s对象上面留下来类似像 Status 或者像 Conditions 的一些字段来进行表示。

                比如说在 Pod 上面有一个字段叫 Status,这个 Status 表示的是 Pod 的一个聚合状态,在这个里面,这个聚合状态处在一个 pending 状态。

                然后再往下看,因为一个 pod 里面有多个 container,每个 container 上面又会有一个字段叫 State,然后 State 的状态表示当前这个 container 的一个聚合状态。那在这个例子里面,这个聚合状态处在的是 waiting 的状态,那具体的原因是因为什么呢?是因为它的镜像没有拉下来,所以处在 waiting 的状态,是在等待这个镜像拉取。然后这个 ready 的部分呢,目前是 false,因为它这个进行目前没有拉取下来,所以这个 pod 不能够正常对外服务,所以此时 ready 的状态是未知的,定义为 false。如果上层的 endpoint 发现底层这个 ready 不是 true 的话,那么此时这个服务是没有办法对外服务的。

                再往下是 condition,condition 这个机制表示是说:在 K8s 里面有很多这种比较小的这个状态,而这个状态之间的聚合会变成上层的这个 Status。那在这个例子里面有几个状态,第一个是 Initialized,表示是不是已经初始化完成?那在这个例子里面已经是初始化完成的,那它走的是第二个阶段,是在这个 ready 的状态。因为上面几个 container 没有拉取下来相应的镜像,所以 ready 的状态是 false。

                然后再往下可以看到这个 container 是否 ready,这里可以看到是 false,而这个状态是 PodScheduled,表示说当前这个 pod 是否是处在一个已经被调度的状态,它已经 bound 在现在这个 node 之上了,所以这个状态也是 true。

                那可以通过相应的 condition 是 true 还是 false 来判断整体上方的这个状态是否是正常的一个状态。而在 K8s 里面不同的状态之间的这个转换都会发生相应的事件,而事件分为两种: 一种叫做 normal 的事件,一种是 warning 事件。大家可以看见在这第一条的事件是有个 normal 事件,然后它相应的 reason 是 scheduler,表示说这个 pod 已经被默认的调度器调度到相应的一个节点之上,然后这个节点是 cn-beijing192.168.3.167 这个节点之上。

                再接下来,又是一个 normal 的事件,表示说当前的这个镜像在 pull 相应的这个 image。然后再往下是一个 warning 事件,这个 warning 事件表示说 pull 这个镜像失败了。

                以此类推,这个地方表示的一个状态就是说在 K8s 里面这个状态机制之间这个状态转换会产生相应的事件,而这个事件又通过类似像 normal 或者是 warning 的方式进行暴露。开发者可以通过类似像通过这个事件的机制,可以通过上层 condition Status 相应的一系列的这个字段来判断当前这个应用的具体的状态以及进行一系列的诊断。

                常见异常

                Pod 停留在 Pending

                第一个就是 pending 状态,pending 表示调度器没有进行介入。此时可以通过 kubectl describe pod 来查看相应的事件,如果由于资源或者说端口占用,或者是由于 node selector 造成 pod 无法调度的时候,可以在相应的事件里面看到相应的结果,这个结果里面会表示说有多少个不满足的 node,有多少是因为 CPU 不满足,有多少是由于 node 不满足,有多少是由于 tag 打标造成的不满足。

                Pod 停留在 waiting

                那第二个状态就是 pod 可能会停留在 waiting 的状态,pod 的 states 处在 waiting 的时候,通常表示说这个 pod 的镜像没有正常拉取,原因可能是由于这个镜像是私有镜像,但是没有配置 Pod secret;那第二种是说可能由于这个镜像地址是不存在的,造成这个镜像拉取不下来;还有一个是说这个镜像可能是一个公网的镜像,造成镜像的拉取失败。

                Pod 不断被拉取并且可以看到 crashing

                第三种是 pod 不断被拉起,而且可以看到类似像 backoff 。这个通常表示说 pod 已经被调度完成了,但是启动失败,那这个时候通常要关注的应该是这个应用自身的一个状态,并不是说配置是否正确、权限是否正确,此时需要查看的应该是 pod 的具体日志。

                Pod 处在 Runing 但是没有正常工作

                第四种 pod 处在 running 状态,但是没有正常对外服务。那此时比较常见的一个点就可能是由于一些非常细碎的配置,类似像有一些字段可能拼写错误,造成了 yaml 下发下去了,但是有一段没有正常地生效,从而使得这个 pod 处在 running 的状态没有对外服务,那此时可以通过 apply-validate-f pod.yaml 的方式来进行判断当前 yaml 是否是正常的,如果 yaml 没有问题,那么接下来可能要诊断配置的端口是否是正常的,以及 Liveness 或 Readiness 是否已经配置正确。

                Service 无法正常的工作

                最后一种就是 service 无法正常工作的时候,该怎么去判断呢?那比较常见的 service 出现问题的时候,是自己的使用上面出现了问题。因为 service 和底层的 pod 之间的关联关系是通过 selector 的方式来匹配的,也就是说 pod 上面配置了一些 label,然后 service 通过 match label 的方式和这个 pod 进行相互关联。如果这个 label 配置的有问题,可能会造成这个 service 无法找到后面的 endpoint,从而造成相应的 service 没有办法对外提供服务,那如果 service 出现异常的时候,第一个要看的是这个 service 后面是不是有一个真正的 endpoint,其次来看这个 endpoint 是否可以对外提供正常的服务。

                控制器

                Pod(容器组)是 Kubernetes 中最小的调度单元,您可以通过 kubectl 直接创建一个 Pod。Pod 本身并不能自愈(self-healing)。如果一个 Pod 所在的 Node (节点)出现故障,或者调度程序自身出现故障,Pod 将被删除;同理,当因为节点资源不够或节点维护而驱逐 Pod 时,Pod 也将被删除。

                Kubernetes 通过引入 Controller(控制器)的概念来管理 Pod 实例。在 Kubernetes 中,您应该始终通过创建 Controller 来创建 Pod,而不是直接创建 Pod。控制器可以提供如下特性:

                水平扩展(运行 Pod 的多个副本)rollout(版本更新)self-healing(故障恢复) 例如:当一个节点出现故障,控制器可以自动地在另一个节点调度一个配置完全一样的 Pod,以替换故障节点上的 Pod。

                ReplicaSet

                工作方式

                ReplicaSet的定义中,包含:

                selector: 用于指定哪些 Pod 属于该 ReplicaSet 的管辖范围replicas: 副本数,用于指定该 ReplicaSet 应该维持多少个 Pod 副本template: Pod模板,在 ReplicaSet 使用 Pod 模板的定义创建新的 Pod

                ReplicaSet 控制器将通过创建或删除 Pod,以使得当前 Pod 数量达到 replicas 指定的期望值。ReplicaSet 创建的 Pod 中,都有一个字段 metadata.ownerReferences 用于标识该 Pod 从属于哪一个 ReplicaSet。replicas​ 指定的期望值。ReplicaSet 创建的 Pod 中,都有一个字段 metadata.ownerReferences 用于标识该 Pod 从属于哪一个 ReplicaSet。

                ReplicaSet 通过 selector 字段的定义,识别哪些 Pod 应该由其管理。如果 Pod 没有 ownerReference 字段,或者 ownerReference 字段指向的对象不是一个控制器,且该 Pod 匹配了 ReplicaSet 的 selector,则该 Pod 的 ownerReference 将被修改为 该 ReplicaSet 的引用selector​ 字段的定义,识别哪些 Pod 应该由其管理。如果 Pod 没有 ownerReference 字段,或者 ownerReference 字段指向的对象不是一个控制器,且该 Pod 匹配了 ReplicaSet 的 selector,则该 Pod 的 ownerReference 将被修改为 该 ReplicaSet 的引用。

                使用ReplicaSet

                这也意味着,您也许永远不会直接操作 ReplicaSet 对象。但是,对其有一定的理解是有必要的,这样您才能更好的理解和使用 Deployment。

                举例

                apiVersion: apps/v1kind: ReplicaSetmetadata: name: frontend labels: app: guestbook tier: frontendspec: # modify replicas according to your case replicas: 3 selector: matchLabels: tier: frontend template: metadata: labels: tier: frontend spec: containers: - name: nginx image: nginx

                ReplicaSet 副本集的主要几个字段有:

                selector 确定哪些 Pod 属于该副本集replicas 副本集应该维护几个 Pod 副本(实例)template Pod 的定义

                副本集将通过创建、删除 Pod 容器组来确保符合 selector 选择器的 Pod 数量等于 replicas 指定的数量。当符合 selector 选择器的 Pod 数量不够时,副本集通过使用 template 中的定义来创建 Pod。

                在 Kubernetes 中,并不建议您直接使用 ReplicaSet,推荐使用 Deployment,由 Deployment 创建和管理 ReplicaSet。

                查看

                kubectl apply -f get rskubectl describe rs/frontend

                ReplicaSet的定义

                与其他 Kubernetes 对象一样,ReplicaSet需要的字段有:

                apiVersion:apps/v1kind:始终为 ReplicaSetmetadataspec: ReplicaSet 的详细定义

                Deployment

                创建Deployment

                下面的 yaml 文件定义了一个 Deployment,该 Deployment 将创建一个有 3 个 nginx Pod 副本的 ReplicaSet(副本集):

                apiVersion: apps/v1kind: Deploymentmetadata: name: nginx-deployment labels: app: nginxspec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80

                将创建一个名为 nginx-deployment 的 Deployment(部署),名称由.metadata.name 字段指定该 Deployment 将创建 3 个 Pod 副本,副本数量由.spec.replicas 字段指定.spec.selector 字段指定了 Deployment 如何找到由它管理的 Pod。此案例中,我们使用了 Pod template 中定义的一个标签(app: nginx)。对于极少数的情况,这个字段也可以定义更加复杂的规则.template 字段包含了如下字段:

                .template.metadata.labels 字段,指定了 Pod 的标签(app: nginx).template.spec.containers[].image 字段,表明该 Pod 运行一个容器nginx:1.7.9.template.spec.containers[].name 字段,表明该容器的名字是nginx

                kubectl apply -f get deployment # 查看############################输出如下NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGEnginx-deployment 3 0 0 0 1s

                字段名称

                说明

                NAME

                Deployment name

                DESIRED

                Deployment 期望的 Pod 副本数,即 Deployment 中 .spec.replicas 字段指定的数值。该数值是“期望”值

                CURRENT

                当前有多少个 Pod 副本数在运行

                UP-TO-DATE

                Deployment 中,符合当前 Pod Template 定义的 Pod 数量

                AVAILABLE

                当前对用户可用的 Pod 副本数

                AGE

                Deployment 部署以来到现在的时长

                更新

                当且仅当 Deployment 的 Pod template(.spec.template)字段中的内容发生变更时(例如标签、容器的镜像被改变),Deployment 的发布更新(rollout)将被触发。Deployment 中其他字段的变化(例如修改 .spec.replicas 字段)将不会触发 Deployment 的发布更新(rollout)

                #将容器镜像从 nginx:1.7.9 更新到 nginx:1.9.1kubectl --record deployment.apps/nginx-deployment set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1###################输出结果#####################deployment.apps/nginx-deployment image updated#或者使用edit修改kubectl edit deployment.v1.apps/nginx-deployment###################输出结果####################deployment.apps/nginx-deployment edited#查看滚动更新kubectl rollout status deployment.v1.apps/nginx-deployment###################输出结果###################Waiting for rollout to finish: 2 out of 3 new replicas have been updated...deployment.apps/nginx-deployment successfully rolled out#更新成功后查看更新结果kubectl get deployments####################输出结果###################NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGEnginx-deployment 3 3 3 3 36s

                Deployment Controller 先创建一个新 Pod,然后删除一个旧 Pod,然后再创建新的,如此循环,直到全部更新。Deployment Controller 不会 kill 旧的 Pod,除非足够数量的新 Pod 已经就绪,Deployment Controller 也不会创新新 Pod 直到足够数量的旧 Pod 已经被 kill。这个过程将确保更新过程中,任意时刻,最少 2 个 / 最多 4 个 Pod 可用。

                执行命令 kubectl describe deployments 查看 Deployment 详情,输出结果如下所示:

                Name: nginx-deploymentNamespace: defaultCreationTimestamp: Thu, 30 Nov 2017 10:56:25 +0000Labels: app=nginxAnnotations: deployment.kubernetes.io/revision=2Selector: app=nginxReplicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailableStrategyType: RollingUpdateMinReadySeconds: 0RollingUpdateStrategy: 25% max unavailable, 25% max surgePod Template:Labels: app=nginxContainers: nginx: Image: nginx:1.9.1 Port: 80/TCP Environment: Mounts: Volumes: Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailableOldReplicaSets: NewReplicaSet: nginx-deployment-1564180365 (3/3 replicas created)Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 2m deployment-controller Scaled up replica set nginx-deployment-2035384211 to 3 Normal ScalingReplicaSet 24s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 1 Normal ScalingReplicaSet 22s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 2 Normal ScalingReplicaSet 22s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 2 Normal ScalingReplicaSet 19s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 1 Normal ScalingReplicaSet 19s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 3 Normal ScalingReplicaSet 14s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 0

                回滚Deployment

                某些情况下,您可能想要回滚(rollback)Deployment,例如:Deployment 不稳定(可能是不断地崩溃)。默认情况下,kubernetes 将保存 Deployment 的所有更新(rollout)历史。您可以设定 revision history limit 来确定保存的历史版本数量。

                #回滚到前一个版本kubectl rollout undo deployment.v1.apps/nginx-deployment#回滚到指定的版本kubectl rollout undo deployment.v1.apps/nginx-deployment --to-revision=2

                伸缩Deployment

                伸缩(Scaling) Deployment,是指改变 Deployment 中 Pod 的副本数量,以应对实际业务流量的变化。

                #执行伸缩kubectl scale deployment.v1.apps/nginx-deployment --replicas=10#启用了自动伸缩,可以基于CPU利用率在一个最大和最小的区间自动伸缩kubectl autoscale deployment.v1.apps/nginx-deployment --min=10 --max=15 --cpu-percent=80###################输出结果############deployment.apps/nginx-deployment scaled

                按照比例伸缩

                滚动更新(RollingUpdate) Deployment 过程中同一时间点运行应用程序的多个版本。如果一个 Deployment 正在执行滚动更新(RollingUpdate)的过程中(也可能暂停了滚动更新),您或者自动伸缩器(autoscaler)对该 Deployment 执行伸缩操作,此时,Deployment Controller 会按比例将新建的 Pod 分配到当前活动的 ReplicaSet(有 Pod 的 ReplicaSet) 中,以避免可能的风险。这种情况叫做按比例伸缩(Proportional Scaling)

                暂停和继续

                您可以先暂停 Deployment,然后再触发一个或多个更新,最后再继续(resume)该 Deployment。这种做法使得您可以在暂停和继续中间对 Deployment 做多次更新,而无需触发不必要的滚动更新。

                #暂停 kubectl rollout pause deployment.v1.apps/nginx-deployment #更新镜像 kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1 #恢复 kubectl rollout resume deployment.v1.apps/nginx-deployment,

                查看状态

                Deployment 的生命周期中,将会进入不同的状态,这些状态可能是:

                Progressing 正在执行滚动更新completefail to progress

                Progressing 状态

                当如下任何一个任务正在执行时,Kubernete 将 Deployment 的状态标记为 progressing:

                Deployment 创建了一个新的 ReplicaSetDeployment 正在 scale up 其最新的 ReplicaSetDeployment 正在 scale down 其旧的 ReplicaSet新的 Pod 变为就绪(ready)或可用(available)

                可以使用命令 kubectl rollout status 监控 Deployment 滚动更新的过程

                Complete 状态

                如果 Deployment 符合以下条件,Kubernetes 将其状态标记为 complete:

                该 Deployment 中的所有 Pod 副本都已经被更新到指定的最新版本该 Deployment 中的所有 Pod 副本都处于可用(available)状态该 Deployment 中没有旧的 ReplicaSet 正在运行

                Failed 状态

                Deployment 在更新其最新的 ReplicaSet 时,可能卡住而不能达到 complete 状态。如下原因都可能导致此现象发生:

                集群资源不够就绪检查(readiness probe)失败镜像抓取失败权限不够资源限制应用程序的配置错误导致启动失败

                为了解决资源不足的问题,您可以尝试:

                scale down 您的 Deploymentscale down 其他的 Deployment向集群中添加计算节点

                如果资源足够,并且 Deployment 完成了其滚动更新,您将看到 Deployment 中出现一个成功的 condition(status=True 且 Reason=NewReplicaSetAvailable)。

                操作处于 Failed 状态的 Deployment

                您可以针对 Failed 状态下的 Deployment 执行任何适用于 Deployment 的指令,例如:

                scale up / scale down回滚到前一个版本暂停(pause)Deployment,以对 Deployment 的 Pod template 执行多处更新

                版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

                上一篇:#云原生征文#Kubernetes工作负载
                下一篇:公关界007:如何打造有温度的沟通?这个品牌照见城市脉动
                相关文章

                 发表评论

                暂时没有评论,来抢沙发吧~