網站首頁 編程語言 正文
Pod 的那些狀態
使用 K8s 部署我們的服務之后,為了觀察 Pod 是否成功,我們都會使用下面這個命令查詢 Pod 的狀態。
kubectl get pods
NAME READY STATUS RESTARTS AGE
my-app-5d7d978fb9-2fj5m 0/1 ContainerCreating 0 10s
my-app-5d7d978fb9-dbt89 0/1 ContainerCreating 0 10s
這里的 STATUS 代表了 Pod 的狀態,可能會遇到的狀態有下面幾個:
- ContainerCreating:代表容器正在創建,這是一個中間狀態,隨著容器創建成功會切換,但是也有可能一直卡在這里,具體問題下面會分析。
- ImagePullBackOff:容器鏡像拉取失敗,具體原因需要結合 describe 命令再去查看。
- CrashLoopBackOff:容器崩潰,一般容器崩潰,Deployment 會重新創建一個 Pod,維持副本數量,但是大概率新創建的Pod 還是會崩潰,它不會無限嘗試,崩潰超過設置次數就不會再嘗試重建Pod,此時Pod的狀態就維持在了 CrashLoopBackOff。
- Evicted: 因為節點資源不足(CPU/Mem/Storage都有可能),Pod 被驅逐會顯示 Evicted 狀態,K8s 會按照策略選擇認為可驅逐的Pod從節點上 Kill 掉。
- Running 這個代表 Pod 正常運行。
下面我們來看一下 Pod 的幾個錯誤狀態的原因,以及怎么排查解決它們。
鏡像拉取失敗
鏡像拉取失敗后 Pod 的狀態字段表示為 ImagePullBackOff,這個發生的情況還是很多的,原因除了我們不小心寫錯鏡像名字之外,還有就是常用軟件的一些官方鏡像都在國外,比如在docker.io 或者 quay.io 的鏡像倉庫上,有的時候訪問速度會很慢。
下面我們自己故意制造一個鏡像名字寫錯的場景,看怎么使用 kubectl 命令進行排查。比如我在 K8s 教程里一直用的 Deployment 定義:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-go-app
spec:
replicas: 2
selector:
matchLabels:
app: go-app
template:
metadata:
labels:
app: go-app
spec:
containers:
- name: go-app-container
image: kevinyan001/kube-go-app:v0.3
resources:
limits:
memory: "200Mi"
cpu: "50m"
ports:
- containerPort: 3000
volumeMounts:
- name: app-storage
mountPath: /tmp
volumes:
- name: app-storage
emptyDir: {}
我們把鏡像的名字故意改錯,改成 v0.5,這個鏡像是我自己打的,確實還沒有 0.5 版本。執行kubectl apply 后,來觀察一下 Pod 的狀態。
? kubectl apply -f deployment.yaml
deployment.apps/my-go-app configured
? kubectl get pods
NAME READY STATUS RESTARTS AGE
my-go-app-5d7d978fb9-2fj5m 1/1 Running 0 3h58m
my-go-app-5d7d978fb9-dbt89 1/1 Running 0 3h58m
my-go-app-6b77dbbcc5-jpgbw 0/1 ContainerCreating 0 7s
? kubectl get pods
NAME READY STATUS RESTARTS AGE
my-go-app-5d7d978fb9-2fj5m 1/1 Running 0 3h58m
my-go-app-5d7d978fb9-dbt89 1/1 Running 0 3h58m
my-go-app-6b77dbbcc5-jpgbw 0/1 ErrImagePull 0 14s
.....// 停頓1分鐘,再查看Pod 的狀態
? kubectl get pods
NAME READY STATUS RESTARTS AGE
my-go-app-5d7d978fb9-2fj5m 1/1 Running 0 4h1m
my-go-app-5d7d978fb9-dbt89 1/1 Running 0 4h1m
my-go-app-6b77dbbcc5-jpgbw 0/1 ImagePullBackOff 0 3m11s
上面我們更新了 deployment 之后,觀察到 Pod 的狀態變化過程是:
ContainerCreating ===> ErrImagePull ===> ImagePullBackOff
首先 deployment 更新 Pod 時是滾動更新,要先把新 Pod 創建出來后能對舊版本 Pod 完成替換。接下來由于鏡像拉取錯誤會反饋一個中間狀態 ErrImagePull,此時會再次嘗試拉取,如果確定鏡像拉取不下來后,最后反饋一個失敗的終態 ImagePullBackOff。
怎么排查是什么導致的拉取失敗呢?通過 kubectl describe pod {pod-name} 查看它的事件記錄
? kubectl describe pod my-go-app-6b77dbbcc5-jpgbw
Name: my-go-app-6b77dbbcc5-jpgbw
Namespace: default
Priority: 0
...
Controlled By: ReplicaSet/my-go-app-6b77dbbcc5
Containers:
go-app-container:
Container ID:
Image: kevinyan001/kube-go-app:v0.5
Image ID:
Port: 3000/TCP
Host Port: 0/TCP
State: Waiting
Reason: ErrImagePull
Ready: False
...
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 2m12s default-scheduler Successfully assigned default/my-go-app-6b77dbbcc5-jpgbw to docker-desktop
Normal Pulling 27s (x4 over 2m12s) kubelet Pulling image "kevinyan001/kube-go-app:v0.5"
Warning Failed 20s (x4 over 2m4s) kubelet Failed to pull image "kevinyan001/kube-go-app:v0.5": rpc error: code = Unknown desc = Error response from daemon: manifest for kevinyan001/kube-go-app:v0.5 not found: manifest unknown: manifest unknown
Warning Failed 20s (x4 over 2m4s) kubelet Error: ErrImagePull
Normal BackOff 4s (x5 over 2m4s) kubelet Back-off pulling image "kevinyan001/kube-go-app:v0.5"
Warning Failed 4s (x5 over 2m4s) kubelet Error: ImagePullBackOff
Pod 事件記錄里,清楚記錄了 Pod 從開始到最后經歷的狀態變化,以及是什么導致狀態變化的,其中失敗事件里清楚的給出了我們原因,就是鏡像找不到。
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning Failed 20s (x4 over 2m4s) kubelet Failed to pull image "kevinyan001/kube-go-app:v0.5": rpc error: code = Unknown desc = Error response from daemon: manifest for kevinyan001/kube-go-app:v0.5 not found: manifest unknown: manifest unknown
Warning Failed 20s (x4 over 2m4s) kubelet Error: ErrImagePull
Normal BackOff 4s (x5 over 2m4s) kubelet Back-off pulling image "kevinyan001/kube-go-app:v0.5"
Warning Failed 4s (x5 over 2m4s) kubelet Error: ImagePullBackOff
還有一種是網絡原因,或者鏡像倉庫沒有權限拒絕拉取請求,導致無法拉取成功。因為我這里網絡環境、加速器之類的好不容易都配好了,就不給大家演示這兩種情況了。
不過排查方式也是一樣,使用kubectl describe 命令查看 Pod 的事件,并且使用 docker pull 嘗試主動的拉取一下鏡像試試,如果確實網絡問題拉取不下來的,可以考慮翻墻,或者使用國內的加速節點。
配置加速器,可以考慮使用阿里云的免費加速器,配置文檔在下面,需要注冊阿里云賬號才能使用加速器
https://help.aliyun.com/product/60716.html
啟動后容器崩潰
再來看這種錯誤,這種一般是容器里運行的程序內部出問題導致的容器連續崩潰出現的問題。最后反饋到 Pod 狀態上是 CrashLoopBackOff 狀態。
演示容器運行中崩潰的情況有點難,不過好在我之前介紹 Go 服務自動采樣的時候,做過一個鏡像
以下內容引用我之前的文章:Go 服務進行自動采樣性能分析的方案設計與實現
我做了個docker 鏡像方便進行試驗,鏡像已經上傳到了Docker Hub上,大家感興趣的可以Down下來自己在電腦上快速試驗一下。
通過以下命令即可快速體驗。
docker run --name go-profile-demo -v /tmp:/tmp -p 10030:80 --rm -d kevinyan001/go-profiling
容器里Go服務提供的路由如下
所以我們把上面的 deployment Pod 模版里的鏡像換成這個 kevinyan001/go-profiling,再通過提供的路由手動制造 OOM,來故意制造容器崩潰的情況。
修改Pod 使用的容器鏡像
#執行 kubectl apply -f deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-go-app
spec:
replicas: 2
selector:
matchLabels:
app: go-app
template:
metadata:
labels:
app: go-app
spec:
containers:
- name: go-app-container
image: kevinyan001/go-profiling:latest
resources:
limits:
memory: "200Mi"
cpu: "50m"
創建個 SVC 讓Pod能接受外部流量
#執行 kubectl apply -f service.yaml
apiVersion: v1
kind: Service
metadata:
name: app-service
spec:
type: NodePort
selector:
app: go-app
ports:
- name: http
protocol: TCP
nodePort: 30080
port: 80
targetPort: 80
程序中提供的路由如下:
訪問 http://127.0.0.1:30080/1gb-slice 讓容器內存溢出,因為 Deployment 會重啟崩潰的 Pod,所以這里非常考驗手速:) 估計狂點一分鐘,Deployment 就放棄治療休息會兒再重啟 Pod,這時 Pod 的狀態成功變成了:
? kubectl get pods
NAME READY STATUS RESTARTS AGE
my-go-app-598f697676-f5jfp 0/1 CrashLoopBackOff 2 (18s ago) 5m37s
my-go-app-598f697676-tps7n 0/1 CrashLoopBackOff 2 (23s ago) 5m35s
這個時候我們使用 kubectl describe pod 看崩潰 Pod 的詳細信息,會看到容器內程序返回的錯誤碼
? kubectl describe pod my-go-app-598f697676-tps7n
Name: my-go-app-598f697676-tps7n
Namespace: default
Port: 3000/TCP
Host Port: 0/TCP
State: Running
Started: Sun, 20 Mar 2022 16:09:29 +0800
Last State: Terminated
Reason: Error
Exit Code: 137
Started: Sun, 20 Mar 2022 16:08:56 +0800
Finished: Sun, 20 Mar 2022 16:09:05 +0800
不過要深入排查 Pod 內容器的問題,需要另一個命令 kubectl logs {pod-name} 的協助。
kubectl logs my-go-app-598f697676-tps7n
如果恰巧這個 Pod 被重啟了,查不出來任何東西,可以通過增加 — previous 參數選項,查看之前容器的日志。
kubectl logs my-go-app-598f697676-tps7n --previous
容器被驅逐
首先聲明,這個問題研發解決不了,但是你發揮一下自己YY的能力:當群里報警、運維@你趕緊看的時候,你來個反殺,告訴他資源不夠了趕緊擴容,是不是能裝到^_^…
扯遠了,現在回正題。集群里資源緊張的時候,K8s 會優先驅逐優先級低的 Pod,被驅逐的 Pod 的狀態會是 Evicted,這個情況沒辦法在本地模擬,貼一個在公司K8s集群遇到這種情況的截圖。
kubectl get pod 查看Pod狀態
上圖可以看到有一個Pod 的狀態變成了 Evicted。
再來用describe 看下詳細信息
kubectl describe pod 查看Pod 的詳細信息和事件記錄
不好意思,歷史久遠,上面的圖太模糊了,圖中的Message 一欄里有給出如下信息:
Status: Faild
Reason: Evicted
Message: The node wan low on resource: xxx-storage. Container xxx using xxxKi,
which exceeds its request of ....
總結
一般來說,大多數常見的部署失敗都可以使用這些命令進行排查和調試:
kubectl get pods
kubectl describe pod <podname>
kubectl logs <podname>
kubectl logs <podname> --previous
當然,有的時候想看 Pod 的配置信息,還可以使用
kubectl get pod <podname> -o=yaml
驗證一下Pod的配置是不是跟我們提交上去的一樣,以及一些其他的額外信息。
get 和 describe 這兩個命令除了能看 Pod 的狀態和信息記錄外,也能看其他資源的狀態和信息。
kubectl get pod|svc|deploy|sts|configmap <xxx-name>
kubectl describe pod|svc|deploy|sts|configmap <xxx-name>
這些就留給大家后面自己體驗吧。為了方便大家在本地試驗,在公眾號「網管叨bi叨」回復【k8s】能找到今天用的各種YAML的模版,感興趣的可以動手實踐起來。
原文鏈接:https://juejin.cn/post/7077912049723899918
相關推薦
- 2022-08-16 解決Django?cors跨域問題_python
- 2022-06-20 C語言超全面define預處理指令的使用說明_C 語言
- 2022-11-14 C#中對集合排序的三種方式_C#教程
- 2022-10-19 python類參數定義及數據擴展方式unsqueeze/expand_python
- 2022-03-12 深入了解C#多線程安全_C#教程
- 2022-10-21 解決Git?Revert?再次合代碼無效問題_相關技巧
- 2023-01-15 SqlServer?多種分頁方式?詳解(含簡單速度測試)_MsSql
- 2022-03-15 org.springframework.web.client.RestTemplate 上傳文件無法
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支