k8s常用命令大全:kubectl 檢視、排錯與維運速查
k8s常用命令幾乎都是 kubectl 的子命令,按用途分五組:檢視(get、describe)、日誌與進入容器(logs、exec)、部署與更新(apply、rollout)、擴縮容(scale)、節點維護(cordon、drain)。排錯記住一個順序:先 get 看狀態,再 describe 看事件,最後 logs 看程式輸出。
k8s常用命令基本都是 kubectl 的子命令,按日常用途可以分成五組:檢視資源用 get、describe,看日誌和進容器用 logs、exec,發版和回滾用 apply、rollout,擴縮容用 scale,維護節點用 cordon、drain、uncordon。排錯時按“先 get 看狀態、再 describe 看事件、最後 logs 看程式輸出”的順序走,大多數問題在這三步裡就能定位。下面按組整理成速查表,每條命令都說明輸出裡該看哪一列、哪一段。範例統一使用名稱空間 shop、Deployment web。
先記住格式:動詞、資源、名稱、引數
kubectl 命令的結構是 kubectl 動詞 資源型別 [名稱] [引數],例如 kubectl get pods web-7d9c8b6f5-2xkqp -n shop -o wide。資源型別可以用縮寫:
| 資源 | 縮寫 | 資源 | 縮寫 |
|---|---|---|---|
| pods | po | services | svc |
| deployments | deploy | statefulsets | sts |
| daemonsets | ds | replicasets | rs |
| nodes | no | namespaces | ns |
| configmaps | cm | persistentvolumeclaims | pvc |
| ingresses | ing | horizontalpodautoscalers | hpa |
kubectl api-resources 會列出叢集裡全部資源型別和縮寫。幾個幾乎每條命令都會用到的引數:
| 引數 | 作用 |
|---|---|
-n 名稱空間 |
指定名稱空間,不寫就用當前上下文的預設值,通常是 default |
-A |
所有名稱空間 |
-l app=web |
按標籤篩選 |
-o wide |
多顯示 Pod IP、所在節點等列 |
-o yaml、-o json |
輸出完整物件,包括 spec 和 status |
-o name |
只輸出“型別/名稱”,方便交給其他命令處理 |
-w |
持續觀察變化,Ctrl+C 退出 |
--field-selector |
按欄位篩選,例如 spec.nodeName=node-2 |
常用別名和補全,寫進 ~/.bashrc:
alias k=kubectl
source <(kubectl completion bash)
complete -o default -F __start_kubectl k # 讓別名 k 也能 Tab 補全
alias kgp='kubectl get pods -o wide'
export dry='--dry-run=client -o yaml' # 用法:k create deploy web --image=nginx $dry > web.yaml
-o 的幾種進階用法,在寫指令碼和做巡檢時很省事:
kubectl get deploy web -n shop -o yaml > web-live.yaml # 匯出線上物件;含 status 等欄位,複用前要刪掉
kubectl get pods -n shop -o custom-columns='NAME:.metadata.name,NODE:.spec.nodeName,IMAGE:.spec.containers[*].image'
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.addresses[?(@.type=="InternalIP")].address}{"\n"}{end}'
kubectl get pods -A --sort-by='.status.containerStatuses[0].restartCount' # 按重啟次數排序
kubectl explain deployment.spec.strategy # 查某個欄位的含義和可選值
檢視資源:get 與 describe 的輸出看什麼
| 命令 | 用途 | 輸出要看什麼 |
|---|---|---|
kubectl get nodes -o wide |
節點列表 | STATUS 是否為 Ready;Ready,SchedulingDisabled 表示被 cordon 了;VERSION 各節點是否一致 |
kubectl get pods -n shop -o wide |
Pod 列表 | READY 分子是否等於分母、STATUS、RESTARTS 是否在漲、NODE 是否都擠在一台上 |
kubectl get pods -A --field-selector=status.phase!=Running |
全叢集不在執行中的 Pod | 已正常結束的 Job Pod 也會列出,狀態為 Completed |
kubectl get deploy -n shop |
部署狀態 | READY 為 2/3 表示有副本沒就緒;UP-TO-DATE 小於期望值表示更新還沒走完 |
kubectl get svc -n shop |
服務 | TYPE、CLUSTER-IP、PORT(S);LoadBalancer 型別的 EXTERNAL-IP 一直是 pending,說明叢集裡沒有可用的負載均衡實現,自建機房的叢集常見 |
kubectl get endpointslices -n shop -l kubernetes.io/service-name=web |
Service 的後端 | ENDPOINTS 一列沒有位址,說明選擇器沒有選中可用的 Pod;有位址仍不通,用 -o yaml 看各後端的 conditions.ready |
kubectl describe pod 名稱 -n shop |
Pod 詳情 | 末尾的 Events;容器的 State、Last State、Reason、Exit Code |
kubectl describe node node-2 |
節點詳情 | Conditions 裡的 MemoryPressure、DiskPressure;Taints;Allocated resources 裡 requests 的佔比 |
kubectl top nodes、kubectl top pods -n shop |
即時 CPU 和記憶體 | 需要叢集裝有 metrics-server,否則報 Metrics API not available |
一段典型的 kubectl get pods -n shop -o wide 輸出:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-7d9c8b6f5-2xkqp 1/1 Running 0 3d 10.244.1.12 node-1 <none> <none>
web-7d9c8b6f5-8wz4m 0/1 CrashLoopBackOff 14 (2m ago) 47m 10.244.2.31 node-2 <none> <none>
api-6c5f9d7b8-qtl7n 0/1 Pending 0 12m <none> <none> <none> <none>
第二個 Pod 已經重啟 14 次、最近一次在 2 分鐘前,是程式啟動後反覆退出,下一步看它的上一次日誌;第三個 Pod 沒有 IP 也沒有節點,說明還沒被排程,原因在 describe 的 Events 裡。較新版本的 kubectl 還可以用 kubectl events -n shop --types=Warning 只看告警事件。
日誌與進入容器:logs、exec
kubectl logs web-7d9c8b6f5-8wz4m -n shop # 容器當前的標準輸出
kubectl logs web-7d9c8b6f5-8wz4m -n shop --previous # 上一次退出前的日誌,CrashLoopBackOff 必看
kubectl logs -f deploy/web -n shop --tail=100 # 跟蹤輸出,從最後 100 行開始
kubectl logs web-7d9c8b6f5-2xkqp -n shop -c nginx # 多容器 Pod 用 -c 指定容器
kubectl logs -l app=web -n shop --since=30m --tail=200 --prefix # 按標籤取多個 Pod 的日誌,每行標出來源
kubectl exec -it web-7d9c8b6f5-2xkqp -n shop -- sh # 進入容器;映象裡沒有 bash 時用 sh
kubectl exec web-7d9c8b6f5-2xkqp -n shop -- cat /etc/resolv.conf # 不進入,直接執行一條命令
kubectl cp shop/web-7d9c8b6f5-2xkqp:/app/logs/error.log ./error.log # 從容器拷出檔案,容器裡需要有 tar
kubectl port-forward svc/web 8080:80 -n shop # 本機 8080 轉到 Service 的 80 連接埠,臨時除錯用
要點:
--previous是排查 CrashLoopBackOff 的關鍵。 容器已經重啟過,kubectl logs預設看的是新啟動的例項,它可能還沒來得及輸出錯誤;上一次崩潰的原因在--previous裡。logs deploy/web只取其中一個 Pod。 要看全部副本用-l按標籤取;按標籤取日誌時,每個 Pod 預設只顯示最後 10 行,要看更多就加--tail。exec後面的--不能省,它把 kubectl 自己的引數和容器裡要執行的命令分開。- 精簡映象裡沒有 shell,exec 會報找不到可執行檔案。可以用
kubectl debug -it 名稱 -n shop --image=busybox:1.36 --target=web往 Pod 里加一個臨時除錯容器,--target填業務容器的名字,就能看到它的程序。 - 日誌只儲存在節點上。 Pod 被刪除後
kubectl logs就查不到了,需要長期保留的日誌要接入集中日誌系統。
部署、更新、回滾與擴縮容:apply、rollout、scale
kubectl diff -f web.yaml # 先看會改動什麼,沒有輸出說明與線上一致
kubectl apply -f web.yaml # 建立或更新,重複執行是安全的
kubectl apply -f ./manifests/ -R # 整個目錄,-R 包含子目錄
kubectl set image deploy/web web=registry.example.internal/shop/web:1.4.3 -n shop
kubectl annotate deploy/web -n shop kubernetes.io/change-cause="upgrade to 1.4.3" # 給這次變更寫說明
kubectl rollout status deploy/web -n shop # 觀察滾動更新進度
kubectl rollout history deploy/web -n shop # 歷史版本和 CHANGE-CAUSE
kubectl rollout undo deploy/web -n shop # 回到上一版
kubectl rollout undo deploy/web -n shop --to-revision=3
kubectl rollout restart deploy/web -n shop # 映象不變,逐個重建 Pod
kubectl scale deploy/web -n shop --replicas=5
rollout status 會持續輸出類似 Waiting for deployment "web" rollout to finish: 1 of 3 updated replicas are available... 的進度,全部替換完顯示 successfully rolled out。新 Pod 一直起不來時,超過 Deployment 的 progressDeadlineSeconds(預設 600 秒)會報 exceeded its progress deadline。Kubernetes 不會自動回滾,這時先 rollout undo 恢復業務,再排查新版本。
幾種寫入方式的區別:
| 命令 | 行為 | 適合 |
|---|---|---|
kubectl create -f |
只建立,物件已存在就報錯 | 一次性建立 |
kubectl apply -f |
不存在就建立,存在就按檔案合併更新 | 日常釋出,YAML 放在版本庫裡 |
kubectl replace -f |
用檔案整體替換物件,物件必須已存在 | 少數需要整體覆蓋的場景 |
kubectl edit |
在編輯器裡直接改線上物件 | 臨時應急;改完要同步回 YAML,否則下次 apply 會被覆蓋 |
擴縮容的幾個注意點:
kubectl scale deploy/web --replicas=0停掉全部 Pod 但保留配置,恢復時再改回原來的數量。- 有 HPA 管理的 Deployment,手工 scale 的結果會被 HPA 改回去,要調整的是 HPA 的最小、最大副本數。
- YAML 裡寫了
replicas,下一次 apply 會把手工 scale 的數量改回檔案裡的值。 kubectl get hpa的 TARGETS 列顯示<unknown>/70%,說明 metrics-server 沒裝好,或者 Pod 沒有設定 CPU requests。
節點維護:cordon、drain、uncordon
物理伺服器換記憶體、升級核心、更新韌體之前,先把節點上的 Pod 遷走:
kubectl cordon node-2 # 標記為不可排程,已有 Pod 不動
kubectl drain node-2 --ignore-daemonsets --delete-emptydir-data --timeout=10m
# 關機維護、開機,確認 kubectl get nodes 裡 node-2 重新變成 Ready
kubectl uncordon node-2 # 恢復排程
| 命令或引數 | 作用 | 注意 |
|---|---|---|
cordon |
禁止新 Pod 排程到該節點 | 節點 STATUS 變為 Ready,SchedulingDisabled |
drain |
先 cordon,再驅逐節點上的 Pod,由控制器在其他節點重建 | 驅逐會遵守 PodDisruptionBudget |
--ignore-daemonsets |
跳過 DaemonSet 的 Pod | 不加時,節點上有 DaemonSet Pod 會直接報錯退出 |
--delete-emptydir-data |
允許驅逐使用 emptyDir 卷的 Pod | emptyDir 裡的資料會丟失 |
--force |
連沒有控制器管理的裸 Pod 也刪除 | 裸 Pod 刪除後不會在別處重建 |
uncordon |
恢復排程 | 已遷走的 Pod 不會自動遷回 |
drain 卡住不動時,輸出裡通常反覆出現 Cannot evict pod as it would violate the pod's disruption budget,說明某個應用的 PodDisruptionBudget 不允許再少一個副本。用 kubectl get pdb -A 找到它,如果副本數本來就等於 minAvailable,先給該應用擴容一個副本,drain 才能繼續。維護結束 uncordon 之後,Pod 不會自己回來,節點之間負載不均時,可以對相關 Deployment 執行一次 rollout restart 讓排程器重新分佈。節點要永久下線,drain 之後執行 kubectl delete node node-2;用 kubeadm 部署的叢集,再到這台機器上執行 kubeadm reset 清理。
排錯常用組合:按 Pod 狀態找原因
| STATUS 或現象 | 常見原因 | 下一步看什麼 |
|---|---|---|
| Pending | 資源不夠、節點有汙點、PVC 沒繫結 | describe 的 Events 裡的 FailedScheduling,例如 0/3 nodes are available: 3 Insufficient cpu |
| ContainerCreating 很久 | 拉映象慢、儲存卷掛載失敗、網路外掛異常 | describe 的 Events |
| ErrImagePull、ImagePullBackOff | 映象名或標籤寫錯、私有倉庫沒配憑據、節點存取不了倉庫 | describe 裡 Failed to pull image 後面的原因 |
| CreateContainerConfigError | 引用的 ConfigMap 或 Secret 不存在 | kubectl get cm,secret -n shop |
| CrashLoopBackOff | 程式啟動後退出,kubelet 按遞增間隔反覆重啟,最長間隔 5 分鐘 | kubectl logs --previous |
| Last State 的 Reason 為 OOMKilled,退出碼 137 | 記憶體超過 limits | 調高 limits,或排查程式的記憶體佔用 |
| Running 但 READY 為 0/1 | 就緒探針失敗,Service 不會把流量轉給它 | describe 裡的 Readiness probe failed |
| Evicted | 節點記憶體或磁碟緊張,Pod 被驅逐 | kubectl describe node 的 Conditions |
| Terminating 刪不掉 | 節點失聯,或物件上有 finalizer | kubectl get pod 名稱 -n shop -o yaml 裡的 finalizers,以及所在節點的狀態 |
Service 存取不通時,按下面的順序查:
# 1. 後端 Pod 是否都已就緒
kubectl get pods -n shop -l app=web -o wide
# 2. Service 是否選中了 Pod
kubectl get endpointslices -n shop -l kubernetes.io/service-name=web
# 3. Service 的選擇器與 Pod 標籤是否一致
kubectl get svc web -n shop -o yaml | grep -A3 selector
kubectl get pods -n shop --show-labels
# 4. 從叢集內部直接存取
kubectl run tmp --rm -it --image=busybox:1.36 --restart=Never -n shop -- wget -qO- http://web.shop.svc.cluster.local
# 5. 報許可權錯誤時,檢查某個帳號能不能做這個操作
kubectl auth can-i create deployments -n shop --as=system:serviceaccount:shop:deployer
第 1 步 Pod 都正常、第 2 步卻為空,幾乎總是選擇器和標籤對不上;第 4 步能存取而外部不通,問題在 Ingress、NodePort 或機房防火牆這一層,和 Pod 本身無關。
在機房裡怎麼落地
叢集跑在自有物理伺服器上時,kubectl 管得到 Pod 和節點物件,管不到節點的硬體和作業系統。典型的維護流程是:kubectl drain 把節點上的業務遷走,在 Toplink DCIM 的 IPMI 遠端管理裡遠端關機、設定下次從 PXE 或 ISO 啟動來重灌系統、開啟 VNC 控制檯看開機自檢,處理完再 uncordon。節點 NotReady、kubelet 連不上 apiserver 時,從控制檯本地登入能直接看到網路卡和系統狀態,不受叢集網路影響。節點位址、apiserver 的虛擬 IP 要在機房位址台帳裡登記,避免被分配給其他伺服器:在 IP 位址管理裡把這些位址登記為已佔用,或把所在的段鎖定,開通新伺服器自動取址時就會跳過它們。
常見問題
每次都要寫 -n,能不能設一個預設名稱空間?
可以修改當前上下文的預設名稱空間:kubectl config set-context --current --namespace=shop,之後不寫 -n 就操作 shop,用 kubectl config view --minify | grep namespace 確認當前值。在多個叢集、多個名稱空間之間來回切換時容易忘記自己在哪,執行刪除類命令前先確認一遍。
kubectl delete pod 之後 Pod 又出現了,怎麼徹底刪掉?
Pod 由 Deployment、StatefulSet 或 DaemonSet 管理時,刪掉 Pod 只會讓控制器補一個新的。要停掉業務,刪除上層物件,例如 kubectl delete deploy web -n shop,或者把副本數縮到 0。用 kubectl get pod 名稱 -o yaml 檢視 ownerReferences 能找到上層物件:Deployment 建立的 Pod 先指向 ReplicaSet,再往上才是 Deployment。
Pod 一直卡在 Terminating 怎麼辦?
先看原因:所在節點已經失聯時,Pod 要等節點恢復或節點物件被刪除才能清理;物件上有 finalizer 時,要等對應的控制器完成清理。確認容器確實已經停止後,可以用 kubectl delete pod 名稱 -n shop --grace-period=0 --force 強制刪除。StatefulSet 的 Pod 慎用強刪,節點只是網路斷開時,可能出現兩個同名例項同時寫同一份資料。