伺服器維運

k8s常用命令大全:kubectl 檢視、排錯與維運速查

k8s常用命令幾乎都是 kubectl 的子命令,按用途分五組:檢視(get、describe)、日誌與進入容器(logs、exec)、部署與更新(apply、rollout)、擴縮容(scale)、節點維護(cordon、drain)。排錯記住一個順序:先 get 看狀態,再 describe 看事件,最後 logs 看程式輸出。

作者 頂聯產品團隊發布於 5 分鐘閱讀

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 慎用強刪,節點只是網路斷開時,可能出現兩個同名例項同時寫同一份資料。

想看看在你的機房裡怎麼用?

從一次產品示範開始,梳理你的業務鏈路。

查看價格
服務熱線 400-112-2951

讓我們聊聊你的 IDC 業務

掃碼新增企業微信,預約產品示範或申請試用。

Toplink 企業微信二維碼

長按儲存或使用企業微信 / 微信掃描

也可致電
400-112-2951
Telegram
@TopLink88