Kubernetes应用程序生命周期管理
# Kubernetes应用程序生命周期管理
# 应用程序生命周期管理
在Kubernetes中部署应用流程
服务编排(YAML)
Deployment工作负载均衡器
- 介绍
- 应用生命周期管理流程
- 应用部署
- 应用升级
- 水平扩缩容 回滚
- 滚动升级与回滚实现机制
# 使用Deployment部署Java应用
使用Deployment控制器部署镜像:
创建一个Deployment控制器然后镜像使用的时nginx:latest
[root@master ~]# kubectl create deployment web --image=nginx:latest deployment.apps/web created
[root@master ~]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGEweb 0/1 1 0 11s
使用Service将Pod暴露出去:
[root@master ~]# kubectl expose deployment web --port=80 --target-port=80 --type=NodePort service/web exposed
访问应用:
[root@master ~]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 11h
web NodePort 10.99.251.101 <none> 80:30746/TCP 3m15shttp://NodeIP:Port
# 服务编排:YAML文件格式说明
在此之前学习ansible的时候就有学习过yaml文件格式
K8s是一个容器编排引擎,使用YAML文件编排要部署应用,因此在学习之前,应先了解YAML语法格式:
• 缩进表示层级关系
• 不支持制表符“tab”缩进,使用空格缩进
• 通常开头缩进 2 个空格
• 字符后缩进 1 个空格,如冒号、逗号等
• “---” 表示YAML格式,一个文件的开始
• “#”注释
# 服务编排:YAML文件创建资源对象
# 服务编排:YAML文件创建资源对象
服务编排:资源字段太多,记不住怎么办?
# 资源字段多的问题
- 用create命令生成
$ kubectl create deployment nginx --image=nginx:1.16 -o yaml --dry-run > my-deploy.yaml
- 用get命令导出
$ kubectl get deployment nginx -o yaml > my-deploy.yaml
- Pod容器的字段忘记拼写了
$ kubectl explain pods.spec.containers
$ kubectl explain deployment
# Pod
# Pod对象:基本概念
Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。
- Pod (就像在鲸鱼荚或者豌豆荚中)是一组(一个或多个) 容器 (opens new window); 这些容器共享存储、网络、以及怎样运行这些容器的声明。 Pod 中的内容总是并置(colocated)的并且一同调度,在共享的上下文中运行。 Pod 所建模的是特定于应用的“逻辑主机”,其中包含一个或多个应用容器, 这些容器是相对紧密的耦合在一起的。 在非云环境中,在相同的物理机或虚拟机上运行的应用类似于 在同一逻辑主机上运行的云应用。
- 除了应用容器,Pod 还可以包含在 Pod 启动期间运行的 Init 容器 (opens new window)。 你也可以在集群中支持临时性容器 (opens new window) 的情况下,为调试的目的注入临时性容器。
资源共享和通信:
Pod 使它的成员容器间能够进行数据共享和通信。Pod中的存储:
一个 Pod 可以设置一组共享的存储卷 (opens new window)。 Pod 中的所有容器都可以访问该共享卷,从而允许这些容器共享数据。 卷还允许 Pod 中的持久数据保留下来,即使其中的容器需要重新启动。
# 如何使用 Pod
通常你不需要直接创建 Pod,甚至单实例 Pod。 相反,你会使用诸如 Deployment (opens new window) 或 Job (opens new window) 这类工作负载资源 来创建 Pod。如果 Pod 需要跟踪状态, 可以考虑 StatefulSet (opens new window) 资源。
你很少在 Kubernetes 中直接创建一个个的 Pod,甚至是单实例(Singleton)的 Pod。 这是因为 Pod 被设计成了相对临时性的、用后即抛的一次性实体。 当 Pod 由你或者间接地由 控制器 (opens new window) 创建时,它被调度在集群中的节点 (opens new window)上运行。 Pod 会保持在该节点上运行,直到 Pod 结束执行、Pod 对象被删除、Pod 因资源不足而被 驱逐 或者节点失效为止。
Kubernetes 集群中的 Pod 主要有两种用法:
- 运行单个容器的 Pod。"每个 Pod 一个容器"模型是最常见的 Kubernetes 用例; 在这种情况下,可以将 Pod 看作单个容器的包装器,并且 Kubernetes 直接管理 Pod,而不是容器。
- 运行多个协同工作的容器的 Pod。 Pod 可能封装由多个紧密耦合且需要共享资源的共处容器组成的应用程序。 这些位于同一位置的容器可能形成单个内聚的服务单元 —— 一个容器将文件从共享卷提供给公众, 而另一个单独的“边车”(sidecar)容器则刷新或更新这些文件。 Pod 将这些容器和存储资源打包为一个可管理的实体。
# Pod 怎样管理多个容器
- Pod 被设计成支持形成内聚服务单元的多个协作过程(形式为容器)。 Pod 中的容器被自动安排到集群中的同一物理机或虚拟机上,并可以一起进行调度。 容器之间可以共享资源和依赖、彼此通信、协调何时以及何种方式终止自身。
- Pod 天生地为其成员容器提供了两种共享资源:网络 (opens new window)和 存储 (opens new window)。
# Pod 使用
说明: 重启 Pod 中的容器不应与重启 Pod 混淆。 Pod 不是进程,而是容器运行的环境。 在被删除之前,Pod 会一直存在。
Pod 和控制器
你可以使用工作负载资源来创建和管理多个 Pod。 资源的控制器能够处理副本的管理、上线,并在 Pod 失效时提供自愈能力。 例如,如果一个节点失败,控制器注意到该节点上的 Pod 已经停止工作, 就可以创建替换性的 Pod。调度器会将替身 Pod 调度到一个健康的节点执行。
# Pod 模版
- 负载 (opens new window)资源的控制器通常使用 Pod 模板(Pod Template) 来替你创建 Pod 并管理它们。
- Pod 模板是包含在工作负载对象中的规范,用来创建 Pod。这类负载资源包括 Deployment (opens new window)、 Job (opens new window) 和 DaemonSets (opens new window)等。
- 工作负载的控制器会使用负载对象中的
PodTemplate
来生成实际的 Pod。PodTemplate
是你用来运行应用时指定的负载资源的目标状态的一部分。
下面的示例是一个简单的 Job 的清单,其中的 template
指示启动一个容器。 该 Pod 中的容器会打印一条消息之后暂停。
apiVersion: batch/v1
kind: Job
metadata:
name: hello
spec:
template:
# 这里是 Pod 模版
spec:
containers:
- name: hello
image: busybox
command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
restartPolicy: OnFailure
# Pod 更新与替换
- 修改 Pod 模版或者切换到新的 Pod 模版都不会对已经存在的 Pod 起作用。 Pod 不会直接收到模版的更新。相反, 新的 Pod 会被创建出来,与更改后的 Pod 模版匹配。
- 当某工作负载的 Pod 模板被改变时,控制器会基于更新的模板 创建新的 Pod 对象而不是对现有 Pod 执行更新或者修补操作。
- Pod 的绝大多数元数据都是不可变的。例如,你不可以改变其
namespace
、name
、uid
或者creationTimestamp
字段;generation
字段是比较特别的,如果更新 该字段,只能增加字段取值而不能减少。 - 在更新
spec.activeDeadlineSeconds
字段时,以下两种更新操作是被允许的:- 如果该字段尚未设置,可以将其设置为一个正数;
- 如果该字段已经设置为一个正数,可以将其设置为一个更小的、非负的整数。
# 容器探针
Pr+obe 是由 kubelet 对容器执行的定期诊断。要执行诊断,kubelet 可以执行三种动作:
ExecAction
(借助容器运行时执行)TCPSocketAction
(由 kubelet 直接检测)HTTPGetAction
(由 kubelet 直接检测)
# Pod 的生命周期
- Pod 遵循一个预定义的生命周期,起始于
Pending
阶段 (opens new window),如果至少 其中有一个主要容器正常启动,则进入Running
,之后取决于 Pod 中是否有容器以 失败状态结束而进入Succeeded
或者Failed
阶段。 - 在 Pod 运行期间,
kubelet
能够重启容器以处理一些失效场景。 在 Pod 内部,Kubernetes 跟踪不同容器的状态 (opens new window) 并确定使 Pod 重新变得健康所需要采取的动作。 - Pod 在其生命周期中只会被调度 (opens new window)一次。 一旦 Pod 被调度(分派)到某个节点,Pod 会一直在该节点运行,直到 Pod 停止或者 被终止 (opens new window)。
# Pod 生命期
- [x] 和一个个独立的应用容器一样,Pod 也被认为是相对临时性(而不是长期存在)的实体。 Pod 会被创建、赋予一个唯一的 ID(UID (opens new window)), 并被调度到节点,并在终止(根据重启策略)或删除之前一直运行在该节点。
- [x] 如果一个节点 (opens new window)死掉了,调度到该节点 的 Pod 也被计划在给定超时期限结束后删除 (opens new window)。
- [x] Pod 自身不具有自愈能力。如果 Pod 被调度到某节点 (opens new window) 而该节点之后失效,Pod 会被删除;类似地,Pod 无法在因节点资源 耗尽或者节点维护而被驱逐期间继续存活。Kubernetes 使用一种高级抽象 来管理这些相对而言可随时丢弃的 Pod 实例,称作 控制器 (opens new window)。
- [x] 任何给定的 Pod (由 UID 定义)从不会被“重新调度(rescheduled)”到不同的节点; 相反,这一 Pod 可以被一个新的、几乎完全相同的 Pod 替换掉。 如果需要,新 Pod 的名字可以不变,但是其 UID 会不同。
- [x] 如果某物声称其生命期与某 Pod 相同,例如存储卷 (opens new window), 这就意味着该对象在此 Pod (UID 亦相同)存在期间也一直存在。 如果 Pod 因为任何原因被删除,甚至某完全相同的替代 Pod 被创建时, 这个相关的对象(例如这里的卷)也会被删除并重建。
# Pod 阶段
Pod 的阶段是 Pod 在其生命周期中所处位置的简单宏观概述。 该阶段并不是对容器或 Pod 状态的综合汇总,也不是为了成为完整的状态机。
Pending (悬决) | Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间, |
---|---|
Running (运行中) | Pod 已经绑定到了某个节点,Pod 中所有的容器都已被创建。至少有一个容器仍在运行,或者正处于启动或重启状态。 |
Succeeded (成功) | Pod 中的所有容器都已成功终止,并且不会再重启。 |
Failed (失败) | Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器以非 0 状态退出或者被系统终止。 |
Unknown (未知) | 因为某些原因无法取得 Pod 的状态。这种情况通常是因为与 Pod 所在主机通信失败。 |
如果某节点死掉或者与集群中其他节点失联,Kubernetes 会实施一种策略,将失去的节点上运行的所有 Pod 为 Failed
。
# 容器状态
Kubernetes 会跟踪 Pod 中每个容器的状态,就像它跟踪 Pod 总体上的阶段 (opens new window)一样。 你可以使用容器生命周期回调 (opens new window) 来在容器生命周期中的特定时间点触发事件。
一旦调度器 (opens new window)将 Pod 分派给某个节点,kubelet
就通过 容器运行时 (opens new window) 开始为 Pod 创建容器。
容器的状态有三种:
Waiting
(等待)Running
(运行中)Terminated
(已终止)
# 容器重启策略
Pod 的 spec
中包含一个 restartPolicy
字段,其可能取值包括 Always、OnFailure 和 Never。默认值是 Always。
restartPolicy
适用于 Pod 中的所有容器。restartPolicy
仅针对同一节点上 kubelet
的容器重启动作。当 Pod 中的容器退出时,kubelet
会按指数回退 方式计算重启的延迟(10s、20s、40s、...),其最长延迟为 5 分钟。 一旦某容器执行了 10 分钟并且没有出现问题,kubelet
对该容器的重启回退计时器执行 重置操作。
# Pod 状况
Pod 有一个 PodStatus 对象,其中包含一个 PodConditions (opens new window) 数组。Pod 可能通过也可能未通过其中的一些状况测试。
PodScheduled
:Pod 已经被调度到某节点;ContainersReady
:Pod 中所有容器都已就绪;Initialized
:所有的 Init 容器 (opens new window) 都已成功启动;Ready
:Pod 可以为请求提供服务,并且应该被添加到对应服务的负载均衡池中
type | Pod 状况的名称 |
---|---|
status | 表明该状况是否适用,可能的取值有 "True ", "False " 或 "Unknown " |
lastProbeTime | 上次探测 Pod 状况时的时间戳 |
lastTransitionTime | Pod 上次从一种状态转换到另一种状态时的时间戳 |
reason | 机器可读的、驼峰编码(UpperCamelCase)的文字,表述上次状况变化的原因 |
message | 人类可读的消息,给出上次状态转换的详细信息 |
# Pod 就绪态
FEATURE STATE:
Kubernetes v1.14 [stable]
你的应用可以向 PodStatus 中注入额外的反馈或者信号:Pod Readiness(Pod 就绪态)。 要使用这一特性,可以设置 Pod 规约中的
readinessGates
列表,为 kubelet 提供一组额外的状况供其评估 Pod 就绪态时使用。就绪态门控基于 Pod 的
status.conditions
字段的当前值来做决定。 如果 Kubernetes 无法在status.conditions
字段中找到某状况,则该状况的 状态值默认为 "False
"。
# 容器探针
Probe (opens new window) 是由 kubelet (opens new window) 对容器执行的定期诊断。 要执行诊断,kubelet 调用由容器实现的 Handler (opens new window) (处理程序)。有三种类型的处理程序:
- ExecAction (opens new window): 在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
- TCPSocketAction (opens new window): 对容器的 IP 地址上的指定端口执行 TCP 检查。如果端口打开,则诊断被认为是成功的。
- HTTPGetAction (opens new window): 对容器的 IP 地址上指定端口和路径执行 HTTP Get 请求。如果响应的状态码大于等于 200 且小于 400,则诊断被认为是成功的。
每次探测都将获得以下三种结果之一:
Success
(成功):容器通过了诊断。Failure
(失败):容器未通过诊断。Unknown
(未知):诊断失败,因此不会采取任何行动。
针对运行中的容器,kubelet
可以选择是否执行以下三种探针,以及如何针对探测结果作出反应:
livenessProbe
:指示容器是否正在运行。如果存活态探测失败,则 kubelet 会杀死容器, 并且容器将根据其重启策略 (opens new window)决定未来。如果容器不提供存活探针, 则默认状态为Success
。readinessProbe
:指示容器是否准备好为请求提供服务。如果就绪态探测失败, 端点控制器将从与 Pod 匹配的所有服务的端点列表中删除该 Pod 的 IP 地址。 初始延迟之前的就绪态的状态值默认为Failure
。 如果容器不提供就绪态探针,则默认状态为Success
。startupProbe
: 指示容器中的应用是否已经启动。如果提供了启动探针,则所有其他探针都会被 禁用,直到此探针成功为止。如果启动探测失败,kubelet
将杀死容器,而容器依其 重启策略 (opens new window)进行重启。 如果容器没有提供启动探测,则默认状态为Success
。# 何时该使用存活态探针?
- FEATURE STATE:
Kubernetes v1.0 [stable]
- 如果容器中的进程能够在遇到问题或不健康的情况下自行崩溃,则不一定需要存活态探针;
kubelet
将根据 Pod 的restartPolicy
自动执行修复操作。 - 如果你希望容器在探测失败时被杀死并重新启动,那么请指定一个存活态探针, 并指定
restartPolicy
为 "Always
" 或 "OnFailure
"。
- FEATURE STATE:
# 何时该使用就绪态探针?
FEATURE STATE:
Kubernetes v1.0 [stable]
如果要仅在探测成功时才开始向 Pod 发送请求流量,请指定就绪态探针。 在这种情况下,就绪态探针可能与存活态探针相同,但是规约中的就绪态探针的存在意味着 Pod 将在启动阶段不接收任何数据,并且只有在探针探测成功后才开始接收数据。
如果你希望容器能够自行进入维护状态,也可以指定一个就绪态探针,检查某个特定于 就绪态的因此不同于存活态探测的端点。
如果你的应用程序对后端服务有严格的依赖性,你可以同时实现存活态和就绪态探针。 当应用程序本身是健康的,存活态探针检测通过后,就绪态探针会额外检查每个所需的后端服务是否可用。 这可以帮助你避免将流量导向只能返回错误信息的 Pod。
说明:
请注意,如果你只是想在 Pod 被删除时能够排空请求,则不一定需要使用就绪态探针; 在删除 Pod 时,Pod 会自动将自身置于未就绪状态,无论就绪态探针是否存在。 等待 Pod 中的容器停止期间,Pod 会一直处于未就绪状态。
# 何时该使用启动探针?
FEATURE STATE:
Kubernetes v1.18 [beta]
对于所包含的容器需要较长时间才能启动就绪的 Pod 而言,启动探针是有用的。 你不再需要配置一个较长的存活态探测时间间隔,只需要设置另一个独立的配置选定, 对启动期间的容器执行探测,从而允许使用远远超出存活态时间间隔所允许的时长。
如果你的容器启动时间通常超出
initialDelaySeconds + failureThreshold × periodSeconds
总值,你应该设置一个启动探测,对存活态探针所使用的同一端点执行检查。periodSeconds
的默认值是 10 秒。你应该将其failureThreshold
设置得足够高, 以便容器有充足的时间完成启动,并且避免更改存活态探针所使用的默认值。 这一设置有助于减少死锁状况的发生。
# Pod对象:管理命令
创建Pod
[root@master ~]# vim pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: web
spec:
containers:
- name: container1
image: nginx
$ kubectl apply -f pod.yaml
pod/web created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
web 1/1 Running 0 2m23s
查看Pod
$ kubectl get pods
$ kubectl describe pod <Pod名称>
查看日志
$ kubectl logs <Pod名称> [-c container]
$ kubectl logs <Pod名称> [-c container] -f
[root@master ~]# kubectl logs web container1
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2021/10/27 02:26:25 [notice] 1#1: using the "epoll" event method
2021/10/27 02:26:25 [notice] 1#1: nginx/1.21.3
2021/10/27 02:26:25 [notice] 1#1: built by gcc 8.3.0 (Debian 8.3.0-6)
2021/10/27 02:26:25 [notice] 1#1: OS: Linux 3.10.0-862.2.3.el7.x86_64
2021/10/27 02:26:25 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2021/10/27 02:26:25 [notice] 1#1: start worker processes
2021/10/27 02:26:25 [notice] 1#1: start worker process 31
2021/10/27 02:26:25 [notice] 1#1: start worker process 32
进入容器终端
$ kubectl exec <Pod名称> [-c container] --bash
删除Pod
$ kubectl delete pod <Pod名称>
# Pod对象:重启策略+健康检查
# 重启策略
Always:
当容器终止退出后,总是重启容器,默认策略。OnFailure:
当容器异常退出后,(退出状态码非0)时,才重启容器。Never:
当容器终止退出,从不重启容器。
# 健康检查有以下两种类型
livenessProbe(存活检查):
如果检查失败,将杀死容器,根据Pod的restartPolicy来操作。readinessProbe(就绪检查):
如果检查失败,Kubernetes会把Pod从service endpoints中剔除。
# 支持以下三种检查方法
httpGet:
发送http请求,返回200-400范围状态码为成功。exec:
执行Shell命令返回状态码是0为成功。tcpSocket:
发起TCP Socket建立成功。
端口探测
[root@master ~]# cat pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: web
spec:
restartPolicy: Always #重启策略
containers:
- image: nginx
name: web
ports:
- containerPort: 80
readinessProbe: #端口探测
tcpSocket:
port: 80 #探测的端口是80
initialDelaySeconds: 30 #启动容器后多少秒健康检查
periodSeconds: 10 #以后间隔多少秒检查一次
[root@master ~]# kubectl apply -f pod.yaml
pod/web created
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
web 0/1 Running 0 97s
需要等到端口探测完成之后才能ready
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
web 1/1 Running 0 97s
http请求的健康检查
[root@master ~]# vim pod.yaml
tcpSocket:
apiVersion: v1
kind: Pod
metadata:
name: web
spec:
containers:
- image: nginx
name: web
ports:
- containerPort: 80
readinessProbe:
httpGet:
path: /index.html
port: 80
initialDelaySeconds: 30
periodSeconds: 10
[root@master ~]# kubectl apply -f pod.yaml
pod/web created
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
web 0/1 Running 0 19s
查看日志检查是否有健康检查成功
[root@master ~]# kubectl logs web web -f
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2021/10/27 12:10:13 [notice] 1#1: using the "epoll" event method
2021/10/27 12:10:13 [notice] 1#1: nginx/1.21.3
2021/10/27 12:10:13 [notice] 1#1: built by gcc 8.3.0 (Debian 8.3.0-6)
2021/10/27 12:10:13 [notice] 1#1: OS: Linux 3.10.0-862.2.3.el7.x86_64
2021/10/27 12:10:13 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2021/10/27 12:10:13 [notice] 1#1: start worker processes
2021/10/27 12:10:13 [notice] 1#1: start worker process 31
2021/10/27 12:10:13 [notice] 1#1: start worker process 32
172.25.253.138 - - [27/Oct/2021:12:10:45 +0000] "GET /index.html HTTP/1.1" 200 615 "-" "kube-probe/1.20" "-"
172.25.253.138 - - [27/Oct/2021:12:10:55 +0000] "GET /index.html HTTP/1.1" 200 615 "-" "kube-probe/1.20" "-"
示例:执行Shell命令
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
示例:HTTP请求
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: Custom-Header
value: Awesome
# Pod对象:lnit Container
lnit Container: 顾名思义,用于初始化工作,执行完就结束,可以理解为一次性任务。
支持大部分应用容器配置,但不支持健康检查
优先应用容器执行
应用场景:
环境检查: 例如确保应用容器依赖的服务启动后再启动应用容器
初始化配置: 例如给应用容器准备配置文件
示例:部署一个web网站,网站程序没有打包到镜像中,而是希望从代码仓库中动态拉取放到应用容器中。
[root@master ~]# cat init-container.yaml
apiVersion: v1
kind: Pod
metadata:
name: init-demo
spec:
initContainers:
- image: busybox
name: init-demo
command:
- wget
- "-O"
- "/opt/index.html"
- "http://www.ctnrs.com"
volumeMounts:
- name: wwwroot
mountPath: "/opt"
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: wwwroot
mountPath: /usr/share/nginx/html
volumes:
- name: wwwroot
emptyDir: {}
[root@master ~]# kubectl apply -f init-container.yaml
pod/init-demo created
因此,Pod中会有这几种类型的容器:
Infrastructure Container:
基础容器- 维护整个Pod的网络
InitContainers:
初始化容器- 先于业务容器开始执行
Containers:
业务容器- 并行启动
# Pod对象:静态Pod
静态 Pod(Static Pod) 直接由特定节点上的
kubelet
守护进程管理, 不需要API 服务器 (opens new window)看到它们。 尽管大多数 Pod 都是通过控制面(例如,Deployment (opens new window)) 来管理的,对于静态 Pod 而言,kubelet
直接监控每个 Pod,并在其失效时重启之。静态 Pod 通常绑定到某个节点上的 kubelet (opens new window)。 其主要用途是运行自托管的控制面。 在自托管场景中,使用
kubelet
来管理各个独立的 控制面组件 (opens new window)。kubelet
自动尝试为每个静态 Pod 在 Kubernetes API 服务器上创建一个 镜像 Pod (opens new window)。 这意味着在节点上运行的 Pod 在 API 服务器上是可见的,但不可以通过 API 服务器来控制。说明:
静态 Pod 的
spec
不能引用其他的 API 对象(例如:ServiceAccount (opens new window)、ConfigMap (opens new window)、Secret (opens new window)等)。
# 静态Pod的特点:
- Pod由特定节点上的kubelet管理
- 不能使用控制器
- Pod的名称标识当前节点的名称
- 在kubelet的配置文件下启动Pod无法使用kubectl删除,只能删除yaml文件,方便更新数据
# 在kubelet配置文件中启用静态Pod:
[root@master ~]# cat /var/lib/kubelet/config.yaml | grep staticPodPath:
staticPodPath: /etc/kubernetes/manifests
[root@master ~]# cd /etc/kubernetes/manifests/
[root@master manifests]# vim pod.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: mypod1
name: static-pod
spec:
containers:
- image: busybox
name: mypod1
command: ["/bin/sh", "-c","sleep 360000"]
# Deployment
# Deployment:应用生命周期管理流程
# Deployment:部署应用
- 创建deployment的yaml文件
[root@master ~]# cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: default
spec:
replicas: 3 # Pod副本预期数量
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web # Pod副本的标签
spec:
containers:
- name: web
image: nginx
- 部署nginx镜像
[root@master ~]# kubectl apply -f deployment.yaml
deployment.apps/web unchanged
[root@master ~]# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
web 2/3 2 2 3m
# Deployment:滚动升级
第二步:应用升级(更新镜像三种方式)
- kubectl apply -f xxx.yaml
- kubectl set image deployment/web nginx=nginx:1.16
- kubectl edit deployment/web
- 滚动升级:K8s对Pod升级的默认策略,通过使 用新版本Pod逐步更新旧版本Pod,实现零停机 发布,用户无感知。
使用kubectl set实现滚动升级
[root@master ~]# kubectl set image deployment/web web=nginx:1.16
deployment.apps/web image updated
# Deployment:水平扩缩容
第三步:水平扩缩容(启动多实例,提高并发)
修改yaml里replicas值,再apply
kubectl scale deployment web --replicas=10
注:replicas参数控制Pod副本数量
[root@master ~]# kubectl scale deployment/web --replicas=10
deployment.apps/web scaled
[root@master ~]# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
web 2/10 0 2 16m
# Deployment:回滚
第四步:回滚(发布失败恢复正常版本)
- kubectl rollout history deployment/web # 查看历史发布版本
- kubectl rollout undo deployment/web # 回滚上一个版本
- kubectl rollout undo deployment/web --to-revision=2 # 回滚历史指定版本
- 注:回滚是重新部署某一次部署时的状态,即当时版本所有配置
[root@master ~]# kubectl rollout history deployment/web
deployment.apps/web
REVISION CHANGE-CAUSE
1 <none>
2 <none>
[root@master ~]# kubectl rollout undo deployment/web
deployment.apps/web rolled back
[root@master ~]# kubectl rollout undo deployment/web --to-revision=2
deployment.apps/web rolled back
# Deployment:删除
最后,项目下线:
- kubectl delete deploy/web
- kubectl delete svc/web
[root@master ~]# kubectl delete deployment/web
deployment.apps "web" deleted
# Deployment:滚动升级与回滚实现机制
滚动更新策略
每次只升级一个或多个服务,升级完成加入生产环境,不断执行这个过 程,直到集群中的全部旧版升级新版本。
特点:
- 用户无感知,平滑过渡
缺点:
- 部署周期长
- 发布策略较复杂
# ReplicationController和ReplicaSet
# ReplicationController
实际工作中,很少单独操作Pod的,之所以k8s能够“自愈”,就是通过rc(ReplicationController)、rs(ReplicaSet)、Deployment等这些组件,再加上k8s核心controller工作机制来实现的。
ReplicationController(简称为RC)。
在旧版本的Kubernetes中,只有ReplicationController对象。它的主要作用是确保Pod以你指定的副本数运行,即如果有容器异常退出,会自动创建新的 Pod 来替代;而异常多出来的容器也会自动回收。可以说,通过ReplicationController,Kubernetes实现了集群的高可用性。ReplicationController(rc)在新的版本中,已经被ReplicaSet(rs)替换了,相对于rc,rs有更好的标签控制策略。
对于pod副本的控制作用,rs和rc的效果是一样的。**
# ReplicationController的使用
- 创建一个RC
- 快速生成一个deployment然后修改类型为replicationcontroller
[root@master ~]# cat nginx.yaml
apiVersion: v1 #api的版本用v1,deployment默认是apps/v1
kind: ReplicationController #指定资源类型是ReplicationController
metadata:
name: test-rc
spec:
replicas: 3 #副本控制在3
selector:
app: test-rc #标签选择器
template:
metadata:
labels:
app: test-rc
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
[root@master ~]# kubectl apply -f replicationcontroller.yaml
replicationcontroller/test-rc created
验证操作
- 查看生成的rc,查看pod副本数。
[root@master ~]# kubectl delete rc nginx-demo
replicationcontroller "nginx-demo" deleted
[root@master ~]# kubectl get rc
NAME DESIRED CURRENT READY AGE
test-rc 3 3 3 2m53s
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
test-rc-v952c 1/1 Running 0 3m
test-rc-vr252 1/1 Running 0 3m
test-rc-x42p9 1/1 Running 0 3m
操作pod,验证rc的副本控制效果。
- 可以直接删除pod,但由于rc设置了目标副本数——3个,所以使用kubectl delete命令删除pod后,又会马上创建一个新的pod,以便维持3个副本。
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
test-rc-v952c 1/1 Running 0 3m
test-rc-vr252 1/1 Running 0 3m
test-rc-x42p9 1/1 Running 0 3m
[root@master ~]# kubectl delete pods --all
pod "test-rc-v952c" deleted
pod "test-rc-vr252" deleted
pod "test-rc-x42p9" deleted
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
test-rc-dwqpf 0/1 ContainerCreating 0 19s
test-rc-r2pjp 0/1 ContainerCreating 0 19s
test-rc-s4j58 1/1 Running 0 19s
# 便捷的进行扩容和缩容
- 对其Pod进行扩展伸缩,扩展到5个副本
[root@master ~]# kubectl scale replicationcontroller test-rc --replicas=5
replicationcontroller/test-rc scaled
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
test-rc-dwqpf 1/1 Running 0 2m12s
test-rc-f75hw 1/1 Running 0 33s
test-rc-r2pjp 1/1 Running 0 2m12s
test-rc-s4j58 1/1 Running 0 2m12s
test-rc-w6tdr 1/1 Running 0 33s
# ReplicaSet
Kubernetes官方强烈建议避免直接使用ReplicaSet,而应该通过Deployment来创建RS和Pod。由于ReplicaSet是ReplicationController的代替物,因此用法基本相同,唯一的区别在于ReplicaSet支持集合式的selector。
作为ReplicationController的下一代,支持新的基于集合的标签选择算符。
# ReplicaSet控制器用途:
Pod副本数量管理,不断对比当前Pod数量与期望Pod数量
Deployment每次发布都会创建一个RS作为记录,用于实现回滚
- kubectl get rs #查看RS记录
- kubectl rollout history deployment web #版本对应RS记录
# ReplicaSet的使用
创建一个RS
创建一个replicaset的yaml
[root@master ~]# cat replicaset.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
labels:
tier: frontend
name: nginx
spec:
replicas: 3
selector:
matchLabels:
tier: fronted
template:
metadata:
labels:
tier: fronted
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
[root@master ~]# kubectl apply -f replicaset.yaml
replicaset.apps/nginx created
- 行验证replicaset和pods的数量
[root@master ~]# kubectl get replicaset
NAME DESIRED CURRENT READY AGE
nginx 3 3 3 3m1s
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-75rjb 1/1 Running 0 3m6s
nginx-87ncr 1/1 Running 0 3m6s
nginx-xsw76 1/1 Running 0 3m6s
###ReplicaSet的伸缩
使用Horizontal Pod Autoscaler(HPA)
RS可以通过HPA来根据一些运行时指标实现自动伸缩,下面是一个简单的例子:
下面的描述文件会创建一个名为frontend-scaler的HorizontalPodAutoscaler,它会根据CPU的运行参数来对名为frontend的RS进行自动伸缩。
[root@master ~]# cat hpa.yaml
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: frontend-scaler
spec:
scaleTargetRef:
kind: ReplicaSet
name: frontend #这里就可以绑定上面的标记对应的frontend
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 50
- 查看hpa的详细
[root@master ~]# kubectl apply -f hpa.yaml
horizontalpodautoscaler.autoscaling/frontend-scaler created
[root@master ~]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
frontend-scaler ReplicaSet/frontend <unknown>/50% 3 10 0 5s
最后我们总结下关于 RC / RS 的⼀些特性和作⽤吧:
⼤部分情况下,我们可以通过定义⼀个 RC 实现的 Pod 的创建和副本数
RC 中包含⼀个完整的 Pod 定义模块(不包含 apiversion 和 kind)
RC 是通过 label selector 机制来实现对 Pod 副本
通过改变 RC ⾥⾯的 Pod 副本数量,可以实现 Pod 的扩
通过改变 RC ⾥⾯的 Pod 模板中镜像版本,可以实现 Pod 的滚动升级功能(但是不⽀持⼀键回 滚,需要⽤相同的⽅法去修改镜像地址)
# HPA
# HPA的简要概述
- Kubernetes 为我们提供了这样⼀个资源对象:
Horizontal Pod Autoscaling (Pod⽔平⾃动 伸缩)
,简称 HPA 。 HAP 通过监控分析 RC 或者 Deployment 控制的所有 Pod 的负载变化情况来确定 是否需要调整 Pod 的副本数量,这是 HPA 最基本的原理。
HPA 在 kubernetes 集群中被设计成⼀个 controller ,我们可以简单的通过 kubectl autoscale 命令 来创建⼀个 HPA 资源对象, HPA Controller 默认30s轮询⼀次(可通过 kube-controller-manager 的标志 --horizontal-pod-autoscaler-sync-period 进⾏设置),查询指定的资源(RC或者 Deployment)中 Pod 的资源使⽤率,并且与创建时设定的值和指标做对⽐,从⽽实现⾃动伸缩的功能。
目前主要分两个版本,autoscaling/v1和autoscaling/v2beta2,v1版本只支持 cpu,v2beta2版本支持 自定义 ,内存 ,但是目前也仅仅是处于beta阶段。
# 安装Metrics Server
HPA需要从Metrics Server中获取Pod的CPU和内存Metrics,用来判断是否达到自动伸缩阈值。
Kubernetes集群使用Metrics Server来采集容器的CPU和内存使用情况,用来监控Node和Pod的CPU和内存使用情况,并用作HPA(自动横向扩展)。
[root@master ~]# wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.3.7/components.yaml
[root@master ~]# vim components.yaml
...
containers:
- name: metrics-server
image: lizhenliang/metrics-server:v0.3.7 #修改镜像
imagePullPolicy: IfNotPresent
args:
- --cert-dir=/tmp
- --secure-port=4443
- --kubelet-insecure-tls #不验证kubelet提供的https证书
- --kubelet-preferred-address-types=InternalIP #使用节点IP连接kubelet
...
[root@master ~]# kubectl delete -f components.yaml
clusterrole.rbac.authorization.k8s.io "system:aggregated-metrics-reader" deleted
clusterrolebinding.rbac.authorization.k8s.io "metrics-server:system:auth-delegator" deleted
rolebinding.rbac.authorization.k8s.io "metrics-server-auth-reader" deleted
Warning: apiregistration.k8s.io/v1beta1 APIService is deprecated in v1.19+, unavailable in v1.22+; use apiregistration.k8s.io/v1 APIService
apiservice.apiregistration.k8s.io "v1beta1.metrics.k8s.io" deleted
serviceaccount "metrics-server" deleted
deployment.apps "metrics-server" deleted
service "metrics-server" deleted
clusterrole.rbac.authorization.k8s.io "system:metrics-server" deleted
clusterrolebinding.rbac.authorization.k8s.io "system:metrics-server" deleted
- 检查监控资源是否正常运行
[root@master ~]# kubectl top nodes
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
master 182m 4% 2166Mi 28%
node 76m 1% 1818Mi 23%
# HPA的使用
- 创建⼀个 Deployment 管理的 Nginx Pod,然后利⽤ HPA 来进⾏⾃动扩缩容。
[root@master ~]# cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hpa-nginx-deployment
spec:
revisionHistoryLimit: 15
selector:
matchLabels:
app: hpa-nginx-deployment
template:
metadata:
labels:
app: hpa-nginx-deployment
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
- 查看deployment和pod
[root@master ~]# kubectl get deployments.apps
NAME READY UP-TO-DATE AVAILABLE AGE
hpa-nginx-deployment 1/1 1 1 3m58s
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
hpa-nginx-deployment-7d546c5c67-qdkhm 1/1 Running 0 4m2s
- 创建一个HPA,用kubectl autosca来创建
[root@master ~]# kubectl autoscale deployment hpa-nginx-deployment --max=10 --min=1 --cpu-percent=50 --dry-run -o yaml >> hpa.yaml
[root@master ~]# cat hpa.yaml
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: hpa-nginx-deployment
spec:
maxReplicas: 10 #最大伸缩副本到10
minReplicas: 1 #最小伸缩副本到1
scaleTargetRef: #伸缩副本的来源,资源类型,RC,RS,Deployment
apiVersion: apps/v1
kind: Deployment
name: hpa-nginx-deployment
targetCPUUtilizationPercentage: 50 #触发伸缩的cpu使⽤率
status:
currentCPUUtilizationPercentage: 48 #当前资源下pod的cpu使⽤率
currentReplicas: 1 #当前的副本数
desiredReplicas: 2 #期望的副本数
- 查看hpa的创建是否正确
[root@master ~]# kubectl apply -f hpa.yaml
horizontalpodautoscaler.autoscaling/hpa-nginx-deployment configured
[root@master ~]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
frontend-scaler ReplicaSet/frontend <unknown>/50% 3 10 0 125m
hpa-nginx-deployment Deployment/hpa-nginx-deployment <unknown>/50% 1 10 1 93s
# 模拟增加负载
- 打开一个新的Terminal,创建一个临时的pod
load-generator
,并在该pod中向php-apache
服务发起不间断循环请求,模拟增加php-apache
的负载(CPU使用率)。
[root@master ~]# kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh
#/ while sleep 0.01; do wget -q -O- http://10.244.167.145; done
- 模拟压力测试几分钟后,观察HPA:
[root@master ~]# kubectl get hpa php-apache
- HPA情况类似:
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache 250%/50% 1 10 5 4m45s
可以看到TARGETS(CPU使用率)的acutal值已升高到250% (超过了期望值50%),副本数REPLICAS也从1自动扩容到了5。
注意:如果Kubernetes集群worker节点的CPU资源已经不足,HPA自动扩容会失败,新扩容的pod会一直处在Pending状态。通过kubectl describe命令查看pod详细信息时,会看到“Insufficient cpu"的错误信息。
# Job 和 Cronjob
- 另外⼀类资源对象:Job,我们在⽇常的⼯作中经常都 会遇到⼀些需要进⾏批量数据处理和分析的需求,当然也会有按时间来进⾏调度的⼯作,在我们 的 Kubernetes 集群中为我们提供了 Job 和 CronJob 两种资源对象来应对我们的这种需求。
- Job 负责处理任务,即仅执⾏⼀次的任务,它保证批处理任务的⼀个或多个 Pod 成功结束。 ⽽ CronJob 则就是在 Job 上加上了时间调度。
# Job的使用
我们⽤ Job 这个资源对象来创建⼀个任务,我们定⼀个 Job 来执⾏⼀个倒计时的任务,定义 YAML ⽂ 件:
注意 Job 的
RestartPolicy 仅⽀持 Never 和 OnFailure 两种
,不⽀持 Always ,我们知道 Job 就相 当于来执⾏⼀个批处理任务,执⾏完就结束了,如果⽀持 Always 的话就陷⼊了死循环了
[root@master ~]# kubectl create job job-demo --image=busybox --dry-run -o yaml > job.yaml
[root@master ~]# cat job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: job-demo
spec:
template:
metadata:
spec:
containers:
- image: busybox
name: job-demo
command:
- "/bin/sh"
- "-c"
- "for i in 9 8 7 6 5 4 3 2 1; do echo $i; done"
restartPolicy: Never
- 然后来创建该 Job
[root@master ~]# kubectl apply -f job.yaml
job.batch/job-demo created.
[root@master ~]# kubectl get job
NAME COMPLETIONS DURATION AGE
job-demo 1/1 17s 2m54s
- 注意查看我们的 Pod 的状态,同样我们可以通过 kubectl logs 来查看当前任务的执⾏结果。
[root@master ~]# kubectl logs job-demo-ntxgx job-demo
9
8
7
6
5
4
3
2
1
# CronJob的使用
CronJob 其实就是在 Job 的基础上加上了时间调度,我们可以:在给定的时间点运⾏⼀个任务,也可 以周期性地在给定时间点运⾏。这个实际上和我们 Linux 中的 crontab 就⾮常类似了。
⼀个 CronJob 对象其实就对应中 crontab ⽂件中的⼀⾏,它根据配置的时间格式周期性地运⾏⼀ 个 Job ,格式和 crontab 也是⼀样的。
crontab 的格式如下: 分 时 ⽇ ⽉ 星期 要运⾏的命令 第1列分钟0~59 第2列⼩时0~23) 第3列⽇1~31 第4列⽉1~ 12 第5列星期0~7(0和7表示星期天) 第6列要运⾏的命令
# Cron 时间表语法
# ┌────────────────── 时区 (可选)
# | ┌───────────── 分钟 (0 - 59)
# | │ ┌───────────── 小时 (0 - 23)
# | │ │ ┌───────────── 月的某天 (1 - 31)
# | │ │ │ ┌───────────── month (1 - 12)
# | │ │ │ │ ┌───────────── 周的某天 (0 - 6)(周日到周一;在某些系统上,7 也是星期日)
# | │ │ │ │ │
# | │ │ │ │ │
# | │ │ │ │ │
# CRON_TZ=UTC * * * * *
# ┌───────────── 分钟 (0 - 59)
# │ ┌───────────── 小时 (0 - 23)
# │ │ ┌───────────── 月的某天 (1 - 31)
# │ │ │ ┌───────────── 月份 (1 - 12)
# │ │ │ │ ┌───────────── 周的某天 (0 - 6) (周日到周一;在某些系统上,7 也是星期日)
# │ │ │ │ │
# │ │ │ │ │
# │ │ │ │ │
# * * * * *
- 现在,我们⽤ CronJob 来管理我们上⾯的 Job 任务
[root@master ~]# kubectl create cronjob cronjob-demo --image=busybox --schedule "*/1 * * * *" --dry-run -o yaml > cronjob.yaml
[root@master ~]# cat cronjob1.yaml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: cronjob-demo1
spec:
jobTemplate:
metadata:
name: cronjob-demo1
spec:
template:
metadata:
spec:
containers:
- image: busybox
name: cronjob-demo1
args:
- "bin/sh"
- "-c"
- "for i in 9 8 7 6 5 4 3 2 1; do echo $i; done"
restartPolicy: OnFailure
schedule: '*/1 * * * *'
[root@master ~]# kubectl apply -f cronjob1.yaml
cronjob.batch/cronjob-demo1 created
这⾥的 Kind 是 CronJob 了,要注意的是 .spec.schedule 字段是必须填写的,⽤来指定任务运⾏ 的周期,格式就和
crontab
⼀样,另外⼀个字段是.spec.jobTemplate
, ⽤来指定需要运⾏的任务,格 式当然和 Job 是⼀致的段
.spec.successfulJobsHistoryLimit
和.spec.failedJobsHistoryLimit
,表示历史限制,是可选的 字段。它们指定了可以保留多少完成和失败的 Job ,默认没有限制,所有成功和失败的 Job 都会被保 留。然⽽,当运⾏⼀个 Cron Job 时, Job 可以很快就堆积很多,所以⼀般推荐设置这两个字段的 值。如果设置限制的值为 0,那么相关类型的 Job 完成后将不会被保留。查看当前的cronjob
[root@master ~]# kubectl get cronjobs.batch
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
cronjob-demo1 */1 * * * * False 1 11s 11m
[root@master ~]# kubectl get jobs
NAME COMPLETIONS DURATION AGE
cronjob-demo1-1636527840 1/1 17s 3m
cronjob-demo1-1636527900 1/1 17s 2m
cronjob-demo1-1636527960 1/1 17s 60s
job-demo 1/1 17s 49m
- 也可以⽤ kubectl run来创建⼀个CronJob:
[root@master ~]# kubectl run hello --schedule="*/1 * * * *" --restart=OnFailure --image=busybox -- /bin/sh -c "date; echo Hello from the Kubernetes cluster"
- 这将会终⽌正在创建的 Job。然⽽,运⾏中的 Job 将不会被终⽌,不会删除 Job 或 它们的 Pod。为了 清理那些 Job 和 Pod,需要列出该 Cron Job 创建的全部 Job,然后删除它们:
[root@master ~]# kubectl get job
NAME COMPLETIONS DURATION AGE
cronjob-demo1-1636528440 1/1 16s 3m
cronjob-demo1-1636528500 1/1 17s 2m
cronjob-demo1-1636528560 1/1 18s 60s
job-demo 1/1 17s 59m
[root@master ~]# kubectl get jobs
NAME COMPLETIONS DURATION AGE
cronjob-demo1-1636528500 1/1 17s 2m45s
cronjob-demo1-1636528560 1/1 18s 105s
cronjob-demo1-1636528620 1/1 17s 45s
job-demo 1/1 17s 60m
[root@master ~]# kubectl delete cronjob --all
cronjob.batch "cronjob-demo1" deleted