k8s探针模式
探針的三種模式
1. 活躍 存活 liveness
2. 就緒 Readiness
3. 啟動 startup
針對運行中的容器,kubelet 可以選擇是否執行以下三種探針,以及如何針對探測結果作出反應:
livenessProbe:指示容器是否正在運行。如果存活態探測失敗,則 kubelet 會殺死容器, 并且容器將根據其重啟策略決定未來。如果容器不提供存活探針, 則默認狀態為 Success。
readinessProbe:指示容器是否準備好為請求提供服務。如果就緒態探測失敗, 端點控制器將從與 Pod 匹配的所有服務的端點列表中刪除該 Pod 的 IP 地址。 初始延遲之前的就緒態的狀態值默認為 Failure。 如果容器不提供就緒態探針,則默認狀態為 Success。
startupProbe: 指示容器中的應用是否已經啟動。如果提供了啟動探針,則所有其他探針都會被 禁用,直到此探針成功為止。如果啟動探測失敗,kubelet 將殺死容器,而容器依其 重啟策略進行重啟。 如果容器沒有提供啟動探測,則默認狀態為 Success。
負載資源的示例
Deployment
StatefulSet
DaemonSet
phase 可能的值: 也是容器的狀態提示
PodScheduled:Pod 已經被調度到某節點;
ContainersReady:Pod 中所有容器都已就緒;
Initialized:所有的 Init 容器 都已成功啟動;
Ready:Pod 可以為請求提供服務,并且應該被添加到對應服務的負載均衡池中
Pending(懸決) Pod 已被 Kubernetes 系統接受,但有一個或者多個容器尚未創建亦未運行。此階段包括等待 Pod 被調度的時間和通過網絡下載鏡像的時間,
Running(運行中) Pod 已經綁定到了某個節點,Pod 中所有的容器都已被創建。至少有一個容器仍在運行,或者正處于啟動或重啟狀態。
Succeeded(成功) Pod 中的所有容器都已成功終止,并且不會再重啟。
Failed(失敗) Pod 中的所有容器都已終止,并且至少有一個容器是因為失敗終止。也就是說,容器以非 0 狀態退出或者被系統終止。
Unknown(未知) 因為某些原因無法取得 Pod 的狀態。這種情況通常是因為與 Pod 所在主機通信失敗。
如果某節點死掉或者與集群中其他節點失聯,Kubernetes 會實施一種策略,將失去的節點上運行的所有 Pod 的 phase 設置為 Failed
容器狀態
Kubernetes 會跟蹤 Pod 中每個容器的狀態,就像它跟蹤 Pod 總體上的階段一樣。 你可以使用容器生命周期回調 來在容器生命周期中的特定時間點觸發事件。
一旦調度器將 Pod 分派給某個節點,kubelet 就通過 容器運行時 開始為 Pod 創建容器。 容器的狀態有三種:Waiting(等待)、Running(運行中)和 Terminated(已終止)。
要檢查 Pod 中容器的狀態,你可以使用 kubectl describe pod <pod 名稱>。 其輸出中包含 Pod 中每個容器的狀態。
每種狀態都有特定的含義:
Waiting (等待)
如果容器并不處在 Running 或 Terminated 狀態之一,它就處在 Waiting 狀態。 處于 Waiting 狀態的容器仍在運行它完成啟動所需要的操作:例如,從某個容器鏡像 倉庫拉取容器鏡像,或者向容器應用 Secret 數據等等。 當你使用 kubectl 來查詢包含 Waiting 狀態的容器的 Pod 時,你也會看到一個 Reason 字段,其中給出了容器處于等待狀態的原因。
Running(運行中)
Running 狀態表明容器正在執行狀態并且沒有問題發生。 如果配置了 postStart 回調,那么該回調已經執行且已完成。 如果你使用 kubectl 來查詢包含 Running 狀態的容器的 Pod 時,你也會看到 關于容器進入 Running 狀態的信息。
Terminated(已終止)
處于 Terminated 狀態的容器已經開始執行并且或者正常結束或者因為某些原因失敗。 如果你使用 kubectl 來查詢包含 Terminated 狀態的容器的 Pod 時,你會看到 容器進入此狀態的原因、退出代碼以及容器執行期間的起止時間。
如果容器配置了 preStop 回調,則該回調會在容器進入 Terminated 狀態之前執行
容器重啟策略
Pod 的 spec 中包含一個 restartPolicy 字段,其可能取值包括 Always、OnFailure 和 Never。默認值是 Always。
restartPolicy 適用于 Pod 中的所有容器。restartPolicy 僅針對同一節點上 kubelet 的容器重啟動作。當 Pod 中的容器退出時,kubelet 會按指數回退 方式計算重啟的延遲(10s、20s、40s、…),其最長延遲為 5 分鐘。 一旦某容器執行了 10 分鐘并且沒有出現問題,kubelet 對該容器的重啟回退計時器執行 重置操作。
Pod 狀況
Pod 有一個 PodStatus 對象,其中包含一個 PodConditions 數組。Pod 可能通過也可能未通過其中的一些狀況測試。
PodScheduled:Pod 已經被調度到某節點;
ContainersReady:Pod 中所有容器都已就緒;
Initialized:所有的 Init 容器 都已成功啟動;
Ready:Pod 可以為請求提供服務,并且應該被添加到對應服務的負載均衡池中。
字段名稱 描述
type Pod 狀況的名稱
status 表明該狀況是否適用,可能的取值有 “True”, “False” 或 “Unknown”
lastProbeTime 上次探測 Pod 狀況時的時間戳
lastTransitionTime Pod 上次從一種狀態轉換到另一種狀態時的時間戳
reason 機器可讀的、駝峰編碼(UpperCamelCase)的文字,表述上次狀況變化的原因
message 人類可讀的消息,給出上次狀態轉換的詳細信息
定義存活命令
許多長時間運行的應用程序最終會過渡到斷開的狀態,除非重新啟動,否則無法恢復。 Kubernetes 提供了存活探測器來發現并補救這種情況。
在這篇練習中,你會創建一個 Pod,其中運行一個基于 k8s.gcr.io/busybox 鏡像的容器。 下面是這個 Pod 的配置文件。
vim pods/probe/exec-liveness.yaml apiVersion: v1 kind: Pod metadata:labels:test: livenessname: liveness-exec spec:containers:- name: livenessimage: admin02/busybox:latest #這個我換成我自己的了 用我的也可以 官網的可能有時候下載失敗 應為在國外args:- /bin/sh- -c- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600livenessProbe:exec:command:- cat- /tmp/healthyinitialDelaySeconds: 5 periodSeconds: 5在這個配置文件中,可以看到 Pod 中只有一個容器。 periodSeconds 字段指定了 kubelet 應該每 5 秒執行一次存活探測。 initialDelaySeconds 字段告訴 kubelet 在執行第一次探測前應該等待 5 秒。 kubelet 在容器內執行命令 cat /tmp/healthy 來進行探測。 如果命令執行成功并且返回值為 0,kubelet 就會認為這個容器是健康存活的。 如果這個命令返回非 0 值,kubelet 會殺死這個容器并重新啟動它。
這個容器生命的前 30 秒, /tmp/healthy 文件是存在的。 所以在這最開始的 30 秒內,執行命令 cat /tmp/healthy 會返回成功代碼。 30 秒之后,執行命令 cat /tmp/healthy 就會返回失敗代碼。 應為這個是 容器啟動 30秒 他會創建這個文件 30以后他就自己刪了 然后找不到了 他就自己重啟容器了
創建 Pod kubectl apply -f https://k8s.io/examples/pods/probe/exec-liveness.yaml 在 30 秒內,查看 Pod 的事件: kubectl describe pod liveness-exec 輸出結果表明還沒有存活探測器失敗: FirstSeen LastSeen Count From SubobjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 24s 24s 1 {default-scheduler } Normal Scheduled Successfully assigned liveness-exec to worker0 23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Pulling pulling image "k8s.gcr.io/busybox" 23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Pulled Successfully pulled image "k8s.gcr.io/busybox" 23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Created Created container with docker id 86849c15382e; Security:[seccomp=unconfined] 23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Started Started container with docker id 86849c15382e 35 秒之后,再來看 Pod 的事件: kubectl describe pod liveness-exec FirstSeen LastSeen Count From SubobjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 37s 37s 1 {default-scheduler } Normal Scheduled Successfully assigned liveness-exec to worker0 36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Pulling pulling image "k8s.gcr.io/busybox" 36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Pulled Successfully pulled image "k8s.gcr.io/busybox" 36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Created Created container with docker id 86849c15382e; Security:[seccomp=unconfined] 36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Started Started container with docker id 86849c15382e 2s 2s 1 {kubelet worker0} spec.containers{liveness} Warning Unhealthy Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory 再等另外 30 秒,檢查看這個容器被重啟了: kubectl get pod liveness-exec輸出結果顯示 RESTARTS 的值增加了 1。 NAME READY STATUS RESTARTS AGE liveness-exec 1/1 Running 1 1m演示第二個項目
定義一個存活態 HTTP 請求接口
另外一種類型的存活探測方式是使用 HTTP GET 請求。 下面是一個 Pod 的配置文件,其中運行一個基于 k8s.gcr.io/liveness 鏡像的容器
這個配置文件中,可以看到 Pod 也只有一個容器。 periodSeconds 字段指定了 kubelet 每隔 3 秒執行一次存活探測。 initialDelaySeconds 字段告訴 kubelet 在執行第一次探測前應該等待 3 秒。 kubelet 會向容器內運行的服務(服務會監聽 8080 端口)發送一個 HTTP GET 請求來執行探測。 如果服務器上 /healthz 路徑下的處理程序返回成功代碼,則 kubelet 認為容器是健康存活的。 如果處理程序返回失敗代碼,則 kubelet 會殺死這個容器并且重新啟動它。
任何大于或等于 200 并且小于 400 的返回代碼標示成功,其它返回代碼都標示失敗。
可以在這里看服務的源碼 server.go。
容器存活的最開始 10 秒中,/healthz 處理程序返回一個 200 的狀態碼。之后處理程序返回 500 的狀態碼。
vim http-liveness.yaml apiVersion: v1 kind: Pod metadata:labels:test: livenessname: liveness-http spec:containers:- name: livenessimage: admin02/liveness:latestargs:- /serverlivenessProbe:httpGet:path: /healthzport: 8080httpHeaders:- name: Custom-Headervalue: AwesomeinitialDelaySeconds: 3periodSeconds: 3 http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {duration := time.Now().Sub(started)if duration.Seconds() > 10 {w.WriteHeader(500)w.Write([]byte(fmt.Sprintf("error: %v", duration.Seconds())))} else {w.WriteHeader(200)w.Write([]byte("ok"))} })kubelet 在容器啟動之后 3 秒開始執行健康檢測。所以前幾次健康檢查都是成功的。 但是 10 秒之后,健康檢查會失敗,并且 kubelet 會殺死容器再重新啟動容器。
創建一個 Pod 來測試 HTTP 的存活檢測:
kubectl apply -f https://k8s.io/examples/pods/probe/http-liveness.yaml10 秒之后,通過看 Pod 事件來檢測存活探測器已經失敗了并且容器被重新啟動了。
kubectl describe pod liveness-http在 1.13(包括 1.13版本)之前的版本中,如果在 Pod 運行的節點上設置了環境變量 http_proxy(或者 HTTP_PROXY),HTTP 的存活探測會使用這個代理。 在 1.13 之后的版本中,設置本地的 HTTP 代理環境變量不會影響 HTTP 的存活探測
定義 TCP 的存活探測
第三種類型的存活探測是使用 TCP 套接字。 通過配置,kubelet 會嘗試在指定端口和容器建立套接字鏈接。 如果能建立連接,這個容器就被看作是健康的,如果不能則這個容器就被看作是有問題的
vim tcp-liveness-readiness.yaml apiVersion: v1 kind: Pod metadata:name: goproxylabels:app: goproxy spec:containers:- name: goproxyimage: k8s.gcr.io/goproxy:0.1ports:- containerPort: 8080readinessProbe:tcpSocket:port: 8080initialDelaySeconds: 5periodSeconds: 10livenessProbe:tcpSocket:port: 8080initialDelaySeconds: 15periodSeconds: 20如你所見,TCP 檢測的配置和 HTTP 檢測非常相似。 下面這個例子同時使用就緒和存活探測器。kubelet 會在容器啟動 5 秒后發送第一個就緒探測。 這會嘗試連接 goproxy 容器的 8080 端口。 如果探測成功,這個 Pod 會被標記為就緒狀態,kubelet 將繼續每隔 10 秒運行一次檢測。
除了就緒探測,這個配置包括了一個存活探測。 kubelet 會在容器啟動 15 秒后進行第一次存活探測。 與就緒探測類似,會嘗試連接 goproxy 容器的 8080 端口。 如果存活探測失敗,這個容器會被重新啟動。
kubectl apply -f https://k8s.io/examples/pods/probe/tcp-liveness-readiness.yaml15 秒之后,通過看 Pod 事件來檢測存活探測器:
kubectl describe pod goproxy使用命名端口
對于 HTTP 或者 TCP 存活檢測可以使用命名的 ContainerPort。
ports: - name: liveness-portcontainerPort: 8080hostPort: 8080livenessProbe:httpGet:path: /healthzport: liveness-port使用啟動探測器保護慢啟動容器
有時候,會有一些現有的應用程序在啟動時需要較多的初始化時間。 要不影響對引起探測死鎖的快速響應,這種情況下,設置存活探測參數是要技巧的。 技巧就是使用一個命令來設置啟動探測,針對HTTP 或者 TCP 檢測,可以通過設置 failureThreshold * periodSeconds 參數來保證有足夠長的時間應對糟糕情況下的啟動時間。
所以,前面的例子就變成了:
ports: - name: liveness-portcontainerPort: 8080hostPort: 8080livenessProbe:httpGet:path: /healthzport: liveness-portfailureThreshold: 1periodSeconds: 10startupProbe:httpGet:path: /healthzport: liveness-portfailureThreshold: 30periodSeconds: 10幸虧有啟動探測,應用程序將會有最多 5 分鐘(30 * 10 = 300s) 的時間來完成它的啟動。 一旦啟動探測成功一次,存活探測任務就會接管對容器的探測,對容器死鎖可以快速響應。 如果啟動探測一直沒有成功,容器會在 300 秒后被殺死,并且根據 restartPolicy 來設置 Pod 狀態。
定義就緒探測器
有時候,應用程序會暫時性的不能提供通信服務。 例如,應用程序在啟動時可能需要加載很大的數據或配置文件,或是啟動后要依賴等待外部服務。 在這種情況下,既不想殺死應用程序,也不想給它發送請求。 Kubernetes 提供了就緒探測器來發現并緩解這些情況。 容器所在 Pod 上報還未就緒的信息,并且不接受通過 Kubernetes Service 的流量。
說明: 就緒探測器在容器的整個生命周期中保持運行狀態。
注意: 活躍性探測器 不等待 就緒性探測器成功。 如果要在執行活躍性探測器之前等待,應該使用 initialDelaySeconds 或 startupProbe。
就緒探測器的配置和存活探測器的配置相似。 唯一區別就是要使用 readinessProbe 字段,而不是 livenessProbe 字段。
HTTP 和 TCP 的就緒探測器配置也和存活探測器的配置一樣的。
就緒和存活探測可以在同一個容器上并行使用。 兩者都用可以確保流量不會發給還沒有準備好的容器,并且容器會在它們失敗的時候被重新啟動
配置探測器
Probe 有很多配置字段,可以使用這些字段精確的控制存活和就緒檢測的行為:
initialDelaySeconds:容器啟動后要等待多少秒后存活和就緒探測器才被初始化,默認是 0 秒,最小值是 0。
periodSeconds:執行探測的時間間隔(單位是秒)。默認是 10 秒。最小值是 1。
timeoutSeconds:探測的超時后等待多少秒。默認值是 1 秒。最小值是 1。
successThreshold:探測器在失敗后,被視為成功的最小連續成功數。默認值是 1。 存活和啟動探測的這個值必須是 1。最小值是 1。
failureThreshold:當探測失敗時,Kubernetes 的重試次數。 存活探測情況下的放棄就意味著重新啟動容器。 就緒探測情況下的放棄 Pod 會被打上未就緒的標簽。默認值是 3。最小值是 1
說明:
在 Kubernetes 1.20 版本之前,exec 探針會忽略 timeoutSeconds:探針會無限期地 持續運行,甚至可能超過所配置的限期,直到返回結果為止。
這一缺陷在 Kubernetes v1.20 版本中得到修復。你可能一直依賴于之前錯誤的探測行為, 甚至你都沒有覺察到這一問題的存在,因為默認的超時值是 1 秒鐘。 作為集群管理員,你可以在所有的 kubelet 上禁用 ExecProbeTimeout 特性門控 (將其設置為 false),從而恢復之前版本中的運行行為,之后當集群中所有的 exec 探針都設置了 timeoutSeconds 參數后,移除此標志重載。 如果你有 Pods 受到此默認 1 秒鐘超時值的影響,你應該更新 Pod 對應的探針的 超時值,這樣才能為最終去除該特性門控做好準備。
當此缺陷被修復之后,在使用 dockershim 容器運行時的 Kubernetes 1.20+ 版本中,對于 exec 探針而言,容器中的進程可能會因為超時值的設置保持持續運行, 即使探針返回了失敗狀態。
注意:
如果就緒態探針的實現不正確,可能會導致容器中進程的數量不斷上升。 如果不對其采取措施,很可能導致資源枯竭的狀況。
HTTP 探測
HTTP Probes 可以在 httpGet 上配置額外的字段:
host:連接使用的主機名,默認是 Pod 的 IP。也可以在 HTTP 頭中設置 “Host” 來代替。
scheme :用于設置連接主機的方式(HTTP 還是 HTTPS)。默認是 HTTP。
path:訪問 HTTP 服務的路徑。默認值為 “/”。
httpHeaders:請求中自定義的 HTTP 頭。HTTP 頭字段允許重復。
port:訪問容器的端口號或者端口名。如果數字必須在 1 ~ 65535 之間。
對于 HTTP 探測,kubelet 發送一個 HTTP 請求到指定的路徑和端口來執行檢測。 除非 httpGet 中的 host 字段設置了,否則 kubelet 默認是給 Pod 的 IP 地址發送探測。 如果 scheme 字段設置為了 HTTPS,kubelet 會跳過證書驗證發送 HTTPS 請求。 大多數情況下,不需要設置host 字段。 這里有個需要設置 host 字段的場景,假設容器監聽 127.0.0.1,并且 Pod 的 hostNetwork 字段設置為了 true。那么 httpGet 中的 host 字段應該設置為 127.0.0.1。 可能更常見的情況是如果 Pod 依賴虛擬主機,你不應該設置 host 字段,而是應該在 httpHeaders 中設置 Host。
針對 HTTP 探針,kubelet 除了必需的 Host 頭部之外還發送兩個請求頭部字段: User-Agent 和 Accept。這些頭部的默認值分別是 kube-probe/{{ skew latestVersion >}} (其中 1.25 是 kubelet 的版本號)和 /。
你可以通過為探測設置 .httpHeaders 來重載默認的頭部字段值;例如:
livenessProbe:httpGet:httpHeaders:- name: Acceptvalue: application/jsonstartupProbe:httpGet:httpHeaders:- name: User-Agentvalue: MyUserAgent你也可以通過將這些頭部字段定義為空值,從請求中去掉這些頭部字段。
livenessProbe:httpGet:httpHeaders:- name: Acceptvalue: ""startupProbe:httpGet:httpHeaders:- name: User-Agentvalue: ""TCP 探測
對于一次 TCP 探測,kubelet 在節點上(不是在 Pod 里面)建立探測連接, 這意味著你不能在 host 參數上配置服務名稱,因為 kubelet 不能解析服務名稱。
探測器級別 terminationGracePeriodSeconds
FEATURE STATE: Kubernetes v1.21 [alpha]
在 1.21 版之前,pod 級別的 terminationGracePeriodSeconds 被用來終止 未能成功處理活躍性探測或啟動探測的容器。 這種耦合是意料之外的,可能會導致在設置了 pod 級別的 terminationGracePeriodSeconds 后, 需要很長的時間來重新啟動失敗的容器。
在1.21中,啟用特性標志 ProbeTerminationGracePeriod 后, 用戶可以指定一個探測器級別的 terminationGracePeriodSeconds 作為探測器規格的一部分。 當該特性標志被啟用時,若同時設置了 Pod 級別和探測器級別的 terminationGracePeriodSeconds, kubelet 將使用探測器級的值。
例如,
spec:terminationGracePeriodSeconds: 3600 # pod-levelcontainers:- name: testimage: ...ports:- name: liveness-portcontainerPort: 8080hostPort: 8080livenessProbe:httpGet:path: /healthzport: liveness-portfailureThreshold: 1periodSeconds: 60# Override pod-level terminationGracePeriodSeconds #terminationGracePeriodSeconds: 60探測器級別的 terminationGracePeriodSeconds 不能用于設置就緒態探針。 它將被 API 服務器拒絕。
總結
- 上一篇: WCF X.509验证
- 下一篇: 点云数据简介