到Deployment滾動更新與Pod配額排障課件)
簡介面向 Kubernetes 初學者與云原生運維人員的這套課件圍繞集群架構(gòu)、核心對象和日常管理展開幫助建立系統(tǒng)化的 k8s 知識框架。資源包為 1 個 pptx 文件約 1.25MB篇幅集中便于按章節(jié)瀏覽和課堂演示。內(nèi)容先說明 apiserver、kubelet、kube-proxy 等組件職責再梳理 Pod、Controllers、Service、Label、Namespace 等對象。結(jié)合 kubectl 命令與 YAML 清單展示集群狀態(tài)查看、資源監(jiān)控、日志排查并串聯(lián) Deployment 的創(chuàng)建、發(fā)布、升級、擴縮容和回滾流程同時延伸調(diào)度、存儲與集群安全。目前已有 2191 人學習適合入門梳理與面試前復盤。1. 一份把 K8s 從概念講到配額邊界的課件適合誰啃剛拿到 kubeconfig 的人最常遇到的問題不是 YAML 縮進寫錯而是 Pod 起不來時只會反復kubectl get pods刷新說不清 apiserver、etcd、kubelet 各自卡在鏈路哪一段。這份 K8s 課件針對的正是這個薄弱點從集群架構(gòu)與組件職責入手接著是監(jiān)控與日志、應(yīng)用生命周期管理、調(diào)度、存儲、集群安全六塊內(nèi)容按「先知道誰在干活再知道怎么讓它干活」的順序排布。它不適合已經(jīng)能順手寫 Operator 的人但對剛接手集群、需要獨立把一個 Deployment 從創(chuàng)建推到升級再回滾的運維和后端更合適。下面我按自己復盤的順序拆開重心放在命令背后的參數(shù)含義和幾個容易出錯的邊界上。2. 集群架構(gòu)拆開看apiserver、etcd、kubelet 各自守哪一段2.1 控制面四個組件的職責邊界很多人把控制面當成一個整體其實它內(nèi)部的分工很明確邊界一旦搞混排查方向就會偏。kube-apiserver 是集群唯一入口所有組件彼此不直接通信只跟 apiserver 通信apiserver 也是唯一能讀寫 etcd 的進程。一個請求進來要過三道關(guān)認證證書、Token 或 ServiceAccount、鑒權(quán)RBAC 規(guī)則、準入控制各種 Admission 插件全過了才落盤。這套設(shè)計的好處是審計點集中壞處是 apiserver 一旦不可用kubectl全線報錯但已經(jīng)在跑的 Pod 不受影響因為 kubelet 還在按本地緩存的期望狀態(tài)干活。kube-controller-manager 是一堆控制器的集合體Deployment、ReplicaSet、Node、Endpoint、ServiceAccount 各有一個控制器在跑。每個控制器本質(zhì)是個死循環(huán)讀期望狀態(tài)spec讀實際狀態(tài)status算差值發(fā)指令。這里有個容易被忽略的嵌套關(guān)系Deployment 控制器并不直接管 Pod它管的是 ReplicaSetReplicaSet 再管 Pod。正因為老版本的 ReplicaSet 會被保留并縮到 0 而不是刪掉回滾才有歷史可退。kube-scheduler 只做一件事給新創(chuàng)建、還沒綁定節(jié)點的 Pod 選一個 Node然后寫一個 Binding 對象把spec.nodeName填上。它不負責把容器啟動起來啟動是 kubelet 的活。調(diào)度分兩階段Filter 先過濾掉不滿足條件的節(jié)點資源不夠、污點不匹配、端口沖突、親和性不符Score 再對剩下的節(jié)點打分。所以看到 Pod 處于 Pending 且 Events 里寫著FailedScheduling問題一定在調(diào)度器這一側(cè)不用去翻容器日志。etcd 是分布式鍵值存儲默認監(jiān)聽 2379/2380正常配置下只允許 apiserver 訪問。集群里所有對象狀態(tài)都在它里面某種意義上刪掉 etcd 數(shù)據(jù)目錄等于刪掉整個集群。組件位置核心職責掛掉后的典型表現(xiàn)kube-apiserver控制面唯一入口認證鑒權(quán)準入讀寫 etcdkubectl 全部報錯已運行 Pod 不受影響kube-controller-manager控制面控制器循環(huán)把實際狀態(tài)拉向期望狀態(tài)副本數(shù)不收斂Service 沒有 Endpointskube-scheduler控制面為新 Pod 選擇節(jié)點并綁定新 Pod 一直 Pendingetcd控制面保存全部集群狀態(tài)apiserver 起不來集群事實性丟失kubelet節(jié)點管理本機 Pod 生命周期該節(jié)點上的 Pod 狀態(tài)不再更新kube-proxy節(jié)點維護 Service 的四層轉(zhuǎn)發(fā)規(guī)則Service 通但后端訪問不到2.2 節(jié)點側(cè)kubelet 和 kube-proxy 不是一回事kubelet 是節(jié)點上的代理它做的是向 apiserver 注冊節(jié)點、watch 到綁定給自己的 Pod、通過 CRI 調(diào)用容器運行時創(chuàng)建容器、掛載數(shù)據(jù)卷、拉取 Secret 和 ConfigMap、執(zhí)行存活與就緒探針、定時上報節(jié)點和 Pod 狀態(tài)。kubelet 把每個 Pod 翻譯成一組容器操作這個翻譯過程出錯Pod 就卡在 ContainerCreating 或者一直重啟。kube-proxy 完全不參與容器創(chuàng)建它 watch Service 和 Endpoints 的變化在節(jié)點上寫 iptables 或 ipvs 規(guī)則實現(xiàn)四層負載均衡。區(qū)分方法很簡單Pod 起不來看 kubelet 和容器運行時Pod 起來了但 Service 訪問不通先看 Endpoints 有沒有后端再看 kube-proxy 的規(guī)則。2.3 用幾條命令把組件狀態(tài)驗證一遍課件里給了kubectl cluster-info但單靠這一條信息量太少。我一般按下面這個順序過一遍每條命令看什么、返回什么算正常心里要有數(shù)。# 集群入口信息apiserver 地址和集群 DNS 服務(wù)地址 kubectl cluster-info # 控制面組件是否都是 Running以及各自落在哪個節(jié)點 kubectl get pods -n kube-system -o wide # 直接打 apiserver 的健康端點返回 ok 說明 apiserver 自身活著 kubectl get --raw /healthz # 看單個節(jié)點的容量、已分配資源、污點和最近事件 kubectl describe node node-name第一條命令的返回值里如果 DNS 那行是10.96.0.10:53這類地址說明集群服務(wù)網(wǎng)段正常。第二條要重點看kube-controller-manager、kube-scheduler、etcd這幾個靜態(tài) Pod 的 RESTARTS 次數(shù)短時間反復重啟通常意味著證書過期或者磁盤壓力。第三條--raw是直接向 apiserver 發(fā)原始請求繞開 kubectl 的客戶端邏輯用來判斷「是 apiserver 掛了還是 kubectl 配置錯了」特別快。注意網(wǎng)上很多老教程會寫kubectl get componentstatuses這個接口在較新版本里已經(jīng)廢棄輸出的警告比內(nèi)容還長。用kubectl get --raw /healthz配合kubectl get pods -n kube-system替代更靠譜也不用記一堆縮寫。2.4 etcd 快照唯一的后悔藥集群層面最該養(yǎng)成的習慣是給 etcd 做快照。誤刪一個 Namespace 會連帶刪掉里面所有對象控制器不會幫你恢復因為對它來說那就是期望狀態(tài)變了。# 在控制面節(jié)點執(zhí)行證書路徑按實際安裝位置修改 ETCDCTL_API3 etcdctl \ --endpointshttps://127.0.0.1:2379 \ --cacert/etc/kubernetes/pki/etcd/ca.crt \ --cert/etc/kubernetes/pki/etcd/server.crt \ --key/etc/kubernetes/pki/etcd/server.key \ snapshot save /var/backups/etcd-$(date %F-%H%M).db # 校驗快照完整性輸出里 hash 和 revision 都要有值 etcdctl snapshot status /var/backups/etcd-20240101-1200.db --write-outtable--endpoints指向本機 etcd 客戶端端口三個證書分別對應(yīng) CA、客戶端證書和私鑰缺一個都會報context deadline exceeded這個報錯很有迷惑性看起來像網(wǎng)絡(luò)不通實際多數(shù)是證書路徑寫錯。snapshot save是熱備份不需要停 etcd但恢復時必須停掉 apiserver 和 etcd 再執(zhí)行snapshot restore恢復動作不要在業(yè)務(wù)時段做。備份文件放本地磁盤意義有限節(jié)點掛了就一起沒了我一般會再同步到集群外的存儲。3. 從 kubectl 到 YAML把一個 Deployment 推到回滾的完整閉環(huán)3.1 命令式創(chuàng)建先用兩條命令跑通初學階段別急著寫 YAML先用命令式把對象關(guān)系跑通看到 Deployment、ReplicaSet、Pod 三層是怎么長出來的比背字段有用得多。# 創(chuàng)建一個 Deployment鏡像用內(nèi)網(wǎng)倉庫地址 kubectl create deployment web --imageregistry.local/demo/java-web:1.0 # 查看 Deployment 和 Pod-o wide 能看到 Pod 落在哪個節(jié)點 kubectl get deploy,pods -o wide # 暴露服務(wù)Service 80 端口轉(zhuǎn)發(fā)到容器 8080 kubectl expose deployment web \ --port80 \ --target-port8080 \ --typeNodePort \ --nameweb kubectl get svc web--port是 Service 自身監(jiān)聽的端口集群內(nèi)其他 Pod 通過web:80訪問--target-port是容器實際監(jiān)聽的端口寫錯這個是最常見的 502 來源--typeNodePort會在 30000–32767 區(qū)間隨機分配一個節(jié)點端口--name不寫的話默認與 Deployment 同名。創(chuàng)建完立刻kubectl get rs會看到一個名字形如web-7d9f8c6b5的 ReplicaSetPod 名字再在后面加隨機后綴。這個三層結(jié)構(gòu)不是冗余設(shè)計Deployment 負責版本和滾動策略ReplicaSet 負責某一版本的副本數(shù)Pod 才是真正被調(diào)度的單元。理解了這一層后面rollout history為什么能列出多條記錄就順理成章了。3.2 YAML 逐字段拆apiVersion 到 containers命令式適合驗證生產(chǎn)必須落到 YAML否則改一個副本數(shù)都要記參數(shù)。下面這份是課件里 Deployment 的加厚版把滾動更新策略和資源配額一起帶上。apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: default labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx # 必須與 template.metadata.labels 完全匹配 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 # 滾動時最多超出期望副本數(shù) 1 個 maxUnavailable: 0 # 滾動時不允許有副本不可用 revisionHistoryLimit: 10 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.25 imagePullPolicy: IfNotPresent ports: - containerPort: 80 resources: requests: cpu: 250m memory: 64Mi limits: cpu: 500m memory: 128MiapiVersion和kind是配對的寫錯組合會直接報no matches for kind不確定時用kubectl api-resources | grep deployment查當前集群支持哪個版本。selector.matchLabels與template.metadata.labels不匹配時 apply 會被拒絕報錯信息是selector does not match template labels這條報錯很直白照著改就行。replicas是期望副本數(shù)但控制器實際收斂需要幾秒剛 apply 完立刻查可能只有 1 個 Pod屬于正?,F(xiàn)象。revisionHistoryLimit默認就是 10意味著最多保留 10 個歷史 ReplicaSet調(diào)小能省 etcd 空間但會讓可回滾的版本變少。3.3 升級、擴縮容與回滾的操作序列# 升級鏡像改的是 Pod 模板會觸發(fā)滾動更新 kubectl set image deployment/web nginxnginx:1.25 # 阻塞等待滾動完成超時退出碼非 0適合放進腳本 kubectl rollout status deployment/web --timeout120s # 查看歷史版本REVISION 列就是回滾時要用的編號 kubectl rollout history deployment/web # 回到指定版本 kubectl rollout undo deployment/web --to-revision2 # 手動擴縮容 kubectl scale deployment web --replicas10 # 配置自動擴縮容CPU 超過 80% 時最多擴到 15 個 kubectl autoscale deployment web --min10 --max15 --cpu-percent80rollout status是我最推薦放進 CI 的一條命令它比sleep 30靠譜得多滾動失敗時會立刻返回而不是傻等。--to-revision有一個容易踩的點回滾本身會產(chǎn)生一個新的 revision 編號比如當前是 3回滾到 2 之后歷史里會多出一個 4內(nèi)容與 2 一致。所以腳本里寫死 revision 號遲早出問題更穩(wěn)的做法是記鏡像 tag。scale和autoscale同時存在會打架。HPA 接管之后會周期性改寫spec.replicas手動 scale 上去的數(shù)字過一會兒就被覆蓋回來排查時看到副本數(shù)自己變先查kubectl get hpa有沒有對應(yīng)的規(guī)則。3.4 滾動更新參數(shù)maxSurge 與 maxUnavailable 的實際影響這兩個參數(shù)決定了滾動更新的節(jié)奏也是「升級時服務(wù)到底會不會抖」的直接原因。maxSurge: 1加maxUnavailable: 0是最保守的組合先起一個新 Pod等它就緒再停一個舊的全程副本數(shù)只多不少。代價是需要集群有富余資源如果節(jié)點資源剛好卡滿新 Pod 調(diào)度不上去滾動就會永遠停在中間狀態(tài)。maxSurge: 0加maxUnavailable: 1則相反先停舊的再起新的省資源但會短暫少一個副本對流量敏感的服務(wù)不要這么配。兩者不能同時為 0否則滾動無法推進apply 時會直接被拒。滾動卡住的排查路徑很固定先kubectl rollout status看卡在哪一步再kubectl describe rs 新 RS 名看 Events。如果是FailedScheduling就是資源或親和性問題如果是Readiness probe failed就是應(yīng)用起來了但沒準備好接收流量這時候要去查就緒探針的路徑和端口而不是懷疑鏡像。4. Pod 為什么不是容器的簡單包裝infra container、拉取策略與配額4.1 共享網(wǎng)絡(luò)是怎么做到的Pod 是 K8s 的最小調(diào)度單元但它本身是個邏輯概念節(jié)點上并沒有一個叫 Pod 的東西。實現(xiàn)方式是每個 Pod 先起一個極小的 infra container也叫 pause 容器由它持有網(wǎng)絡(luò)命名空間然后把業(yè)務(wù)容器 join 進這個命名空間。于是同一 Pod 內(nèi)的容器看到的網(wǎng)卡、IP、路由表完全一致可以直接用127.0.0.1通信。這解釋了幾個日?,F(xiàn)象同 Pod 內(nèi)容器不能監(jiān)聽同一個端口因為共享同一張網(wǎng)卡nginx 加 php-fpm 這種組合放同一個 Pod 里nginx 直接fastcgi_pass 127.0.0.1:9000就行不用配 ServicePod 重建后 IP 會變因為它拿到的是新的網(wǎng)絡(luò)命名空間。存儲共享走的是另一條路靠 volume 掛載而不是命名空間。多個容器把同一個 emptyDir 掛到各自路徑下就能看到同樣的文件。課件里那個 nginx 日志的例子就是這個思路把容器內(nèi)的日志目錄掛到宿主機方便采集。apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: web image: registry.local/demo/nginx-php:1.0 volumeMounts: - name: logs mountPath: /usr/local/nginx/logs volumes: - name: logs hostPath: path: /tmp/logs type: DirectoryOrCreatetype: DirectoryOrCreate比Directory安全后者要求宿主機目錄必須已存在不存在時 Pod 會卡在 ContainerCreating 并報FailedMount。這一點在批量部署時格外明顯十臺節(jié)點里只要有一臺沒建目錄那臺機器上的 Pod 就永遠起不來。4.2 imagePullPolicy 三個值與 :latest 的隱式規(guī)則三個取值的含義分別是IfNotPresent本地沒有才拉Always每次創(chuàng)建都拉Never只用手動導入的鏡像。真正需要記住的是默認值規(guī)則它跟標簽有關(guān)而不是固定的當鏡像標簽是latest或者干脆不寫標簽時默認是Always寫了具體標簽時默認是IfNotPresent。所以生產(chǎn)環(huán)境用latest有兩個隱患一是每次 Pod 重建都要打倉庫倉庫抖動就直接ImagePullBackOff二是同一個標簽對應(yīng)的鏡像內(nèi)容可能已經(jīng)變了回滾時你以為回到了舊版本實際拉的是新內(nèi)容。我的做法是標簽寫死到小版本重要服務(wù)用 digest 固定形如nginxsha256:...這樣鏡像內(nèi)容不可變回滾才有確定性。4.3 requests 與 limitsCPU 單位、OOMKilled 與 QoS 分類這兩個字段經(jīng)常被混著寫其實職責完全不同。requests是調(diào)度依據(jù)調(diào)度器按它計算節(jié)點還剩多少可分配資源limits是運行時上限由容器運行時強制執(zhí)行。CPU 超過 limits 會被節(jié)流表現(xiàn)為響應(yīng)變慢但進程還在內(nèi)存超過 limits 會直接觸發(fā) OOMKilled容器被殺掉重啟。這個差異決定了排查方向CPU 問題看監(jiān)控里的 throttling 指標內(nèi)存問題看kubectl describe pod里的Last State: Terminated, Reason: OOMKilled。單位方面CPU 的m是千分之一核250m就是 0.25 核1000m等于 1。內(nèi)存的Mi、Gi是二進制單位1024 進制M、G是十進制兩者差 4.8% 左右配額算得緊的時候這點差異會變成事故。# 查看 Pod 的 QoS 等級 kubectl get pod web-7d9f8c6b5-abcde -o jsonpath{.status.qosClass} # 查看容器上次退出的原因OOMKilled 會在這里體現(xiàn) kubectl describe pod web-7d9f8c6b5-abcde | grep -A3 Last StateQoS 分三檔所有容器都設(shè)置了 requests 且等于 limits 是 Guaranteed部分設(shè)置是 Burstable一個都沒設(shè)是 BestEffort。節(jié)點資源緊張觸發(fā)驅(qū)逐時順序是 BestEffort 優(yōu)先被趕走Burstable 次之Guaranteed 最后。所以核心服務(wù)把 requests 和 limits 設(shè)成相等不只是為了穩(wěn)定也是為了在驅(qū)逐排序里靠后。不設(shè) requests 的后果比想象中嚴重。調(diào)度器會認為這個 Pod 不需要資源把它塞到已經(jīng)快滿的節(jié)點上實際跑起來內(nèi)存一漲節(jié)點整體進入壓力狀態(tài)最后被驅(qū)逐的可能是隔壁那個規(guī)規(guī)矩矩設(shè)了配額的服務(wù)。這就是為什么我堅持新服務(wù)上線前先把 requests 填上哪怕估值不準也比空著強。4.4 私有倉庫拉取imagePullSecrets 的創(chuàng)建與掛載內(nèi)網(wǎng)倉庫基本都要認證報錯表現(xiàn)為ErrImagePull或ImagePullBackOffdescribe的 Events 里會明確寫no basic auth credentials或者unauthorized。# 創(chuàng)建 docker-registry 類型的 Secret kubectl create secret docker-registry regcred \ --docker-serverregistry.local \ --docker-usernamedevops \ --docker-password密碼 \ --docker-emaildevexample.com # 掛到命名空間的默認 ServiceAccount 上該空間內(nèi) Pod 自動繼承 kubectl patch serviceaccount default \ -p {imagePullSecrets:[{name:regcred}]}掛載位置有兩種選擇。寫進 Pod 的spec.imagePullSecrets只對當前 Pod 生效適合跨團隊共享集群但倉庫權(quán)限不同的場景patch 到 ServiceAccount 上則整個命名空間生效省事但權(quán)限范圍大。密碼里有特殊字符時記得用單引號包住$和!在雙引號里會被 shell 展開這個坑我在不同環(huán)境里見過好幾次。5. 監(jiān)控與日志排查kubectl top 不出數(shù)、日志抓不到的五個坑5.1 metrics-server 的數(shù)據(jù)從哪來kubectl top背后依賴的是 metrics-server它本身不采集數(shù)據(jù)而是定期向每個節(jié)點的 kubelet 請求資源用量kubelet 再從 cAdvisor 拿容器級指標。metrics-server 把結(jié)果聚合成 Metrics API通過 APIService 注冊到 apiserver 上kubectl 和 HPA 都是從這條路讀數(shù)據(jù)。這個鏈路決定了排查順序先看 APIService 有沒有注冊成功再看 metrics-server Pod 是否健康最后看它能不能連通 kubelet 的 10250 端口。# APIService 的 AVAILABLE 必須是 True kubectl get apiservice v1beta1.metrics.k8s.io -o wide # 看節(jié)點和 Pod 的實時資源占用按內(nèi)存排序 kubectl top node kubectl top pod -A --sort-bymemory # metrics-server 自身日志證書和連接錯誤都在這里 kubectl logs -n kube-system deploy/metrics-server --tail50需要清楚一點metrics-server 只保留最近幾分鐘的數(shù)據(jù)不做長期存儲想看過往趨勢得另外上 Prometheus 之類的方案。它的定位就是給 HPA 和kubectl top供數(shù)不要指望它當監(jiān)控系統(tǒng)用。5.2 日志的三條路徑容器日志一般分三層看。第一層是應(yīng)用寫到標準輸出的內(nèi)容用kubectl logs讀這是最常用的。容器重啟過要看上次的日志加--previous多容器 Pod 要加-c指定容器名。第二層是節(jié)點上的日志文件。容器運行時會把標準輸出落到/var/log/pods/namespace_pod_uid/container/0.logPod 已經(jīng)被刪掉但節(jié)點上還有殘留時直接去這個路徑撈。第三層是組件自身的日志。kubelet 通常由 systemd 托管用journalctl -u kubelet看以靜態(tài) Pod 形式運行的控制面組件用kubectl logs -n kube-system pod看。# 持續(xù)跟蹤日志只顯示最后 100 行 kubectl logs -f deploy/web --tail100 # 看容器上一次崩潰前的日志 kubectl logs web-7d9f8c6b5-abcde -c nginx --previous # 跟蹤節(jié)點上 kubelet 的日志只看最近 10 分鐘 journalctl -u kubelet -f --since 10 min ago如果應(yīng)用是把日志寫文件而不是標準輸出kubectl logs什么都看不到這不是 bug。要么改成輸出到標準輸出要么用 emptyDir 或 hostPath 把日志目錄掛出來再接采集器。5.3 五條踩坑記錄現(xiàn)象一kubectl top node報error: Metrics API not available但 Pod 都正常。原因APIService 沒注冊成功或者 metrics-server 連不上 kubelet 的 10250 端口。自簽證書的集群上metrics-server 校驗 kubelet 證書失敗是高頻原因。解決先kubectl get apiservice v1beta1.metrics.k8s.io -o yaml看status.conditions里的 message再去翻 metrics-server 日志。確認是證書問題的話在它的啟動參數(shù)里加--kubelet-insecure-tls這是測試和生產(chǎn)自簽環(huán)境都常見的做法代價是放棄對 kubelet 證書的校驗。現(xiàn)象二Pod 一直 ContainerCreatingdescribe里 Events 顯示FailedMount。原因hostPath 寫了type: Directory但宿主機上目錄不存在或者掛載的 ConfigMap、Secret 還沒創(chuàng)建。解決type改成DirectoryOrCreate或者提前在節(jié)點上把目錄建好。用 DaemonSet 掛宿主機目錄時尤其要注意集群擴容進來的新節(jié)點不會自動帶上目錄得靠初始化腳本或 DaemonSet 自己創(chuàng)建?,F(xiàn)象三kubectl logs報previous terminated container xxx not found。原因容器已經(jīng)重啟過多次舊日志被運行時輪轉(zhuǎn)清理掉了--previous也拿不回來。解決短期靠及時抓長期靠把日志落盤到掛載卷或者接采集器。容器日志的輪轉(zhuǎn)策略是運行時管的默認單個文件到 10Mi 左右就會切業(yè)務(wù)日志寫得猛的話幾分鐘就沒?,F(xiàn)象四Service 訪問不通但后端 Pod 狀態(tài)是 Running。原因Endpoints 為空通常是 Service 的 selector 與 Pod 的 labels 不匹配或者targetPort寫成了 Service 端口。解決kubectl get endpoints svc-name先看有沒有后端地址空的話kubectl get svc svc-name -o yaml把 selector 抄出來跟 Pod 的 labels 逐字比對。大小寫和拼寫錯誤是主要來源app: nginx和app: Nginx在 YAML 里是兩個完全不同的選擇器?,F(xiàn)象五出問題想查事件kubectl get events是空的。原因事件默認只保留 1 小時apiserver 的--event-ttl參數(shù)排查拖久了就沒了。解決故障當下立刻執(zhí)行kubectl get events -A --sort-by.lastTimestamp把輸出重定向到文件留檔。超過保留期的只能靠提前部署的事件采集組件這個能力在事后復盤時價值很高。6. 調(diào)度、存儲與安全三個能當場跑通的驗證動作課件目錄里還有調(diào)度、存儲、集群安全三塊篇幅不多但都是容易「看著懂、上手懵」的部分。我的習慣是每塊至少跑一個最小驗證確認自己理解的和集群實際行為一致。調(diào)度這塊驗證方式是把 Pod 釘?shù)街付ü?jié)點再觀察結(jié)果。給 Pod 加nodeSelector或者直接用nodeName創(chuàng)建后kubectl get pod -o wide看 NODE 列是不是預(yù)期的那臺。用污點和容忍做反向驗證更直觀給節(jié)點打上kubectl taint node node envtest:NoSchedule不帶容忍的 Pod 會 Pendingdescribe里的FailedScheduling會明確寫出污點不匹配的原因。這比讀十遍文檔管用。# 給節(jié)點打污點再驗證不帶容忍的 Pod 是否被擋住 kubectl taint node node-01 envtest:NoSchedule kubectl run probe --imagenginx:1.25 kubectl describe pod probe | grep -A2 FailedScheduling # 驗證某個 ServiceAccount 在命名空間里有哪些權(quán)限 kubectl auth can-i --list \ --assystem:serviceaccount:default:deployer \ -n default存儲這塊PVC 一直 Pending 時按三步查kubectl get storageclass看有沒有可用的 StorageClasskubectl describe pvc name看 Events 里是no persistent volumes available還是waiting for a volume to be created再比對 PVC 的accessModes和 PV 支持的是不是一致。ReadWriteOnce和ReadOnlyMany寫混了不會報語法錯只會靜靜掛起。安全這塊RBAC 的驗證靠kubectl auth can-i上面那條命令會把這個身份能做的動作全列出來。我在給新同事分配 kubeconfig 之前一定會跑一次確認權(quán)限范圍跟預(yù)期一致避免出現(xiàn)「以為只給了只讀實際能刪 Deployment」這種事。有個習慣我改不掉任何環(huán)境做變更之前先跑一遍kubectl get --raw /healthz加一次 etcd 快照。這個動作花不到一分鐘但在我誤刪過一整個命名空間之后它就成了肌肉記憶。希望幫到你。本文還有配套的精品資源點擊獲取