一.pod资源限制:
对pod资源限制原因:高并发占用所有的cpu资源、内存资源、会造成雪崩
当定义 Pod 时可以选择性地为每个容器设定所需要的资源数量。 最常见的可设定资源是 CPU 和内存大小,以及其他类型的资源。
方式:
- 对pod做限制
- 对k8s做限制
1.pod资源限制方式:
- 当定义 Pod 时可以选择性地为每个容器设定所需要的资源数量。
- 最常见的可设定资源是 CPU 和内存大小,以及其他类型的资源。
2.pod资源限制指定时指定的参数:
- request 资源:
当为 Pod 中的容器指定了 request 资源时,调度器就使用该信息来决定将 Pod 调度到哪个节点上。
- limit 资源:
当还为容器指定了 limit 资源时,kubelet 就会确保运行的容器不会使用超出所设的 limit 资源量。kubelet 还会为容器预留所设的 request 资源量, 供该容器使用。
如果 Pod 运行所在的节点具有足够的可用资源,容器可以使用超出所设置的 request 资源量。不过,容器不可以使用超出所设置的 limit 资源量。
- 两种资源匹配方式:
如果给容器设置了内存的 limit 值,但未设置内存的 request 值,Kubernetes 会自动为其设置与内存 limit 相匹配的 request 值。 类似的,如果给容器设置了 CPU 的 limit 值但未设置 CPU 的 request 值,则 Kubernetes 自动为其设置 CPU 的 request 值 并使之与 CPU 的 limit 值匹配。
3.资源限制的示例:
3.1官网示例:
Resource Management for Pods and Containers | Kubernetes
3.2Pod和容器的资源请求和限制格式:
#Pod 和 容器 的资源请求和限制:
spec.containers[].resources.requests.cpu //定义创建容器时预分配的CPU资源
spec.containers[].resources.requests.memory //定义创建容器时预分配的内存资源
spec.containers[].resources.limits.cpu //定义 cpu 的资源上限
spec.containers[].resources.limits.memory //定义内存的资源上限
3.3CPU 资源单位介绍:
- 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 资源。
4.案例一:OOMKilled:资源不足被杀死:
apiVersion: v1
kind: Pod
metadata:
name: ky-web-db
spec:
containers:
- name: web
image: nginx
env:
- name: WEB_ROOT_PASSWORD
value: "password"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: db
image: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "abc123"
resources:
requests:
memory: "64Mi"
cpu: "0.25"
limits:
memory: "128Mi"
cpu: "500m"
5.案例二 :给足资源:
apiVersion: v1
kind: Pod
metadata:
name: ky-web-db
spec:
containers:
- name: web
image: nginx
env:
- name: WEB_ROOT_PASSWORD
value: "password"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: db
image: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "abc123"
resources:
requests:
memory: "64Mi"
cpu: "0.5"
limits:
memory: "1Gi"
cpu: "1"
二、健康检查,又称为探针(Probe):
探针是由kubelet对容器执行的定期诊断
1.探针的三种规则:
livenessProbe :
判断容器是否正在运行。如果探测失败,则kubelet会杀死容器,并且容器将根据 restartPolicy 来设置 Pod 状态。 如果容器不提供存活探针,则默认状态为Success。
readinessProbe :
判断容器是否准备好接受请求。如果探测失败,端点控制器将从与 Pod 匹配的所有 service 址endpoints 中剔除删除该Pod的IP地。 初始延迟之前的就绪状态默认为Failure。如果容器不提供就绪探针,则默认状态为Success。
startupProbe(这个1.17版本增加的):
判断容器内的应用程序是否已启动,主要针对于不能确定具体启动时间的应用。如果配置了 startupProbe 探测,在则在 startupProbe 状态为 Success 之前,其他所有探针都处于无效状态,直到它成功后其他探针才起作用。 如果 startupProbe 失败,kubelet 将杀死容器,容器将根据 restartPolicy 来重启。如果容器没有配置 startupProbe, 则默认状态为 Success。 #注:以上规则可以同时定义。在readinessProbe检测成功之前,Pod的running状态是不会变成ready状态的。
2.Probe支持三种检查方法(探测):
exec:
在容器内执行指定命令。如果命令退出时返回码为0则认为诊断成功。
tcpSocket:
对指定端口上的容器的IP地址进行TCP检查(三次握手)。如果端口打开,则诊断被认为是成功的。
httpGet:
对指定的端口和路径上的容器的IP地址执行HTTPGet请求。如果响应的状态码大于等于200且小于400,则诊断被认为是成功的。
3.每次探测都将获得以下三种结果之一:
●成功:容器通过了诊断。
●失败:容器未通过诊断。
●未知:诊断失败,因此不会采取任何行动。
官网示例:
https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
4.探针三种方式示例:
4.1.exec方式:
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: busybox
imagePullPolicy: IfNotPresent
args: ###启动容器参数
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 60
livenessProbe: #定义了容器的就绪探针
exec: #在容器内执行指定命令。如果命令退出时返回码为0则认为诊断成功。
command: #指定了执行的命令
- cat
- /tmp/healthy
failureThreshold: 1 #就绪探针在连续失败一次后被视为失败
initialDelaySeconds: 5 #延迟5秒启动容器
periodSeconds: 5 #每隔5秒探测一次
// - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 60
创建一个名为 /tmp/healthy 的文件,暂停执行脚本,等待 30 秒钟,删除后,再次暂停执行脚本,等待额外的 60 秒钟
因为/tmp/healthy文件不存在,所以探测失败
4.2.httpGet方式:
apiVersion: v1
kind: Pod
metadata:
name: liveness-httpget
namespace: default
spec:
containers:
- name: liveness-httpget-container
image: soscscs/myapp:v1 #soscscs:nginx1.12
imagePullPolicy: IfNotPresent #拉取策略
ports:
- name: http
containerPort: 80
livenessProbe: #探针
httpGet:
port: http
path: /index.html
initialDelaySeconds: 1 #延迟1秒开始探测
periodSeconds: 3 #每3秒探测一次
timeoutSeconds: 10 #超时时间10秒
删除index.html:
查看:
当我们删除页面后,会报错404;然后就会探测失败,最后会重启
4.3tcpSocket方式:
apiVersion: v1
kind: Pod
metadata:
name: liveness-httpget
namespace: default
spec:
containers:
- name: liveness-httpget-container
image: soscscs/myapp:v1 #soscscs:nginx1.12
imagePullPolicy: IfNotPresent #拉取策略
ports:
- name: http
containerPort: 80
livenessProbe: #探针
httpGet:
port: http
path: /index.html
initialDelaySeconds: 1 #延迟1秒开始探测
periodSeconds: 3 #每3秒探测一次
timeoutSeconds: 10 #超时时间10秒
这个例子同时使用 readinessProbe 和 livenessProbe 探测。kubelet 会在容器启动 5 秒后发送第一个 readinessProbe 探测。这会尝试连接 goproxy 容器的 8080 端口。如果探测成功,kubelet 将继续每隔 10 秒运行一次检测。除了 readinessProbe 探测,这个配置包括了一个 livenessProbe 探测。kubelet 会在容器启动 15 秒后进行第一次 livenessProbe 探测。就像 readinessProbe 探测一样,会尝试连接 goproxy 容器的 8080 端口。如果 livenessProbe 探测失败,这个容器会被重新启动。
4.4.就绪探针readinessProbe1:
vim readiness-httpget.yaml
apiVersion: v1
kind: Pod
metadata:
name: readiness-httpget
namespace: default
spec:
containers:
- name: readiness-httpget-container
image: soscscs/myapp:v1 #指定了容器使用的镜像
imagePullPolicy: IfNotPresent #指定了镜像拉取策略为仅在本地不存在时才拉取
ports: #定义了容器暴露的端口,这里使用的是 80 端口
- name: http
containerPort: 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" 端口(实际上可能是 "http" 端口的映射,比如 8080)
path: /index.html #探测请求发送的路径为 "/index.html"
initialDelaySeconds: 1 #器启动后等待 1 秒后开始进行存活探测
periodSeconds: 3 #进行存活探测的间隔为 3 秒
timeoutSeconds: 10 #探测请求的超时时间为 10 秒
kubectl create -f readiness-httpget.yaml
#readiness探测失败,无法进入READY状态
kubectl get pods
kubectl exec -it readiness-httpget sh
cd /usr/share/nginx/html/
ls
50x.html index.html
echo 123 > index1.html
exit
kubectl get pods
4.5.就绪探针readinessProbe2:
vim readiness-myapp.yaml
---
apiVersion: v1
kind: Pod
metadata:
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
kubectl create -f readiness-myapp.yaml
kubectl get pods,svc,endpoints -o wide
kubectl exec -it pod/myapp1 -- rm -rf /usr/share/nginx/html/index.html
#readiness探测失败,Pod 无法进入READY状态,且端点控制器将从 endpoints 中剔除删除该 Pod 的 IP 地址
kubectl get pods,svc,endpoints -o wide
4.6.启动、退出动作 :
#启动、退出动作
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 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: 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
kubectl create -f post.yaml
kubectl get pods -o wide
kubectl exec -it lifecycle-demo -- cat /var/log/nginx/message
#在 node01 节点上查看
[root@node01 ~]# cd /data/volumes/nginx/log/
[root@node01 log]# ls
access.log error.log message
[root@node01 log]# cat message
Hello initContainers
Hello from the postStart handler
#由上可知,init Container先执行,然后当一个主容器启动后,Kubernetes 将立即发送 postStart 事件。
#在master删除 pod 后,再在 node01 节点上查看
kubectl delete pod lifecycle-demo
[root@node01 log]# cat message
Hello initContainers
Hello from the postStart handler
Hello from the poststop handler
#由上可知,当在容器被终结之前, Kubernetes 将发送一个 preStop 事件。
三、总结:
1.pod容器探针三种方式:
存活探针:
判断容器是否运行正常,如果探测失败则杀死容器(不是pod),容器根据容器策略决定是否重启
就绪探针:
判断pod是否能进入ready状态,做好接受请求的准备,如果探测失败会进入notready状态,并且从serivce资源的endpointis中的提出,service将不会再把访问请求转发给这个pod
启动探针:
判断容器内的应用是否启动成功,在探测成功状态为success之前,其他探针都会处于失效状态
2.三种探测方式:
exec:
通过command设置,执行在容器内执行的Linux命令来进行探测,如果返回码为0,则为探测成功;非0则为探测失败
httpget:
通过http get 请求访问指定容器端口和url路径,如果访问状态码为>=200且<400(2xx 300),则认为探测成功,否则失败
tcpsocket:
通过指定的端口发送tcp连接,如果端口无误且三次握手成功(tcp连接成功),则认为探测成功