pod进阶
资源限制
当定义 Pod 时可以选择性地为每个容器设定所需要的资源数量。 最常见的可设定资源是 CPU 和内存大小,以及其他类型的资源。
当为 Pod 中的容器指定了 request 资源时,调度器就使用该信息来决定将 Pod 调度到哪个节点上。当还为容器指定了 limit 资源时,kubelet 就会确保运行的容器不会使用超出所设的 limit 资源量。kubelet 还会为容器预留所设的 request 资源量, 供该容器使用。
如果 Pod 运行所在的节点具有足够的可用资源,容器可以使用超出所设置的 request 资源量。不过,容器不可以使用超出所设置的 limit 资源量。
如果给容器设置了内存的 limit 值,但未设置内存的 request 值,Kubernetes 会自动为其设置与内存 limit 相匹配的 request 值。 类似的,如果给容器设置了 CPU 的 limit 值但未设置 CPU 的 request 值,则 Kubernetes 自动为其设置 CPU 的 request 值 并使之与 CPU 的 limit 值匹配。
Pod有以下几种可能的状态:
- Pending(等待中):Pod已被创建,但尚未被调度到任何节点上运行。
- Running(运行中):Pod已经调度到节点并正在运行中。
- Succeeded(成功):Pod中的所有容器已经成功地完成任务并且已经终止。
- Failed(失败):Pod中的至少一个容器已经以非正常方式退出。
- Unknown(未知):无法获取Pod的状态信息。
这些状态可以通过Kubernetes命令行工具(如kubectl)或Kubernetes API来查询和监控。请注意,具体的状态可能会因不同的环境和配置而有所差异。
生命周期的表示
容器的生命周期通常包含以下几个关键阶段的表示:
- 创建(Created):在此阶段,容器对象已被创建,但尚未分配给任何节点运行。
- 等待(Pending):容器已被调度到节点上,并等待资源分配和启动。
- 运行中(Running):容器正在运行中,且正常执行其指定的任务。
- 终止(Terminated):容器任务已完成或非正常退出,进入终止状态。 成功终止(Succeeded):容器内的应用程序成功完成任务并正常退出。 失败终止(Failed):容器内的应用程序以非正常方式退出,可能是发生了错误或异常。
- 删除(Deleted):容器对象已从集群中移除。
这些生命周期的表示可以通过监控和查询相关容器对象的状态来获取。具体的表示方式可能会根据使用的容器编排工具和配置而有所不同。
官网示例:
https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/
Pod 和 容器 的资源请求和限制:
针对每个容器,你都可以指定其资源限制和请求,包括如下选项:
spec.containers[].resources.requests.cpu //定义创建容器时预分配的CPU资源
spec.containers[].resources.requests.memory //定义创建容器时预分配的内存资源
spec.containers[].resources.limits.cpu //定义 cpu 的资源上限
spec.containers[].resources.limits.memory //定义内存的资源上限
资源类型
概述:
CPU 和内存都是一种资源类型。资源类型具有基本单位。 CPU 表示计算处理,以 Kubernetes CPU 为单位指定。 内存以字节为单位指定。 对于 Linux 工作负载,您可以指定巨大的页面资源。 大页面是 Linux 特有的功能,节点内核在其中分配内存块 比默认页面大小大得多。
分类:
1、CPU 资源单位
CPU 资源的 request 和 limit 以 cpu 为单位。Kubernetes 中的一个 cpu 相当于1个 vCPU(1个超线程)。
Kubernetes 也支持带小数 CPU 的请求。spec.containers[].resources.requests.cpu 为 0.5 的容器能够获得一个 cpu 的一半 CPU 资源(类似于Cgroup对CPU资源的时间分片)。表达式 0.1 等价于表达式 100m(毫核),表示每 1000 毫秒内容器可以使用的 CPU 时间总量为 0.1*1000 毫秒。
Kubernetes 不允许设置精度小于 1m 的 CPU 资源。
2、内存 资源单位
内存的 request 和 limit 以字节为单位。可以以整数表示,或者以10为底数的指数的单位(E、P、T、G、M、K)来表示, 或者以2为底数的指数的单位(Ei、Pi、Ti、Gi、Mi、Ki)来表示。
如:1KB=10^3=1000,1MB=10^6=1000000=1000KB,1GB=10^9=1000000000=1000MB
1KiB=2^10=1024,1MiB=2^20=1048576=1024KiB
PS:在买硬盘的时候,操作系统报的数量要比产品标出或商家号称的小一些,主要原因是标出的是以 MB、GB为单位的,1GB 就是1,000,000,000Byte,而操作系统是以2进制为处理单位的,因此检查硬盘容量时是以MiB、GiB为单位,1GiB=2^30=1,073,741,824,相比较而言,1GiB要比1GB多出1,073,741,824-1,000,000,000=73,741,824Byte,所以检测实际结果要比标出的少一些。
容器资源示例
以下 Pod 有两个容器。每个容器的请求为 0.25 CPU 和 64MiB(226 字节)内存, 每个容器的资源限制为 0.5 CPU 和 128MiB 内存。 你可以认为该 Pod 的资源请求为 0.5 CPU 和 128 MiB 内存,资源限制为 1 CPU 和 256MiB 内存。
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: app
image: images.my-company.example/app:v4
env:
- name: MYSQL_ROOT_PASSWORD
value: "password"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: log-aggregator
image: images.my-company.example/log-aggregator:v6
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
下面的文件进行修改
更改后:
资源不足导致的OOMKilled
由于MySQL的内核与内存资源需求大,需要提升资源数
扩展内存后,需要删除原有资源,从新创建,不然会报错
显示正常
可以查看资源不足的信息
查看在哪个节点
资源占用
健康检查:又称为探针(Probe)
探针是由kubelet对容器执行的定期诊断。
探针的三种规则:
1、livenessProbe :
判断容器是否正在运行。如果探测失败,则kubelet会杀死容器,并且容器将根据 restartPolicy 来设置 Pod 状态。 如果容器不提供存活探针,则默认状态为Success。
2、readinessProbe :
判断容器是否准备好接受请求。如果探测失败,端点控制器将从与 Pod 匹配的所有 service 址endpoints 中剔除删除该Pod的IP地。 初始延迟之前的就绪状态默认为Failure。如果容器不提供就绪探针,则默认状态为Success。
3、startupProbe
(这个1.17版本增加的):判断容器内的应用程序是否已启动,主要针对于不能确定具体启动时间的应用。如果配置了 startupProbe 探测,在则在 startupProbe 状态为 Success 之前,其他所有探针都处于无效状态,直到它成功后其他探针才起作用。 如果 startupProbe 失败,kubelet 将杀死容器,容器将根据 restartPolicy 来重启。如果容器没有配置 startupProbe, 则默认状态为 Success。
#注:以上规则可以同时定义。在readinessProbe检测成功之前,Pod的running状态是不会变成ready状态的。
Probe支持三种检查方法:
- exec :在容器内执行指定命令。如果命令退出时返回码为0则认为诊断成功。
- tcpSocket :对指定端口上的容器的IP地址进行TCP检查(三次握手)。如果端口打开,则诊断被认为是成功的。
- httpGet :对指定的端口和路径上的容器的IP地址执行HTTPGet请求。如果响应的状态码大于等于200且小于400,则诊断被认为是成功的
每次探测都将获得以下三种结果之一:
- 成功:容器通过了诊断。
- 失败:容器未通过诊断。
- 未知:诊断失败,因此不会采取任何行动
探针的类:
1、存活探针:
判断容器是否正常,如果探测失败这杀掉容器(不是pod),容器会根据容器策略决定是否重启
2、就绪探针:
判断坡度是否能进入到ready状态,做好就收到请求的准备:如果探测失败就会进入到农田ready状态,并且service资源的enpoints中提出,service将不会吧访问请求发给这个pod
3、启动探针:
判断容器是否成功:在探测成功后转台为service之前,其他探针都会处于失效效果
官网示例:
https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
三种探测方式
- exec: 通过command设置执行在容器内执行的linux 命今来探测,如果返回码为0,则为探测成功
- httpqet:通过http get 请求范文指定的容器端口和r路径,如果返回状态为>=200日< 400 (2xx 3xx),则认为探测成功
- tcpsocket: 通过指定的端口发送TCP 连接,如果端口无误 且三次握手成功(tcp连接成功),则认为探测成功
实例一;\exec方式
#initialDelaySeconds:指定 kubelet 在执行第一次探测前应该等待5秒,即第一次探测是在容器启动后的第6秒才开始执行。默认是 0 秒,最小值是 0。
#periodSeconds:指定了 kubelet 应该每 5 秒执行一次存活探测。默认是 10 秒。最小值是 1。
#failureThreshold: 当探测失败时,Kubernetes 将在放弃之前重试的次数。 存活探测情况下的放弃就意味着重新启动容器。就绪探测情况下的放弃 Pod 会被打上未就绪的标签。默认值是 3。最小值是 1。
#timeoutSeconds:探测的超时后等待多少秒。默认值是 1 秒。最小值是 1。(在 Kubernetes 1.20 版本之前,exec 探针会忽略 timeoutSeconds 探针会无限期地 持续运行,甚至可能超过所配置的限期,直到返回结果为止。)
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: k8s.gcr.io/busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 60
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
failureThreshold: 1
initialDelaySeconds: 5
periodSeconds: 5
实例二、http
kubectl get pod -w
表示成功
查看详细信息
网页访问正常
远程登陆
将indexhtml删除
重新请求两回
网络访问
当删除第三次也正常
示例3:tcpSocket方式
im tcpsocket.yaml
apiVersion: v1
kind: Pod
metadata:
name: probe-tcp
spec:
containers:
- name: nginx
image: nginx
livenessProbe:
initialDelaySeconds: 5
timeoutSeconds: 1
tcpSocket:
port: 8080
periodSeconds: 10
failureThreshold: 2
实例:就绪检测
apiVersion: v1
kind: Pod
metadata:
name: readiness-httpget
namespace: default
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
livenessProbe:
httpGet:
port: http
path: /index.html
initialDelaySeconds: 1
periodSeconds: 3
timeoutSeconds: 10
readinessProbe:
httpGet:
port: 80
path: /index1.html
initialDelaySeconds: 1
periodSeconds: 3
timeoutSeconds: 10
~
yaml文件创建成功
由上可看出,yaml文件不是根据从上到下的顺序执行的,而是根据(就绪探测在先,存货探针或则启动探针在后)然而,就绪探针的文件不存在,所以失败
进入环境,添加相应文件
运行正常
可以做个小测试:
kubectl exec -it readiness-httpget -- rm -rf /usr/share/nginx/html/index.html
kubectl get pods -w
实例;就绪测试2
可以参照这个进行创建yaml文件
vim readiness-myapp.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp1
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: 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
创建成功
删除其中一个的文件
由于探针失败,三个地址去除了一个失败的,成了两个
做一个小小的测试:
登陆环境,输入简单的语句,进行区分
访问
实例:启动、退出动作
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: nginx
lifecycle: #此为关键字段
postStart:
exec:
command: ["/bin/sh", "-c", "echo Hello from the postStart handler >> /var/log/nginx/message"]
preStop:
exec:
command: ["/bin/sh", "-c", "echo Hello from the poststop handler >> /var/log/nginx/message"]
volumeMounts:
- name: message-log
mountPath: /var/log/nginx/
readOnly: false
initContainers:
- name: init-myservice
image: nginx
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
创建
登录node2
忧伤可看出运行的顺序为
由上可知,init Container先执行,然后当一个主容器启动后,Kubernetes 将立即发送 postStart 事件。
删除pod后,在查看node节点上
由上可知,当在容器被终结之前, Kubernetes 将发送一个 preStop 事件。