前言
在 Kubernetes 中,定义 Pod 时可以选择性地为每个容器设定所需要的资源数量。 最常见的可设定资源是 CPU 和内存大小,以及其他类型的资源;另一方面,通过配置探针,可以确保容器在运行时保持健康,并且只有在准备好接收流量时才会被负载均衡器引导流量。从而提高应用程序的可靠性和稳定性。
目录
一、容器管理资源概念
1. 概述
在 K8s 中,对 Pod 容器的资源限制主要围绕着两个关键参数:request 资源和 limit 资源,用于配置 CPU 和内存的使用情况;避免资源竞争和不必要的浪费,同时确保 Pod 在运行时具有足够的资源支持。
参考官网示例:为 Pod 和容器管理资源 | Kubernetes
2. 资源请求和限制
针对每个容器,你都可以指定其资源限制和请求,包括如下选项:
2.1 request 预留资源
创建 pod 容器时需要预留的资源量,cpu(0.5 或 500m),内存 Mi、Gi(以2为底的幂数),M、G(以10为底)。
spec.containers[].resources.requests.cpu
spec.containers[].resources.requests.memory
2.2 limit 限制资源
pod 容器能够使用资源量的一个上限。如:4Gi 代表内存上限不允许超过上限值;1 代表 cpu 上限不允许超过上限值。
spec.containers[].resources.limits.cpu
spec.containers[].resources.limits.memory
3. K8s 中的资源单位
3.1 CPU 资源单位
在 K8s 中,一个 CPU 等于 1 个物理 CPU 核 或者 1 个虚拟核, 取决于节点是一台物理主机还是运行在某物理主机上的虚拟机。
当定义一个容器,将其 spec.containers[].resources.requests.cpu 设置为 0.5 时, 所请求的 CPU 是请求 1.0 CPU 时的一半。 对于 CPU 资源单位,数量表达式 0.1 等价于表达式 100m(一百毫核),可以看作 “100 millicpu”。
注意:K8s 不允许设置精度小于 1m 或 0.001 的 CPU 资源。
3.2 内存资源单位
memory 的限制和请求以字节为单位。 可以使用普通的整数,或者带有以下 数量后缀 的定点数字来表示内存:E、P、T、G、M、k。 也可以使用对应的 2 的幂数:Ei、Pi、Ti、Gi、Mi、Ki。
4. 资源限制配置规则
如果 Pod 运行所在的节点具有足够的可用资源,容器可以使用超出所设置的 request 资源量。不过,容器不可以使用超出所设置的 limit 资源量。
如果给容器设置了内存的 limit 值,但未设置内存的 request 值,Kubernetes 会自动为其设置与内存 limit 相匹配的 request 值;类似的 cpu 同理。
5. 容器资源示例
5.1 request 与 limit 创建 pod 模板
以下例子中的 Pod 有两个容器。每个容器的 request 值为 0.25 cpu 和 64MiB 内存,每个容器的 limit 值为 0.5 cpu 和 128MiB 内存。那么可以认为该 Pod 的总的资源 request 为 0.5 cpu 和 128 MiB 内存,总的资源 limit 为 1 cpu 和 256MiB 内存。
[root@master01 demo]# vim demo1.yaml
apiVersion: v1
kind: Pod
metadata:
name: demo-01
spec:
containers:
- name: app
image: images.my-company.example/app:v4
env: # 定义了容器的环境变量
- name: MYSQL_ROOT_PASSWORD # 设置环境变量
value: "123456" # 环境变量的值
resources: # 容器的资源限制和请求
requests: # 容器的资源请求
memory: "64Mi" # 请求容器使用的内存量为64MiB
cpu: "250m" # 请求容器使用的CPU量为250 m
limits: # 容器的资源限制
memory: "128Mi" # 限制容器使用的最大内存量为128MiB
cpu: "500m" # 限制容器使用的最大CPU量为500 m
- name: log-aggregator
image: images.my-company.example/log-aggregator:v6
resources: # 容器的资源限制和请求
requests: # 容器的资源请求
memory: "64Mi" # 容器使用的内存量为64MiB
cpu: "250m" # 第二个容器使用的CPU量为250 m
limits: # 容器的资源限制
memory: "128Mi" # 限制第二个容器使用的最大内存量为128MiB
cpu: "500m" # 限制第二个容器使用的最大CPU量为500 m
5.2 OOMKilled 内存耗尽保护机制
为了模拟内存耗尽情况并观察OOMKilled(Out Of Memory Killed)内存耗尽保护机制的效果,我们将调整数据库容器的资源请求(requests)和内存限制(limits)到一个较小的值,以便触发内存不足的情况。
请注意,在生产环境中,调整容器的资源请求和限制应该谨慎进行,以避免对系统产生不可预料的影响。
① 创建 yaml 文件
[root@master01 demo]# vim demo2.yaml
apiVersion: v1
kind: Pod
metadata:
name: web-db
spec:
containers:
- name: web
image: nginx
env:
- name: WEB_ROOT_PASSWORD
value: "123123"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: db
image: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "123123"
resources:
requests:
memory: "64Mi"
cpu: "0.25"
limits:
memory: "128Mi"
cpu: "500m"
② 启动 pod
[root@master01 demo]# kubectl apply -f demo2.yaml
pod/web-db created
③ 查看资源信息
[root@master01 demo]# kubectl get pod web-db -w
NAME READY STATUS RESTARTS AGE
web-db 0/2 ContainerCreating 0 18s
web-db 2/2 Running 0 63s
web-db 1/2 OOMKilled 0 76s
web-db 2/2 Running 1 93s
web-db 1/2 OOMKilled 1 105s
web-db 1/2 CrashLoopBackOff 1 2m
web-db 2/2 Running 2 2m1s
web-db 1/2 OOMKilled 2 2m14s
web-db 1/2 CrashLoopBackOff 2 2m28s
# 多次出现的 OOMKilled 表示容器由于内存耗尽而被系统终止
[root@master01 demo]# kubectl describe pod web-db
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 3m20s default-scheduler Successfully assigned default/web-db to node01
Normal Pulling 3m19s kubelet Pulling image "nginx"
Normal Pulled 3m4s kubelet Successfully pulled image "nginx" in 15.521857377s
Normal Created 3m4s kubelet Created container web
Normal Started 3m4s kubelet Started container web
Normal Pulled 2m18s kubelet Successfully pulled image "mysql" in 46.048445572s
Normal Pulled 108s kubelet Successfully pulled image "mysql" in 15.474925496s
Normal Pulled 80s kubelet Successfully pulled image "mysql" in 399.833869ms
Normal Pulling 38s (x4 over 3m4s) kubelet Pulling image "mysql"
Normal Created 38s (x4 over 2m17s) kubelet Created container db
Normal Started 38s (x4 over 2m17s) kubelet Started container db
Normal Pulled 38s kubelet Successfully pulled image "mysql" in 388.467767ms
Warning BackOff 13s (x5 over 95s) kubelet Back-off restarting failed container
# 容器 "db" 失败并且在多次尝试后仍然无法成功启动,导致触发了 BackOff 机制
④ 调整资源配额限制
[root@master01 demo]# kubectl delete -f demo2.yaml
pod "web-db" deleted
[root@master01 demo]# vim demo2.yaml
resources:
requests:
memory: "128Mi"
cpu: "0.5"
limits:
memory: "1Gi"
cpu: "1000m"
⑤ 再次尝试启动 pod
[root@master01 demo]# kubectl apply -f demo2.yaml
pod/web-db created
[root@master01 demo]# kubectl get pod web-db
NAME READY STATUS RESTARTS AGE
web-db 2/2 Running 0 42s
⑥ 查看 node 节点资源占比
[root@master01 demo]# kubectl get pod web-db -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-db 2/2 Running 0 94s 10.244.1.22 node01 <none> <none>
[root@master01 demo]# kubectl describe node node01
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits AGE
--------- ---- ------------ ---------- --------------- ------------- ---
default pod-01 0 (0%) 0 (0%) 0 (0%) 0 (0%) 4h19m
default web-db 750m (37%) 1500m (75%) 192Mi (11%) 1152Mi (66%) 2m13s
kube-flannel kube-flannel-ds-wz8p2 100m (5%) 0 (0%) 50Mi (2%) 0 (0%) 8d
kube-system kube-proxy-w7vl7 0 (0%) 0 (0%) 0 (0%) 0 (0%) 8d
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
Resource Requests Limits
-------- -------- ------
cpu 850m (42%) 1500m (75%)
memory 242Mi (14%) 1152Mi (66%)
ephemeral-storage 0 (0%) 0 (0%)
hugepages-1Gi 0 (0%) 0 (0%)
hugepages-2Mi 0 (0%) 0 (0%)
Pod "web-db" 的资源请求和限制如下:
- CPU 请求:750m,CPU 限制:1500m
- 内存请求:192Mi,内存限制:1152Mi
已分配的资源情况如下:
- CPU 请求总量:850m(42%),CPU 限制总量:1500m(75%)
- 内存请求总量:242Mi(14%),内存限制总量:1152Mi(66%)
二、Pod 容器的探针
1. 概述
探针是由 kubelet 对容器执行的定期诊断。容器的探针是一种关键的机制,用于监测和管理容器的健康状态,确保容器在各种情况下都能正常运行。通过配置适当的探针,可以提高容器的可靠性和稳定性,确保容器能够有效应对各种运行时情况,并及时处理健康状态的变化。
2. 探针的三种规则
在 Kubernetes 中,探针(Probes)用于监测容器的健康状态和确定容器是否已准备好接收流量。主要有三种类型的探针:
2.1 存活探针(Liveness Probe)
用于确定容器是否正在运行并且健康。如果存活探针失败,Kubernetes 将根据重启策略(如 `RestartPolicy`)尝试重新启动容器。如果容器不提供存活探针,则默认状态为 Success。
2.2 就绪探针(Readiness Probe)
用于确定容器是否已准备好接收流量。如果就绪探针失败,容器将被从 Service 的负载均衡池中移除该 Pod 的 IP 地址,直到就绪探针再次成功。初始延迟之前的就绪状态默认为 Failure。如果容器不提供就绪探针,则默认状态为 Success。
2.3 启动探针(Startup Probe)
1.17版本增加的。用于确定容器是否已经启动并且已经准备好接收其它探针的检查。启动探针在容器启动后执行,但在就绪探针和存活探针之前执行。
如果 startupProbe 失败,kubelet 将杀死容器,容器将根据 restartPolicy 来重启。如果容器没有配置 startupProbe, 则默认状态为 Success。
以上规则可以同时定义。在 readinessProbe 检测成功之前,Pod 的 running 状态是不会变成 ready 状态的。通过配置这些探针,可以确保容器在运行时保持健康,并且只有在准备好接收流量时才会被负载均衡器引导流量。这有助于提高应用程序的可靠性和稳定性。
3. 探针三种检查方法
- exec :在容器内执行指定命令。如果命令退出时返回码为0则认为诊断成功;
- tcpSocket :对指定端口上的容器的IP地址进行TCP检查(三次握手)。如果端口打开,则诊断被认为是成功的;
- httpGet :对指定的端口和路径上的容器的IP地址执行HTTPGet请求。如果响应的状态码大于等于200且小于400,则诊断被认为是成功的。
每次探测都将获得以下三种结果之一:
- 成功:容器通过了诊断;
- 失败:容器未通过诊断;
- 未知:诊断失败,因此不会采取任何行动。
4. 探针配置示例
4.1 定义存活命令
许多长时间运行的应用最终会进入损坏状态,除非重新启动,否则无法被恢复。 Kubernetes 提供了存活探针来发现并处理这种情况。
示例1:livenessProbe 规则,配合 exec 检查方法。
① 编辑 pod 的 yaml 配置文件
[root@master01 demo]# vim demo3.yaml
apiVersion: v1
kind: Pod
metadata: # 元数据
labels: # Pod 的标签
test: liveness
name: liveness-exec
spec: # Pod 的规格
containers: # 容器列表
- name: liveness # 容器的名称
image: busybox # 一个轻量级的 BusyBox 镜像
imagePullPolicy: IfNotPresent # 镜像拉取策略,先本地后仓库
args: # 容器的启动参数部分
- /bin/sh
- -c # 后面的内容将作为 shell 的命令执行
- touch /tmp/healthy; sleep 10; rm -rf /tmp/healthy; sleep 10
# 在容器启动时执行的命令,首先创建一个/tmp/healthy文件,然后等待10秒,接着删除该文件,最后再等待10秒
livenessProbe: # 定义存活探针的配置
exec: # 使用 exec 方式执行命令
command: # 要执行的命令
- cat
- /tmp/healthy # 读取 /tmp/healthy 文件的内容
failureThreshold: 1 # 存活探针的失败阈值为1,即连续失败1次后认为探针失败,默认值是3。最小值是1
initialDelaySeconds: 3 # 容器启动后等待3秒开始进行存活探测,其实是4秒,默认是0秒,最小值是0
periodSeconds: 2 # 每隔2秒进行一次存活探测,默认是10秒。最小值是1。
这个容器生命的前 10 秒,/tmp/healthy 文件是存在的。 所以在这最开始的 10 秒内,执行命令 cat /tmp/healthy 会返回成功代码。 10 秒之后,执行命令 cat /tmp/healthy 就会返回失败代码。
② 启动 pod
[root@master01 demo]# kubectl apply -f demo3.yaml
pod/liveness-exec created
③ 查看容器状态详情信息
[root@master01 demo]# kubectl get pod liveness-exec -w
NAME READY STATUS RESTARTS AGE
liveness-exec 1/1 Running 0 3s
liveness-exec 1/1 Running 1 22s
liveness-exec 1/1 Running 2 43s
liveness-exec 1/1 Running 3 63s
liveness-exec 1/1 Running 4 83s
liveness-exec 0/1 CrashLoopBackOff 4 103s
# Pod中的容器liveness由于存活探针失败而不断重启,并最终进入了CrashLoopBackOff状态
# 输出结果显示RESTARTS的值增加了1。 请注意,一旦失败的容器恢复为运行状态,RESTARTS计数器就会加1
查看 Pod 的事件:
[root@master01 demo]# kubectl describe pod liveness-exec
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 2m24s default-scheduler Successfully assigned default/liveness-exec to node01
Normal Pulled 62s (x5 over 2m24s) kubelet Container image "busybox" already present on machine
Normal Created 62s (x5 over 2m24s) kubelet Created container liveness
Normal Started 62s (x5 over 2m24s) kubelet Started container liveness
Warning Unhealthy 51s (x5 over 2m13s) kubelet Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
Normal Killing 51s (x5 over 2m13s) kubelet Container liveness failed liveness probe, will be restarted
# 显示存活探针失败了,这个失败的容器被杀死并且被重建了
# 是否重启还是根据重启策略来决定,这里明显是always
4.2 定义一个存活态 HTTP 请求接口
另外一种类型的存活探测方式是使用 HTTP GET 请求。
示例2:livenessProbe 规则,配合 httpGet 检查方法。
① 编辑 pod 的 yaml 配置文件
[root@master01 demo]# vim demo4.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-httpget
namespace: default
spec:
containers:
- name: liveness-httpget-container
image: soscscs/myapp:v1
imagePullPolicy: IfNotPresent # 镜像拉取策略
ports:
- name: http
containerPort: 80 # 容器内部的端口号为 80
livenessProbe: # 定义存活探针的配置
httpGet: # 使用HTTP GET请求方式进行探测
port: http # 探测请求发送到的端口为http,即容器内部的80端口
path: /index.html # 探测请求的路径为 /index.html
initialDelaySeconds: 1 # 容器启动后等待1秒后开始进行存活探测
periodSeconds: 3 # 每隔3秒进行一次存活探测
timeoutSeconds: 5 # 超时时间为5秒
如果存活探针发送的 HTTPGET 请求返回成功(即能够访问到 /index.html),则认为容器是健康的。如果请求失败(无法访问到 /index.html 或返回错误),则认为容器不健康处理程序返回失败代码,kubelet 会杀死这个容器并且重新启动它。
② 启动 pod
[root@master01 demo]# kubectl apply -f demo4.yaml
pod/liveness-httpget created
[root@master01 demo]# kubectl get pod liveness-httpget -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
liveness-httpget 1/1 Running 0 65s 10.244.1.24 node01 <none> <none>
尝试访问页面:
[root@master01 demo]# curl 10.244.1.24
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[root@master01 demo]# curl 10.244.1.24 -I
Server: nginx/1.12.2
③ 删除容器中 index.html
[root@master01 demo]# kubectl exec -it liveness-httpget -- rm -f /usr/share/nginx/html/index.html
③ 查看容器状态详情信息
[root@master01 demo]# kubectl get pod liveness-httpget
NAME READY STATUS RESTARTS AGE
liveness-httpget 1/1 Running 2 5m42s
[root@master01 demo]# kubectl describe pod liveness-httpget
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 6m32s default-scheduler Successfully assigned default/liveness-httpget to node01
Normal Pulling 6m32s kubelet Pulling image "soscscs/myapp:v1"
Normal Pulled 6m14s kubelet Successfully pulled image "soscscs/myapp:v1" in 18.054706565s
Normal Created 66s (x3 over 6m13s) kubelet Created container liveness-httpget-container
Warning Unhealthy 66s (x6 over 2m54s) kubelet Liveness probe failed: HTTP probe failed with statuscode: 404
Normal Killing 66s (x2 over 2m48s) kubelet Container liveness-httpget-container failed liveness probe, will be restarted
Normal Pulled 66s (x2 over 2m48s) kubelet Container image "soscscs/myapp:v1" already present on machine
Normal Started 65s (x3 over 6m13s) kubelet Started container liveness-httpget-container
容器中的存活探针失败是因为 HTTP 探测返回了状态码 404,表示无法访问到指定的路径 /index.html。因此,容器被标记为不健康,被 Kubernetes 系统自动重新启动以尝试恢复其健康状态。
4.3 定义 TCP 的存活探测
使用这种配置时,kubelet 会尝试在指定端口和容器建立套接字链接。 如果能建立连接,这个容器就被看作是健康的,如果不能则这个容器就被看作是有问题的。
示例3:livenessProbe 规则,配合 tcpSocket 检查方法。
① 编辑 pod 的 yaml 配置文件
[root@master01 demo]# vim demo5.yaml
apiVersion: v1
kind: Pod
metadata:
name: probe-tcp
spec:
containers:
- name: nginx
image: soscscs/myapp:v1
livenessProbe:
initialDelaySeconds: 5 # 容器启动后等待 5 秒后开始执行存活探针
timeoutSeconds: 1 # 探测超时时间为 1 秒
tcpSocket: # 使用 TCP 探测方式
port: 8080 # 探测的端口为 8080
periodSeconds: 10 # 每隔 10 秒执行一次存活探针
failureThreshold: 2 # 如果连续 2 次探测失败,则认为容器不健康
上面的 YAML 文件描述了一个名为 probe-tcp 的 Pod,其中包含一个名为 nginx 的容器,使用镜像 soscscs/myapp:v1,配置了一个针对端口 8080 的 TCP 探测器,用于检测容器的健康状态。由于业务本身端口是 80,所有这步就是探针肯定是失败的,持续查看探针过程。
② 启动 pod
[root@master01 demo]# kubectl apply -f demo5.yaml
pod/probe-tcp created
使用kubectl工具在名为probe-tcp的容器中执行netstat -natp命令:
[root@master01 demo]# kubectl exec -it probe-tcp -- netstat -natp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1/nginx: master pr
③ 持续查看容器状态详情信息
[root@master01 demo]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
probe-tcp 0/1 Pending 0 0s
probe-tcp 0/1 Pending 0 0s
probe-tcp 0/1 ContainerCreating 0 0s
probe-tcp 1/1 Running 0 2s
probe-tcp 1/1 Running 1 18s
probe-tcp 1/1 Running 2 38s
probe-tcp 1/1 Running 3 57s
probe-tcp 1/1 Running 4 78s
# 由于探测8080端口失败,可以看到 Pod 重启了多次
# 理论上第一次重启时间为:5+1+10=16秒
# 理论上第二次重启时间为:+20秒
# 理论上第三次重启时间为:+20秒
# 理论上第四次重启时间为:+20秒
4.4 定义 readinessProbe 就绪探针
有时候,应用会暂时性地无法为请求提供服务。 例如,应用在启动时可能需要加载大量的数据或配置文件,或是启动后要依赖等待外部服务。 在这种情况下,既不想杀死应用,也不想给它发送请求。 Kubernetes 提供了就绪探针来发现并缓解这些情况。 容器所在 Pod 上报还未就绪的信息,并且不接受通过 Kubernetes Service 的流量。
示例4: readinessProbe 和 livenessProbe 规则,配合 httpGet 检查方法。
① 编辑 pod 的 yaml 配置文件
[root@master01 demo]# vim demo6.yaml
apiVersion: v1
kind: Pod
metadata:
name: readiness-httpget
namespace: default
spec:
containers:
- name: readiness-httpget-container
image: soscscs/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80 # 指定容器将监听的端口为 80
readinessProbe: # 定义容器的就绪性探针
httpGet: # 指定用于就绪性检查的 HTTP GET 请求
port: 80 # 指定进行就绪性检查的端口(端口 80)
path: /index1.html # 指定就绪性检查期间请求的路径("/index1.html")
initialDelaySeconds: 1 # 指定容器启动后开始就绪性探针的等待时间(1 秒)
periodSeconds: 3 # 指定连续就绪性探针之间的间隔(3 秒)
livenessProbe: # 定义容器的存活性探针
httpGet: # 指定用于存活性检查的 HTTP GET 请求
port: http # 指定进行存活性检查的端口("http"端口)
path: /index.html # 指定存活性检查期间请求的路径("/index.html")
initialDelaySeconds: 1 # 指定容器启动后开始存活性探针的等待时间(1 秒)
periodSeconds: 3 # 指定连续存活性探针之间的间隔(3 秒)
timeoutSeconds: 10 # 指定存活性探针在等待响应的最大时间(10 秒)
② 启动 pod
[root@master01 demo]# kubectl apply -f demo6.yaml
pod/readiness-httpget created
③ 查看容器状态详情信息
[root@master01 demo]# kubectl get pod
NAME READY STATUS RESTARTS AGE
readiness-httpget 0/1 Running 0 17s
# 0/1表示该Pod中的容器当前处于未就绪状态
[root@master01 demo]# kubectl describe pod readiness-httpget
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 39s default-scheduler Successfully assigned default/readiness-httpget to node01
Normal Pulled 38s kubelet Container image "soscscs/myapp:v1" already present on machine
Normal Created 38s kubelet Created container readiness-httpget-container
Normal Started 38s kubelet Started container readiness-httpget-container
Warning Unhealthy 3s (x12 over 36s) kubelet Readiness probe failed: HTTP probe failed with statuscode: 404
# 就绪性探针失败,因为 HTTP 探测返回了状态码 404,由于就绪性探针配置中指定的路径/index1.html不存在或有误。
④ 创建 index1.html 页面
[root@master01 demo]# kubectl exec -it readiness-httpget sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # echo "index1" > /usr/share/nginx/html/index1.html
/ # exit
⑤ 再次查看 pod 状态
[root@master01 demo]# kubectl get pod
NAME READY STATUS RESTARTS AGE
readiness-httpget 1/1 Running 0 5m36s
# 已就绪
⑥ 删除原有 index.html,查看存活探针结果
[root@master01 demo]# kubectl get pod
NAME READY STATUS RESTARTS AGE
readiness-httpget 0/1 Running 1 9m32s
[root@master01 demo]# kubectl describe pod readiness-httpget
Warning Unhealthy 33s kubelet Liveness probe failed: HTTP probe failed with statuscode: 404
# 无法找到 index.html 页面
4.5 多资源配置就绪检测
下面这个 YAML 文件定义了三个名为 myapp1、myapp2 和 myapp3 的 Pod,它们使用相同的镜像并具有相似的配置,以及一个名为 myapp 的 Service,用于将流量路由到这些 Pod 上的端口 80。
测试目的:readiness 探测失败,pod 无法进入 ready 状态,则端点控制器会将 pod 从 endpoints 中剔除删除该 pod 的 IP 地址。
示例5: readinessProbe 规则,配合 httpGet 检查方法。
① 编辑 pod 的 yaml 配置文件
[root@master01 demo]# vim readiness-httpget.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp1
labels:
app: myapp
spec:
containers:
- name: myapp
image: soscscs/myapp:v1
ports:
- name: http
containerPort: 80 # 容器内部的端口号为 80
readinessProbe: # 定义了就绪性探针
httpGet: # 指定了使用 HTTP GET 请求进行探测
port: 80 # 指定了探测的端口为 80
path: /index.html # 指定健康检查发送请求的路径为 /index.html
initialDelaySeconds: 5 # 容器创建后等待 5 秒开始执行健康检查
periodSeconds: 5 # 每隔 5 秒进行一次健康检查
timeoutSeconds: 10 # 健康检查的超时时间为 10 秒
---
apiVersion: v1
kind: Pod
metadata:
name: myapp2
labels:
app: myapp
spec:
containers:
- name: myapp
image: soscscs/myapp:v1
ports:
- name: http
containerPort: 80
readinessProbe:
httpGet:
port: 80
path: /index.html
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 10
---
apiVersion: v1
kind: Pod
metadata:
name: myapp3
labels:
app: myapp
spec:
containers:
- name: myapp
image: soscscs/myapp:v1
ports:
- name: http
containerPort: 80
readinessProbe:
httpGet:
port: 80
path: /index.html
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
selector:
app: myapp
type: ClusterIP
ports:
- name: http
port: 80
targetPort: 80
② 启动 pod
[root@master01 demo]# kubectl apply -f readiness-httpget.yaml
pod/myapp1 created
pod/myapp2 created
pod/myapp3 created
service/myapp created
③ 查看 pod、svc 以及关联后端的节点信息
[root@master01 demo]# kubectl get pod,svc,endpoints -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/myapp1 1/1 Running 0 28s 10.244.1.27 node01 <none> <none>
pod/myapp2 1/1 Running 0 28s 10.244.2.10 node02 <none> <none>
pod/myapp3 1/1 Running 0 27s 10.244.1.28 node01 <none> <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 10d <none>
service/myapp ClusterIP 10.96.35.59 <none> 80/TCP 27s app=myapp
service/nginx NodePort 10.96.75.23 <none> 80:32165/TCP 10d app=nginx
service/nginx-deployment NodePort 10.96.101.251 <none> 30000:31603/TCP 9d app=nginx-deployment
NAME ENDPOINTS AGE
endpoints/kubernetes 192.168.190.100:6443 10d
endpoints/myapp 10.244.1.27:80,10.244.1.28:80,10.244.2.10:80 27s
endpoints/nginx <none> 10d
endpoints/nginx-deployment 10.244.1.10:80,10.244.1.11:80,10.244.2.6:80 9d
④ 删除 index.html
[root@master01 demo]# kubectl exec -it myapp3 -- rm -rf /usr/share/nginx/html/index.html
⑤ 再次查看关联后端的节点
[root@master01 demo]# kubectl get pod,svc,endpoints -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/myapp1 1/1 Running 0 2m42s 10.244.1.27 node01 <none> <none>
pod/myapp2 1/1 Running 0 2m42s 10.244.2.10 node02 <none> <none>
pod/myapp3 0/1 Running 0 2m41s 10.244.1.28 node01 <none> <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 10d <none>
service/myapp ClusterIP 10.96.35.59 <none> 80/TCP 2m41s app=myapp
service/nginx NodePort 10.96.75.23 <none> 80:32165/TCP 10d app=nginx
service/nginx-deployment NodePort 10.96.101.251 <none> 30000:31603/TCP 9d app=nginx-deployment
NAME ENDPOINTS AGE
endpoints/kubernetes 192.168.190.100:6443 10d
endpoints/myapp 10.244.1.27:80,10.244.2.10:80 2m41s
endpoints/nginx <none> 10d
endpoints/nginx-deployment 10.244.1.10:80,10.244.1.11:80,10.244.2.6:80 9d
此时可以看到对于 readiness 探测失败,pod myapp3 无法进入 reday 状态,端点控制器将 pod myapp3 的 ip 从 endpoints 中剔除删除。
4.6 启动和退出动作
以下将演示在 Kubernetes 中如何定义容器的生命周期事件,包括容器启动后和终止前的操作,以及如何使用初始化容器来执行特定任务。
示例6:根据日志反馈的内容了解容器处于生命周期的哪个阶段
① 编辑 pod 的 yaml 配置文件
[root@master01 demo]# vim post.yaml
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: soscscs/myapp:v1
lifecycle: # 此为关键字段,定义容器的生命周期
postStart: # 容器启动后执行的操作
exec: # 使用执行命令的方式
command: ["/bin/sh", "-c", "echo Hello Start >> /var/log/nginx/message"]
# 执行的命令是往日志中写入启动信息
preStop: # 容器终止前执行的操作
exec: # 使用执行命令的方式
command: ["/bin/sh", "-c", "echo Hello Stop >> /var/log/nginx/message"]
# 执行的命令是往日志中写入停止信息
volumeMounts: # 挂载卷到容器内部
- name: message-log # 卷的名称
mountPath: /var/log/nginx/ # 挂载路径
readOnly: false # 是否只读
initContainers: # 初始化容器
- name: init-myservice # 初始化容器的名称
image: soscscs/myapp:v1 # 初始化容器使用的镜像
command: ["/bin/sh", "-c", "echo 'Hello initContainers' >> /var/log/nginx/message"] # 初始化容器执行的命令,往日志中写入初始化信息
volumeMounts: # 挂载卷到容器内部
- name: message-log # 卷的名称
mountPath: /var/log/nginx/ # 挂载路径
readOnly: false # 是否只读
volumes: # 定义卷
- name: message-log # 卷的名称
hostPath: # 使用主机路径
path: /data/volumes/nginx/log/ # 主机上的路径
type: DirectoryOrCreate # 类型为目录或创建
② 启动 pod
[root@master01 demo]# kubectl create -f post.yaml
pod/lifecycle-demo created
③ 查看 pod 详情
[root@master01 demo]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
lifecycle-demo 1/1 Running 0 6s 10.244.1.29 node01 <none> <none>
④ 查看容器日志
[root@master01 demo]# kubectl exec -it lifecycle-demo -- cat /var/log/nginx/message
Hello initContainers
Start
由此可见,首先启动了 init 容器,然后启动成功后返回信息“Start”,代表启动成功。
⑤ 在 node01 节点查看日志
[root@node01 ~]# cd /data/volumes/nginx/log/
[root@node01 log]# ls
access.log error.log message
[root@node01 log]# cat message
Hello initContainers
Start
⑥ 删除 pod 后,再在 node01 节点上查看日志
[root@master01 demo]# kubectl delete pod lifecycle-demo
pod "lifecycle-demo" deleted
[root@node01 log]# cat message
Hello initContainers
Start
Stop
由此课件,当在容器被终结之前, Kubernetes 将发送一个 preStop 事件,即探针关闭生命周期结束。
三、补充概念
1. pod 的状态
pending
- pod已经被系统认可了,但是内部的container还没有创建出来。这里包含调度到node上的时间以及下载镜像的时间,会持续一小段时间;
Running
- pod已经与node绑定了(调度成功),而且pod中所有的container已经创建出来,至少有一个容器在运行中,或者容器的进程正在启动或者重启状态。--这里需要注意pod虽然已经Running了,但是内部的container不一定完全可用。因此需要进一步检测container的状态;
Succeeded
- 这个状态很少出现,表明pod中的所有container已经成功的terminated了,而且不会再被拉起了;
Failed
- pod中的所有容器都被terminated,至少一个container是非正常终止的。(退出的时候返回了一个非0的值或者是被系统直接终止)
unknown
- 由于某些原因pod的状态获取不到,有可能是由于通信问题。 一般情况下pod最常见的就是前两种状态。而且当Running的时候,需要进一步关注container的状态。
2. Container 生命周期
Waiting
- 启动到运行中间的一个等待状态;
Running
- 运行状态;
Terminated
- 终止状态。 如果没有任何异常的情况下,container应该会从Waiting状态变为Running状态,这时容器可用。
如果容器长时间处于 Waiting 状态,可以查看容器的 reason 字段,该字段会显示容器所处的状态和原因。如果 reason 显示容器再也无法启动,例如 ContainerCannotRun,整个服务启动就会迅速返回。这是一个失败状态返回的特性。
标签:容器,Kubernetes,demo,master01,探针,Pod,root,pod From: https://blog.csdn.net/qq_64612585/article/details/139181809