Kubernetes中Pod容器的資源限制和探針配置方式
在 Kubernetes 中,定義 Pod 時(shí)可以選擇性地為每個(gè)容器設(shè)定所需要的資源數(shù)量。
最常見的可設(shè)定資源是 CPU 和內(nèi)存大小,以及其他類型的資源;另一方面,通過配置探針,可以確保容器在運(yùn)行時(shí)保持健康,并且只有在準(zhǔn)備好接收流量時(shí)才會(huì)被負(fù)載均衡器引導(dǎo)流量。
從而提高應(yīng)用程序的可靠性和穩(wěn)定性。
一、容器管理資源概念
1.1.概述
在 K8s 中,對(duì) Pod 容器的資源限制主要圍繞著兩個(gè)關(guān)鍵參數(shù):request 資源和 limit 資源,用于配置 CPU 和內(nèi)存的使用情況;避免資源競(jìng)爭(zhēng)和不必要的浪費(fèi),同時(shí)確保 Pod 在運(yùn)行時(shí)具有足夠的資源支持。
官網(wǎng)示例:
https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/
1.2. Pod 和 容器 的資源請(qǐng)求和限制
spec.containers[].resources.requests.cpu //定義創(chuàng)建容器時(shí)預(yù)分配的CPU資源 spec.containers[].resources.requests.memory //定義創(chuàng)建容器時(shí)預(yù)分配的內(nèi)存資源 spec.containers[].resources.limits.cpu //定義 cpu 的資源上限 spec.containers[].resources.limits.memory //定義內(nèi)存的資源上限
request 預(yù)留資源
創(chuàng)建 pod 容器時(shí)需要預(yù)留的資源量,cpu(0.5 或 500m),內(nèi)存 Mi、Gi(以2為底的冪數(shù)),M、G(以10為底)。
spec.containers[].resources.requests.cpu spec.containers[].resources.requests.memory
limit 限制資源
pod 容器能夠使用資源量的一個(gè)上限。如:4Gi 代表內(nèi)存上限不允許超過上限值;1 代表 cpu 上限不允許超過上限值。
spec.containers[].resources.limits.cpu spec.containers[].resources.limits.memory
1.3. K8s 中的資源單位
1.3.1 CPU 資源單位
CPU 資源的 request 和 limit 以 cpu 為單位。在 K8s 中,一個(gè) CPU 等于 1 個(gè)物理 CPU 核 或者 1 個(gè)虛擬核, 取決于節(jié)點(diǎn)是一臺(tái)物理主機(jī)還是運(yùn)行在某物理主機(jī)上的虛擬機(jī)。
當(dāng)定義一個(gè)容器,將其 spec.containers[].resources.requests.cpu 設(shè)置為 0.5 時(shí), 所請(qǐng)求的 CPU 是請(qǐng)求 1.0 CPU 時(shí)的一半。 對(duì)于 CPU 資源單位,數(shù)量表達(dá)式 0.1 等價(jià)于表達(dá)式 100m(一百毫核),可以看作 “100 millicpu”。
注意:K8s 不允許設(shè)置精度小于 1m 或 0.001 的 CPU 資源。
1.3.2 內(nèi)存資源單位
內(nèi)存的 request 和 limit 以字節(jié)為單位。 可以使用普通的整數(shù),或者帶有以下 數(shù)量后綴 的定點(diǎn)數(shù)字來表示內(nèi)存:E、P、T、G、M、k。 也可以使用對(duì)應(yīng)的 2 的冪數(shù):Ei、Pi、Ti、Gi、Mi、Ki。
PS:在買硬盤的時(shí)候,操作系統(tǒng)報(bào)的數(shù)量要比產(chǎn)品標(biāo)出或商家號(hào)稱的小一些,主要原因是標(biāo)出的是以 MB、GB為單位的,1GB 就是1,000,000,000Byte,而操作系統(tǒng)是以2進(jìn)制為處理單位的,因此檢查硬盤容量時(shí)是以MiB、GiB為單位,1GiB=2^30=1,073,741,824,相比較而言,1GiB要比1GB多出1,073,741,824-1,000,000,000=73,741,824Byte,所以檢測(cè)實(shí)際結(jié)果要比標(biāo)出的少一些。
1.4. 資源限制配置規(guī)則
如果 Pod 運(yùn)行所在的節(jié)點(diǎn)具有足夠的可用資源,容器可以使用超出所設(shè)置的 request 資源量。不過,容器不可以使用超出所設(shè)置的 limit 資源量。
如果給容器設(shè)置了內(nèi)存的 limit 值,但未設(shè)置內(nèi)存的 request 值,Kubernetes 會(huì)自動(dòng)為其設(shè)置與內(nèi)存 limit 相匹配的 request 值;類似的 cpu 同理。
1.5. 容器資源示例
1.5.1 request 與 limit 創(chuàng)建 pod 模板
以下例子中的 Pod 有兩個(gè)容器。每個(gè)容器的 request 值為 0.25 cpu 和 64MiB 內(nèi)存,每個(gè)容器的 limit 值為 0.5 cpu 和 128MiB 內(nèi)存。那么可以認(rèn)為該 Pod 的總的資源 request 為 0.5 cpu 和 128 MiB 內(nèi)存,總的資源 limit 為 1 cpu 和 256MiB 內(nèi)存。
[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: # 定義了容器的環(huán)境變量 - name: MYSQL_ROOT_PASSWORD # 設(shè)置環(huán)境變量 value: "123456" # 環(huán)境變量的值 resources: # 容器的資源限制和請(qǐng)求 requests: # 容器的資源請(qǐng)求 memory: "64Mi" # 請(qǐng)求容器使用的內(nèi)存量為64MiB cpu: "250m" # 請(qǐng)求容器使用的CPU量為250 m limits: # 容器的資源限制 memory: "128Mi" # 限制容器使用的最大內(nèi)存量為128MiB cpu: "500m" # 限制容器使用的最大CPU量為500 m - name: log-aggregator image: images.my-company.example/log-aggregator:v6 resources: # 容器的資源限制和請(qǐng)求 requests: # 容器的資源請(qǐng)求 memory: "64Mi" # 容器使用的內(nèi)存量為64MiB cpu: "250m" # 第二個(gè)容器使用的CPU量為250 m limits: # 容器的資源限制 memory: "128Mi" # 限制第二個(gè)容器使用的最大內(nèi)存量為128MiB cpu: "500m" # 限制第二個(gè)容器使用的最大CPU量為500 m
1.5.2. OOMKilled 內(nèi)存耗盡保護(hù)機(jī)制
為了模擬內(nèi)存耗盡情況并觀察OOMKilled(Out Of Memory Killed)內(nèi)存耗盡保護(hù)機(jī)制的效果,我們將調(diào)整數(shù)據(jù)庫容器的資源請(qǐng)求(requests)和內(nèi)存限制(limits)到一個(gè)較小的值,以便觸發(fā)內(nèi)存不足的情況。
請(qǐng)注意,在生產(chǎn)環(huán)境中,調(diào)整容器的資源請(qǐng)求和限制應(yīng)該謹(jǐn)慎進(jìn)行,以避免對(duì)系統(tǒng)產(chǎn)生不可預(yù)料的影響。
① 創(chuàng)建 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"
② 啟動(dòng) 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 # 多次出現(xiàn)的 OOMKilled 表示容器由于內(nèi)存耗盡而被系統(tǒng)終止 [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" 失敗并且在多次嘗試后仍然無法成功啟動(dòng),導(dǎo)致觸發(fā)了 BackOff 機(jī)制
④ 調(diào)整資源配額限制
[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"
⑤ 再次嘗試啟動(dòng) 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 節(jié)點(diǎn)資源占比
[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" 的資源請(qǐng)求和限制如下:
- CPU 請(qǐng)求:750m,CPU 限制:1500m
- 內(nèi)存請(qǐng)求:192Mi,內(nèi)存限制:1152Mi
已分配的資源情況如下:
- CPU 請(qǐng)求總量:850m(42%),CPU 限制總量:1500m(75%)
- 內(nèi)存請(qǐng)求總量:242Mi(14%),內(nèi)存限制總量:1152Mi(66%)
二、Pod 容器的探針
2.1. 概述
探針是由 kubelet 對(duì)容器執(zhí)行的定期診斷。容器的探針是一種關(guān)鍵的機(jī)制,用于監(jiān)測(cè)和管理容器的健康狀態(tài),確保容器在各種情況下都能正常運(yùn)行。通過配置適當(dāng)?shù)奶结?,可以提高容器的可靠性和穩(wěn)定性,確保容器能夠有效應(yīng)對(duì)各種運(yùn)行時(shí)情況,并及時(shí)處理健康狀態(tài)的變化。
2.2.探針的三種規(guī)則
2.2.1 存活探針(Liveness Probe)
用于確定容器是否正在運(yùn)行并且健康。如果存活探針失敗,Kubernetes 將根據(jù)重啟策略(如 `RestartPolicy`)嘗試重新啟動(dòng)容器。如果容器不提供存活探針,則默認(rèn)狀態(tài)為 Success。
2.2.2 就緒探針(Readiness Probe)
用于確定容器是否已準(zhǔn)備好接收流量。如果就緒探針失敗,容器將被從 Service 的負(fù)載均衡池中移除該 Pod 的 IP 地址,直到就緒探針再次成功。初始延遲之前的就緒狀態(tài)默認(rèn)為 Failure。如果容器不提供就緒探針,則默認(rèn)狀態(tài)為 Success。
2.2.3 啟動(dòng)探針(Startup Probe)
1.17版本增加的。用于確定容器是否已經(jīng)啟動(dòng)并且已經(jīng)準(zhǔn)備好接收其它探針的檢查。啟動(dòng)探針在容器啟動(dòng)后執(zhí)行,但在就緒探針和存活探針之前執(zhí)行。
如果 startupProbe 失敗,kubelet 將殺死容器,容器將根據(jù) restartPolicy 來重啟。如果容器沒有配置 startupProbe, 則默認(rèn)狀態(tài)為 Success。
以上規(guī)則可以同時(shí)定義。在 readinessProbe 檢測(cè)成功之前,Pod 的 running 狀態(tài)是不會(huì)變成 ready 狀態(tài)的。通過配置這些探針,可以確保容器在運(yùn)行時(shí)保持健康,并且只有在準(zhǔn)備好接收流量時(shí)才會(huì)被負(fù)載均衡器引導(dǎo)流量。這有助于提高應(yīng)用程序的可靠性和穩(wěn)定性。
2.3. 探針三種檢查方法
- exec :在容器內(nèi)執(zhí)行指定命令。如果命令退出時(shí)返回碼為0則認(rèn)為診斷成功;
- tcpSocket :對(duì)指定端口上的容器的IP地址進(jìn)行TCP檢查(三次握手)。如果端口打開,則診斷被認(rèn)為是成功的;
- httpGet :對(duì)指定的端口和路徑上的容器的IP地址執(zhí)行HTTPGet請(qǐng)求。如果響應(yīng)的狀態(tài)碼大于等于200且小于400,則診斷被認(rèn)為是成功的。
每次探測(cè)都將獲得以下三種結(jié)果之一:
- 成功:容器通過了診斷;
- 失敗:容器未通過診斷;
- 未知:診斷失敗,因此不會(huì)采取任何行動(dòng)。
2.4.探針配置示例
2.4.1 定義存活命令
許多長(zhǎng)時(shí)間運(yùn)行的應(yīng)用最終會(huì)進(jìn)入損壞狀態(tài),除非重新啟動(dòng),否則無法被恢復(fù)。 Kubernetes 提供了存活探針來發(fā)現(xiàn)并處理這種情況。
示例1:livenessProbe 規(guī)則,配合 exec 檢查方法。
① 編輯 pod 的 yaml 配置文件
[root@master01 demo]# vim demo3.yaml apiVersion: v1 kind: Pod metadata: # 元數(shù)據(jù) labels: # Pod 的標(biāo)簽 test: liveness name: liveness-exec spec: # Pod 的規(guī)格 containers: # 容器列表 - name: liveness # 容器的名稱 image: busybox # 一個(gè)輕量級(jí)的 BusyBox 鏡像 imagePullPolicy: IfNotPresent # 鏡像拉取策略,先本地后倉庫 args: # 容器的啟動(dòng)參數(shù)部分 - /bin/sh - -c # 后面的內(nèi)容將作為 shell 的命令執(zhí)行 - touch /tmp/healthy; sleep 10; rm -rf /tmp/healthy; sleep 10 # 在容器啟動(dòng)時(shí)執(zhí)行的命令,首先創(chuàng)建一個(gè)/tmp/healthy文件,然后等待10秒,接著刪除該文件,最后再等待10秒 livenessProbe: # 定義存活探針的配置 exec: # 使用 exec 方式執(zhí)行命令 command: # 要執(zhí)行的命令 - cat - /tmp/healthy # 讀取 /tmp/healthy 文件的內(nèi)容 failureThreshold: 1 # 存活探針的失敗閾值為1,即連續(xù)失敗1次后認(rèn)為探針失敗,默認(rèn)值是3。最小值是1 initialDelaySeconds: 3 # 容器啟動(dòng)后等待3秒開始進(jìn)行存活探測(cè),其實(shí)是4秒,默認(rèn)是0秒,最小值是0 periodSeconds: 2 # 每隔2秒進(jìn)行一次存活探測(cè),默認(rèn)是10秒。最小值是1。
這個(gè)容器生命的前 10 秒,/tmp/healthy 文件是存在的。 所以在這最開始的 10 秒內(nèi),執(zhí)行命令 cat /tmp/healthy 會(huì)返回成功代碼。 10 秒之后,執(zhí)行命令 cat /tmp/healthy 就會(huì)返回失敗代碼。
② 啟動(dòng) pod
[root@master01 demo]# kubectl apply -f demo3.yaml pod/liveness-exec created
③ 查看容器狀態(tài)詳情信息
[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由于存活探針失敗而不斷重啟,并最終進(jìn)入了CrashLoopBackOff狀態(tài) # 輸出結(jié)果顯示RESTARTS的值增加了1。 請(qǐng)注意,一旦失敗的容器恢復(fù)為運(yùn)行狀態(tài),RESTARTS計(jì)數(shù)器就會(huì)加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 # 顯示存活探針失敗了,這個(gè)失敗的容器被殺死并且被重建了 # 是否重啟還是根據(jù)重啟策略來決定,這里明顯是always
2.4.2 定義一個(gè)存活態(tài) HTTP 請(qǐng)求接口
另外一種類型的存活探測(cè)方式是使用 HTTP GET 請(qǐng)求。
示例2:livenessProbe 規(guī)則,配合 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 # 容器內(nèi)部的端口號(hào)為 80 livenessProbe: # 定義存活探針的配置 httpGet: # 使用HTTP GET請(qǐng)求方式進(jìn)行探測(cè) port: http # 探測(cè)請(qǐng)求發(fā)送到的端口為http,即容器內(nèi)部的80端口 path: /index.html # 探測(cè)請(qǐng)求的路徑為 /index.html initialDelaySeconds: 1 # 容器啟動(dòng)后等待1秒后開始進(jìn)行存活探測(cè) periodSeconds: 3 # 每隔3秒進(jìn)行一次存活探測(cè) timeoutSeconds: 5 # 超時(shí)時(shí)間為5秒
如果存活探針發(fā)送的 HTTPGET 請(qǐng)求返回成功(即能夠訪問到 /index.html),則認(rèn)為容器是健康的。如果請(qǐng)求失?。o法訪問到 /index.html 或返回錯(cuò)誤),則認(rèn)為容器不健康處理程序返回失敗代碼,kubelet 會(huì)殺死這個(gè)容器并且重新啟動(dòng)它。
② 啟動(dòng) 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" rel="external nofollow" >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
③ 查看容器狀態(tài)詳情信息
[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
容器中的存活探針失敗是因?yàn)?HTTP 探測(cè)返回了狀態(tài)碼 404,表示無法訪問到指定的路徑 /index.html。因此,容器被標(biāo)記為不健康,被 Kubernetes 系統(tǒng)自動(dòng)重新啟動(dòng)以嘗試恢復(fù)其健康狀態(tài)。
2.4.3 定義 TCP 的存活探測(cè)
使用這種配置時(shí),kubelet 會(huì)嘗試在指定端口和容器建立套接字鏈接。 如果能建立連接,這個(gè)容器就被看作是健康的,如果不能則這個(gè)容器就被看作是有問題的。
示例3:livenessProbe 規(guī)則,配合 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 # 容器啟動(dòng)后等待 5 秒后開始執(zhí)行存活探針 timeoutSeconds: 1 # 探測(cè)超時(shí)時(shí)間為 1 秒 tcpSocket: # 使用 TCP 探測(cè)方式 port: 8080 # 探測(cè)的端口為 8080 periodSeconds: 10 # 每隔 10 秒執(zhí)行一次存活探針 failureThreshold: 2 # 如果連續(xù) 2 次探測(cè)失敗,則認(rèn)為容器不健康
上面的 YAML 文件描述了一個(gè)名為 probe-tcp 的 Pod,其中包含一個(gè)名為 nginx 的容器,使用鏡像 soscscs/myapp:v1,配置了一個(gè)針對(duì)端口 8080 的 TCP 探測(cè)器,用于檢測(cè)容器的健康狀態(tài)。由于業(yè)務(wù)本身端口是 80,所有這步就是探針肯定是失敗的,持續(xù)查看探針過程。
② 啟動(dòng) pod
[root@master01 demo]# kubectl apply -f demo5.yaml pod/probe-tcp created 使用kubectl工具在名為probe-tcp的容器中執(zhí)行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
③ 持續(xù)查看容器狀態(tài)詳情信息
[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 # 由于探測(cè)8080端口失敗,可以看到 Pod 重啟了多次 # 理論上第一次重啟時(shí)間為:5+1+10=16秒 # 理論上第二次重啟時(shí)間為:+20秒 # 理論上第三次重啟時(shí)間為:+20秒 # 理論上第四次重啟時(shí)間為:+20秒
2.4.4 定義 readinessProbe 就緒探針
有時(shí)候,應(yīng)用會(huì)暫時(shí)性地?zé)o法為請(qǐng)求提供服務(wù)。 例如,應(yīng)用在啟動(dòng)時(shí)可能需要加載大量的數(shù)據(jù)或配置文件,或是啟動(dòng)后要依賴等待外部服務(wù)。 在這種情況下,既不想殺死應(yīng)用,也不想給它發(fā)送請(qǐng)求。 Kubernetes 提供了就緒探針來發(fā)現(xiàn)并緩解這些情況。 容器所在 Pod 上報(bào)還未就緒的信息,并且不接受通過 Kubernetes Service 的流量。
示例4: readinessProbe 和 livenessProbe 規(guī)則,配合 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 # 指定容器將監(jiān)聽的端口為 80 readinessProbe: # 定義容器的就緒性探針 httpGet: # 指定用于就緒性檢查的 HTTP GET 請(qǐng)求 port: 80 # 指定進(jìn)行就緒性檢查的端口(端口 80) path: /index1.html # 指定就緒性檢查期間請(qǐng)求的路徑("/index1.html") initialDelaySeconds: 1 # 指定容器啟動(dòng)后開始就緒性探針的等待時(shí)間(1 秒) periodSeconds: 3 # 指定連續(xù)就緒性探針之間的間隔(3 秒) livenessProbe: # 定義容器的存活性探針 httpGet: # 指定用于存活性檢查的 HTTP GET 請(qǐng)求 port: http # 指定進(jìn)行存活性檢查的端口("http"端口) path: /index.html # 指定存活性檢查期間請(qǐng)求的路徑("/index.html") initialDelaySeconds: 1 # 指定容器啟動(dòng)后開始存活性探針的等待時(shí)間(1 秒) periodSeconds: 3 # 指定連續(xù)存活性探針之間的間隔(3 秒) timeoutSeconds: 10 # 指定存活性探針在等待響應(yīng)的最大時(shí)間(10 秒)
② 啟動(dòng) pod
[root@master01 demo]# kubectl apply -f demo6.yaml pod/readiness-httpget created
③ 查看容器狀態(tài)詳情信息
[root@master01 demo]# kubectl get pod NAME READY STATUS RESTARTS AGE readiness-httpget 0/1 Running 0 17s # 0/1表示該P(yáng)od中的容器當(dāng)前處于未就緒狀態(tài) [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 # 就緒性探針失敗,因?yàn)?HTTP 探測(cè)返回了狀態(tài)碼 404,由于就緒性探針配置中指定的路徑/index1.html不存在或有誤。
④ 創(chuàng)建 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 狀態(tài)
[root@master01 demo]# kubectl get pod NAME READY STATUS RESTARTS AGE readiness-httpget 1/1 Running 0 5m36s # 已就緒
⑥ 刪除原有 index.html,查看存活探針結(jié)果
[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 頁面
2.4.5 多資源配置就緒檢測(cè)
下面這個(gè) YAML 文件定義了三個(gè)名為 myapp1、myapp2 和 myapp3 的 Pod,它們使用相同的鏡像并具有相似的配置,以及一個(gè)名為 myapp 的 Service,用于將流量路由到這些 Pod 上的端口 80。
測(cè)試目的:readiness 探測(cè)失敗,pod 無法進(jìn)入 ready 狀態(tài),則端點(diǎn)控制器會(huì)將 pod 從 endpoints 中剔除刪除該 pod 的 IP 地址。
示例5: readinessProbe 規(guī)則,配合 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 # 容器內(nèi)部的端口號(hào)為 80 readinessProbe: # 定義了就緒性探針 httpGet: # 指定了使用 HTTP GET 請(qǐng)求進(jìn)行探測(cè) port: 80 # 指定了探測(cè)的端口為 80 path: /index.html # 指定健康檢查發(fā)送請(qǐng)求的路徑為 /index.html initialDelaySeconds: 5 # 容器創(chuàng)建后等待 5 秒開始執(zhí)行健康檢查 periodSeconds: 5 # 每隔 5 秒進(jìn)行一次健康檢查 timeoutSeconds: 10 # 健康檢查的超時(shí)時(shí)間為 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
② 啟動(dòng) pod
[root@master01 demo]# kubectl apply -f readiness-httpget.yaml pod/myapp1 created pod/myapp2 created pod/myapp3 created service/myapp created
③ 查看 pod、svc 以及關(guān)聯(lián)后端的節(jié)點(diǎn)信息
[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
⑤ 再次查看關(guān)聯(lián)后端的節(jié)點(diǎn)
[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
此時(shí)可以看到對(duì)于 readiness 探測(cè)失敗,pod myapp3 無法進(jìn)入 reday 狀態(tài),端點(diǎn)控制器將 pod myapp3 的 ip 從 endpoints 中剔除刪除。
2.4.6 啟動(dòng)和退出動(dòng)作
以下將演示在 Kubernetes 中如何定義容器的生命周期事件,包括容器啟動(dòng)后和終止前的操作,以及如何使用初始化容器來執(zhí)行特定任務(wù)。
示例6:根據(jù)日志反饋的內(nèi)容了解容器處于生命周期的哪個(gè)階段
① 編輯 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: # 此為關(guān)鍵字段,定義容器的生命周期 postStart: # 容器啟動(dòng)后執(zhí)行的操作 exec: # 使用執(zhí)行命令的方式 command: ["/bin/sh", "-c", "echo Hello Start >> /var/log/nginx/message"] # 執(zhí)行的命令是往日志中寫入啟動(dòng)信息 preStop: # 容器終止前執(zhí)行的操作 exec: # 使用執(zhí)行命令的方式 command: ["/bin/sh", "-c", "echo Hello Stop >> /var/log/nginx/message"] # 執(zhí)行的命令是往日志中寫入停止信息 volumeMounts: # 掛載卷到容器內(nèi)部 - 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"] # 初始化容器執(zhí)行的命令,往日志中寫入初始化信息 volumeMounts: # 掛載卷到容器內(nèi)部 - name: message-log # 卷的名稱 mountPath: /var/log/nginx/ # 掛載路徑 readOnly: false # 是否只讀 volumes: # 定義卷 - name: message-log # 卷的名稱 hostPath: # 使用主機(jī)路徑 path: /data/volumes/nginx/log/ # 主機(jī)上的路徑 type: DirectoryOrCreate # 類型為目錄或創(chuàng)建
② 啟動(dòng) 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
由此可見,首先啟動(dòng)了 init 容器,然后啟動(dòng)成功后返回信息“Start”,代表啟動(dòng)成功。
⑤ 在 node01 節(jié)點(diǎn)查看日志
[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 節(jié)點(diǎn)上查看日志
[root@master01 demo]# kubectl delete pod lifecycle-demo pod "lifecycle-demo" deleted [root@node01 log]# cat message Hello initContainers Start Stop
由此課件,當(dāng)在容器被終結(jié)之前, Kubernetes 將發(fā)送一個(gè) preStop 事件,即探針關(guān)閉生命周期結(jié)束。
三、補(bǔ)充概念
3.1.pod 的狀態(tài)
- pending:pod已經(jīng)被系統(tǒng)認(rèn)可了,但是內(nèi)部的container還沒有創(chuàng)建出來。這里包含調(diào)度到node上的時(shí)間以及下載鏡像的時(shí)間,會(huì)持續(xù)一小段時(shí)間。
- Running:pod已經(jīng)與node綁定了(調(diào)度成功),而且pod中所有的container已經(jīng)創(chuàng)建出來,至少有一個(gè)容器在運(yùn)行中,或者容器的進(jìn)程正在啟動(dòng)或者重啟狀態(tài)。--這里需要注意pod雖然已經(jīng)Running了,但是內(nèi)部的container不一定完全可用。因此需要進(jìn)一步檢測(cè)container的狀態(tài)。
- Succeeded:這個(gè)狀態(tài)很少出現(xiàn),表明pod中的所有container已經(jīng)成功的terminated了,而且不會(huì)再被拉起了。
- Failed:pod中的所有容器都被terminated,至少一個(gè)container是非正常終止的。(退出的時(shí)候返回了一個(gè)非0的值或者是被系統(tǒng)直接終止)
- unknown:由于某些原因pod的狀態(tài)獲取不到,有可能是由于通信問題。 一般情況下pod最常見的就是前兩種狀態(tài)。而且當(dāng)Running的時(shí)候,需要進(jìn)一步關(guān)注container的狀態(tài)
3.2.Container生命周期
- Waiting:?jiǎn)?dòng)到運(yùn)行中間的一個(gè)等待狀態(tài)。
- Running:運(yùn)行狀態(tài)。
- Terminated:終止?fàn)顟B(tài)。 如果沒有任何異常的情況下,container應(yīng)該會(huì)從Waiting狀態(tài)變?yōu)镽unning狀態(tài),這時(shí)容器可用。
但如果長(zhǎng)時(shí)間處于Waiting狀態(tài),container會(huì)有一個(gè)字段reason表明它所處的狀態(tài)和原因,如果這個(gè)原因很容易能標(biāo)識(shí)這個(gè)容器再也無法啟動(dòng)起來時(shí),例如ContainerCannotRun,整個(gè)服務(wù)啟動(dòng)就會(huì)迅速返回。(這里是一個(gè)失敗狀態(tài)返回的特性,不詳細(xì)闡述)
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
k8s?clientConfig和rawConfig區(qū)別解析
k8s clientConfig和rawConfig區(qū)別k8s.io/client-gov0.28.2基于kubeconfig可以創(chuàng)建clientConfig和rawConfig,兩者區(qū)別在于,clientConfig包含了訪問kube-apiserver的地址和認(rèn)證鑒權(quán)信息,感興趣的朋友一起看看吧2025-03-03Kubernetes應(yīng)用服務(wù)質(zhì)量管理詳解
這篇文章主要為大家介紹了Kubernetes應(yīng)用服務(wù)質(zhì)量管理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11Rancher通過界面管理K8s平臺(tái)的圖文步驟詳解
這篇文章主要為大家介紹了Rancher通過界面管理K8s平臺(tái)通過詳細(xì)的圖文進(jìn)行步驟講解,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03tkestack/gpu-manager在k8s1.23版本之后的使用方法
這篇文章主要介紹了tkestack/gpu-manager在k8s1.23版本之后的使用,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04kubernetes部署dashboard及應(yīng)用小結(jié)
Dashboard?是基于網(wǎng)頁的?Kubernetes?用戶界面,可以對(duì)?Deployment?實(shí)現(xiàn)彈性伸縮、發(fā)起滾動(dòng)升級(jí)、重啟?Pod?或者使用向?qū)?chuàng)建新的應(yīng)用,這篇文章主要介紹了kubernetes部署dashboard,需要的朋友可以參考下2024-06-06Rancher部署配置開源Rainbond云原生應(yīng)用管理平臺(tái)
這篇文章主要為大家介紹了Rancher部署配置開源Rainbond云原生應(yīng)用管理平臺(tái),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04k8s自身原理service及實(shí)現(xiàn)圖文示例解析
這篇文章主要為大家介紹了k8s自身原理service圖文示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08