戰(zhàn):從環(huán)境準(zhǔn)備到網(wǎng)絡(luò)配置的完整踩坑指南)
1. 項(xiàng)目概述與核心痛點(diǎn)最近在給團(tuán)隊(duì)搭建一套新的KubernetesK8s測(cè)試集群從零開始走了一遍部署流程。雖然官方文檔和各種教程滿天飛但真到自己動(dòng)手從環(huán)境準(zhǔn)備到組件拉起再到集群可用每一步都可能遇到意想不到的“坑”。這次部署的目標(biāo)是一個(gè)三節(jié)點(diǎn)的生產(chǎn)級(jí)測(cè)試集群1 Master 2 Worker使用containerd作為容器運(yùn)行時(shí)Calico作為網(wǎng)絡(luò)插件。整個(gè)過(guò)程下來(lái)最大的感觸就是K8s部署的成功往往不在于你記住了多少命令而在于你是否理解每個(gè)命令背后的原理以及當(dāng)命令失敗時(shí)你能否快速定位到那個(gè)“搗鬼”的配置項(xiàng)。這篇文章我就把這次部署中遇到的關(guān)鍵問題、排查思路和最終解決方案以“踩坑記錄”的形式整理出來(lái)希望能幫你繞過(guò)我走過(guò)的彎路。對(duì)于剛接觸K8s的朋友來(lái)說(shuō)部署集群是第一個(gè)“下馬威”。它不像安裝一個(gè)單機(jī)軟件那么簡(jiǎn)單涉及到操作系統(tǒng)配置、容器運(yùn)行時(shí)、網(wǎng)絡(luò)、存儲(chǔ)等多個(gè)層面的協(xié)調(diào)。常見的痛點(diǎn)集中在幾個(gè)方面系統(tǒng)參數(shù)配置不當(dāng)如關(guān)閉swap、配置內(nèi)核模塊、容器運(yùn)行時(shí)與kubelet的cgroup驅(qū)動(dòng)不一致導(dǎo)致節(jié)點(diǎn)無(wú)法注冊(cè)、網(wǎng)絡(luò)插件安裝后Pod之間無(wú)法通信、以及證書相關(guān)的問題導(dǎo)致組件間認(rèn)證失敗。這些問題往往相互關(guān)聯(lián)一個(gè)環(huán)節(jié)出錯(cuò)表象可能出現(xiàn)在另一個(gè)完全不同的地方排查起來(lái)非常考驗(yàn)對(duì)K8s架構(gòu)的理解。2. 環(huán)境準(zhǔn)備與前置條件梳理部署K8s集群第一步不是急著運(yùn)行kubeadm init而是要把基礎(chǔ)環(huán)境打磨好。這就像蓋房子前要打好地基地基不穩(wěn)后面砌再高的墻也容易塌。2.1 操作系統(tǒng)與內(nèi)核要求我們選用的是Ubuntu 22.04 LTS。選擇穩(wěn)定的、K8s社區(qū)支持良好的Linux發(fā)行版至關(guān)重要。首先必須確保所有節(jié)點(diǎn)Master和Worker的系統(tǒng)主機(jī)名、/etc/hosts文件配置正確且能夠互相解析。我遇到過(guò)因?yàn)橹鳈C(jī)名帶下劃線而導(dǎo)致kubelet啟動(dòng)失敗的問題所以最好使用標(biāo)準(zhǔn)的DNS命名規(guī)則僅包含字母、數(shù)字、連字符和點(diǎn)。接下來(lái)是內(nèi)核參數(shù)的調(diào)整。K8s對(duì)Linux內(nèi)核有一些硬性要求比如必須關(guān)閉swap。這不僅僅是為了性能更是因?yàn)閗ubelet的默認(rèn)行為假設(shè)節(jié)點(diǎn)有充足的非交換內(nèi)存。關(guān)閉swap可以通過(guò)sudo swapoff -a臨時(shí)生效并編輯/etc/fstab永久注釋掉swap分區(qū)行。此外還需要加載一些必需的內(nèi)核模塊如br_netfilter、ip_vs等并配置sysctl參數(shù)以啟用IP轉(zhuǎn)發(fā)和橋接流量。# 加載內(nèi)核模塊 sudo modprobe br_netfilter sudo modprobe ip_vs sudo modprobe ip_vs_rr sudo modprobe ip_vs_wrr sudo modprobe ip_vs_sh sudo modprobe nf_conntrack # 配置sysctl參數(shù) cat EOF | sudo tee /etc/modules-load.d/k8s.conf br_netfilter EOF cat EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables 1 net.bridge.bridge-nf-call-iptables 1 net.ipv4.ip_forward 1 EOF sudo sysctl --system注意sysctl --system會(huì)重新加載所有配置文件確保上述配置生效。如果遇到bridge-nf-call參數(shù)報(bào)“文件不存在”的錯(cuò)誤通常是因?yàn)閎r_netfilter模塊沒有成功加載請(qǐng)先用lsmod | grep br_netfilter檢查。2.2 容器運(yùn)行時(shí)選型與安裝Containerd實(shí)戰(zhàn)K8s早已不再綁定Docker事實(shí)上從1.24版本開始Dockershim已被移除你需要直接選擇一種容器運(yùn)行時(shí)接口CRI兼容的運(yùn)行時(shí)。主流的選項(xiàng)是containerd和CRI-O。我們選擇containerd因?yàn)樗阅軆?yōu)秀、資源占用少且是Docker的底層運(yùn)行時(shí)生態(tài)成熟。安裝containerd推薦使用官方二進(jìn)制包或從發(fā)行版?zhèn)}庫(kù)安裝。這里以官方二進(jìn)制為例。下載解壓后需要生成默認(rèn)配置文件/etc/containerd/config.toml。這里藏著第一個(gè)大坑cgroup驅(qū)動(dòng)。# 安裝containerd wget https://github.com/containerd/containerd/releases/download/v1.7.13/containerd-1.7.13-linux-amd64.tar.gz sudo tar Cxzvf /usr/local containerd-1.7.13-linux-amd64.tar.gz sudo systemctl enable --now containerd # 生成默認(rèn)配置 sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml生成配置后關(guān)鍵一步是修改cgroup驅(qū)動(dòng)。K8s的kubelet默認(rèn)使用systemd作為cgroup驅(qū)動(dòng)而containerd默認(rèn)生成的配置中SystemdCgroup參數(shù)是false。如果不一致kubelet在啟動(dòng)時(shí)會(huì)報(bào)錯(cuò)節(jié)點(diǎn)狀態(tài)一直是NotReady。# 編輯 /etc/containerd/config.toml [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc] ... [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc.options] SystemdCgroup true # 將這里改為 true修改后重啟containerdsudo systemctl restart containerd。務(wù)必使用sudo systemctl status containerd檢查服務(wù)狀態(tài)確保沒有錯(cuò)誤日志。2.3 K8s組件安裝與版本鎖定安裝kubeadm, kubelet和kubectl。建議使用阿里云或谷歌的鏡像源來(lái)加速下載。這里又一個(gè)細(xì)節(jié)在安裝kubelet后不要立即啟動(dòng)它。因?yàn)榇藭r(shí)集群還未初始化kubelet會(huì)不斷嘗試連接一個(gè)不存在的API Server產(chǎn)生大量錯(cuò)誤日志。# 添加阿里云鏡像源 sudo apt-get update sudo apt-get install -y apt-transport-https curl curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add - echo deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main | sudo tee /etc/apt/sources.list.d/kubernetes.list # 安裝指定版本保持各節(jié)點(diǎn)版本一致 sudo apt-get update sudo apt-get install -y kubelet1.28.0-00 kubeadm1.28.0-00 kubectl1.28.0-00 sudo apt-mark hold kubelet kubeadm kubectl # 鎖定版本防止意外升級(jí)apt-mark hold命令非常重要它能防止系統(tǒng)自動(dòng)更新時(shí)升級(jí)K8s組件避免因版本不一致導(dǎo)致集群故障。在所有節(jié)點(diǎn)上重復(fù)上述環(huán)境準(zhǔn)備步驟確保配置完全一致。3. 集群初始化與首個(gè)“攔路虎”基礎(chǔ)環(huán)境就緒后就可以在Master節(jié)點(diǎn)上執(zhí)行初始化命令了。這是最激動(dòng)人心也最容易出錯(cuò)的一步。3.1 kubeadm init 命令參數(shù)解析不要直接運(yùn)行sudo kubeadm init建議使用配置文件來(lái)初始化這樣參數(shù)清晰、可重復(fù)。創(chuàng)建一個(gè)kubeadm-config.yaml文件apiVersion: kubeadm.k8s.io/v1beta3 kind: InitConfiguration localAPIEndpoint: advertiseAddress: 192.168.1.100 # 替換為Master節(jié)點(diǎn)的實(shí)際IP bindPort: 6443 nodeRegistration: criSocket: unix:///var/run/containerd/containerd.sock imagePullPolicy: IfNotPresent taints: [] --- apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration kubernetesVersion: v1.28.0 controlPlaneEndpoint: 192.168.1.100:6443 # 高可用時(shí)可配置負(fù)載均衡器VIP networking: podSubnet: 192.168.0.0/16 # 必須與后續(xù)安裝的CNI插件如Calico的默認(rèn)網(wǎng)段匹配 serviceSubnet: 10.96.0.0/12 apiServer: extraArgs: authorization-mode: Node,RBAC timeoutForControlPlane: 4m0s imageRepository: registry.aliyuncs.com/google_containers # 使用國(guó)內(nèi)鏡像源加速 --- apiVersion: kubelet.config.k8s.io/v1beta1 kind: KubeletConfiguration cgroupDriver: systemd # 明確指定kubelet使用systemd cgroup驅(qū)動(dòng)重點(diǎn)關(guān)注幾個(gè)參數(shù)advertiseAddressMaster節(jié)點(diǎn)的IP其他節(jié)點(diǎn)將通過(guò)這個(gè)地址連接API Server。podSubnet這是Pod的IP地址范圍。這個(gè)值必須與你將要安裝的網(wǎng)絡(luò)插件CNI的默認(rèn)網(wǎng)段一致。例如Calico的默認(rèn)IPPool是192.168.0.0/16。如果不一致網(wǎng)絡(luò)插件將無(wú)法正確分配IP導(dǎo)致Pod無(wú)法啟動(dòng)。imageRepository墻內(nèi)必備。指向阿里云鏡像倉(cāng)庫(kù)可以極大加快鏡像拉取速度避免初始化卡在Pull鏡像階段。cgroupDriver: systemd在KubeletConfiguration中顯式聲明與containerd的配置遙相呼應(yīng)雙重保險(xiǎn)。3.2 初始化過(guò)程詳解與常見報(bào)錯(cuò)執(zhí)行初始化sudo kubeadm init --configkubeadm-config.yaml --upload-certs | tee kubeadm-init.log。使用tee命令將輸出同時(shí)保存到文件方便后續(xù)排查。初始化過(guò)程會(huì)依次進(jìn)行預(yù)檢、拉取鏡像、生成證書和靜態(tài)Pod清單等。這里最容易卡住的地方是鏡像拉取。即使配置了國(guó)內(nèi)鏡像源也可能因?yàn)榫W(wǎng)絡(luò)波動(dòng)導(dǎo)致某個(gè)鏡像拉取失敗。觀察輸出日志如果卡在某個(gè)鏡像上可以手動(dòng)去其他節(jié)點(diǎn)docker pull或crictl pull對(duì)應(yīng)的鏡像然后打tag。另一個(gè)常見錯(cuò)誤是[ERROR Port-6443]或[ERROR Port-10259]等端口占用。這通常是因?yàn)橹安渴鹗『笙嚓P(guān)組件沒有清理干凈或者有其他服務(wù)占用了K8s默認(rèn)端口6443, 10250, 10259等。使用sudo netstat -tlnp | grep 端口號(hào)檢查并解決沖突。如果初始化失敗可以使用sudo kubeadm reset -f進(jìn)行清理它會(huì)重置kubeadm所做的更改。但注意kubeadm reset不會(huì)清除iptables規(guī)則和CNI插件創(chuàng)建的網(wǎng)橋設(shè)備這些需要手動(dòng)清理。# 清理網(wǎng)絡(luò)殘留在重置后執(zhí)行 sudo iptables -F sudo iptables -t nat -F sudo iptables -t mangle -F sudo iptables -X sudo ip link delete cni0 2/dev/null sudo ip link delete flannel.1 2/dev/null sudo ip link delete cali* 2/dev/null 2/dev/null # 如果用了Calico初始化成功后會(huì)輸出加入集群的命令類似于kubeadm join ...。務(wù)必把這段信息保存好。按照提示配置kubectlmkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config此時(shí)運(yùn)行kubectl get nodes應(yīng)該能看到Master節(jié)點(diǎn)但狀態(tài)是NotReady因?yàn)榫W(wǎng)絡(luò)插件CNI還沒有安裝。4. 網(wǎng)絡(luò)插件部署與跨節(jié)點(diǎn)通信難題CNI插件是K8s集群的“神經(jīng)系統(tǒng)”負(fù)責(zé)Pod之間的網(wǎng)絡(luò)通信。沒有它集群就是癱瘓的。我們選擇Calico功能強(qiáng)大且文檔完善。4.1 Calico安裝與關(guān)鍵配置核對(duì)安裝Calico通常很簡(jiǎn)單一條命令即可kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.4/manifests/calico.yaml但是魔鬼在細(xì)節(jié)里。直接應(yīng)用這個(gè)官方y(tǒng)aml很可能導(dǎo)致Pod網(wǎng)絡(luò)與你的kubeadm配置沖突。最大的坑就是Pod子網(wǎng)CIDR不匹配。在初始化時(shí)我們?cè)O(shè)置了podSubnet: 192.168.0.0/16而Calico默認(rèn)的IP池IPPool可能也是這個(gè)網(wǎng)段這看起來(lái)沒問題。但如果你的物理網(wǎng)絡(luò)恰好也是192.168.0.0/16就會(huì)產(chǎn)生路由沖突。或者你之前初始化時(shí)用了別的網(wǎng)段那Calico Pod將無(wú)法分配IP。解決方案在安裝前先下載Calico的yaml文件檢查并修改其IP池配置。wget https://raw.githubusercontent.com/projectcalico/calico/v3.26.4/manifests/calico.yaml用編輯器打開calico.yaml搜索CIDR或IPPOOL。你會(huì)找到一個(gè)Calico自定義資源定義CRD的配置部分。確保其cidr字段與kubeadm配置中的podSubnet完全一致。apiVersion: crd.projectcalico.org/v1 kind: IPPool metadata: name: default-ipv4-ippool spec: blockSize: 26 cidr: 192.168.0.0/16 # 確認(rèn)這里與 podSubnet 一致 ipipMode: Never natOutgoing: true nodeSelector: all() vxlanMode: Always修改保存后再應(yīng)用kubectl apply -f calico.yaml。應(yīng)用后使用kubectl get pods -n kube-system觀察calico-node-xxx和calico-kube-controllers-xxx這些Pod的狀態(tài)直到全部變?yōu)镽unning。4.2 節(jié)點(diǎn)NotReady問題深度排查即使Calico Pod跑起來(lái)了kubectl get nodes可能依然顯示NotReady。這是最讓人頭疼的階段需要系統(tǒng)化排查。檢查kubelet狀態(tài)在問題節(jié)點(diǎn)上運(yùn)行sudo systemctl status kubelet -l。查看是否有紅色錯(cuò)誤日志。常見錯(cuò)誤是“cgroup driver mismatch”或“failed to run kubelet”。檢查容器運(yùn)行時(shí)運(yùn)行sudo crictl ps看pause容器和k8s核心組件如etcd, apiserver的容器是否正常運(yùn)行。如果crictl命令報(bào)錯(cuò)或沒有容器說(shuō)明containerd沒有正確服務(wù)kubelet。檢查CNI插件在節(jié)點(diǎn)上查看CNI配置和日志。ls -la /etc/cni/net.d/ # 應(yīng)該能看到Calico的配置文件 sudo journalctl -u kubelet -f | grep -i cni # 查看kubelet日志中關(guān)于CNI的錯(cuò)誤檢查Calico Node DaemonSetkubectl describe pod calico-node-xxxx -n kube-system。關(guān)注Events部分和容器狀態(tài)。常見問題是鏡像拉取失敗、權(quán)限不足需要掛載/var/run/calico等目錄或節(jié)點(diǎn)標(biāo)簽不匹配。檢查IP分配Calico為每個(gè)節(jié)點(diǎn)分配一個(gè)Pod網(wǎng)段塊。在Master節(jié)點(diǎn)上運(yùn)行kubectl get ipamblock -o yaml可以查看分配情況。如果某個(gè)節(jié)點(diǎn)的塊沒有分配成功該節(jié)點(diǎn)上的Pod就無(wú)法獲取IP。我遇到的一個(gè)典型問題是Worker節(jié)點(diǎn)一直NotReadykubelet日志顯示network plugin is not ready: cni config uninitialized。檢查/etc/cni/net.d/發(fā)現(xiàn)是空的。原因是Calico的calico-nodePod在該節(jié)點(diǎn)上啟動(dòng)失敗。進(jìn)一步describe該P(yáng)od發(fā)現(xiàn)事件是Failed to create pod sandbox: rpc error: code Unknown desc failed to setup network for sandbox ...。這通常指向更底層的網(wǎng)絡(luò)問題比如主機(jī)iptables規(guī)則沖突、內(nèi)核模塊缺失或者節(jié)點(diǎn)防火墻如ufw沒有關(guān)閉。實(shí)操心得遇到節(jié)點(diǎn)NotReady不要慌按照“kubelet日志 - 容器運(yùn)行時(shí)狀態(tài) - CNI配置與日志 - 網(wǎng)絡(luò)插件Pod狀態(tài)”這條鏈路自上而下或自下而上進(jìn)行排查總能定位到問題根源。善用journalctl和kubectl describe、kubectl logs這三個(gè)命令。5. Worker節(jié)點(diǎn)加入與認(rèn)證故障Master節(jié)點(diǎn)Ready后就可以讓W(xué)orker節(jié)點(diǎn)加入了。在每個(gè)Worker節(jié)點(diǎn)上運(yùn)行Master初始化成功后給出的kubeadm join命令。5.1 join命令執(zhí)行與令牌管理kubeadm join命令包含API Server地址、令牌和CA證書哈希。令牌默認(rèn)24小時(shí)有效。如果令牌過(guò)期可以在Master節(jié)點(diǎn)上重新生成# 生成新的令牌 kubeadm token create --print-join-command # 獲取CA證書哈希 openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2/dev/null | openssl dgst -sha256 -hex | sed s/^.* //將新令牌和哈希值組合成新的kubeadm join命令。Worker節(jié)點(diǎn)執(zhí)行join后使用kubectl get nodes在Master上觀察新節(jié)點(diǎn)會(huì)先處于NotReady狀態(tài)待Calico等Pod調(diào)度到該節(jié)點(diǎn)并運(yùn)行后狀態(tài)會(huì)變?yōu)镽eady。5.2 節(jié)點(diǎn)加入失敗的認(rèn)證與網(wǎng)絡(luò)排查Worker節(jié)點(diǎn)加入失敗常見原因有網(wǎng)絡(luò)不通Worker節(jié)點(diǎn)無(wú)法訪問Master節(jié)點(diǎn)的6443端口。用telnet master-ip 6443或curl -k https://master-ip:6443測(cè)試。令牌或證書哈希無(wú)效確保復(fù)制的命令完整無(wú)誤特別是超長(zhǎng)的證書哈希。時(shí)間不同步所有節(jié)點(diǎn)的時(shí)間必須基本同步否則TLS握手會(huì)失敗。使用chronyd或ntpd服務(wù)確保時(shí)間同步。Hostname沖突集群內(nèi)節(jié)點(diǎn)主機(jī)名必須唯一。如果join命令看似成功但節(jié)點(diǎn)一直不出現(xiàn)檢查Master節(jié)點(diǎn)上kube-apiserver的日志sudo journalctl -u kube-apiserver -f看是否有來(lái)自Worker節(jié)點(diǎn)的連接請(qǐng)求和認(rèn)證錯(cuò)誤。6. 核心組件狀態(tài)監(jiān)控與問題修復(fù)集群初步就緒后需要確保所有核心系統(tǒng)Pod都健康運(yùn)行。這些Pod都在kube-system命名空間下。6.1 系統(tǒng)Pod健康檢查清單運(yùn)行kubectl get pods -n kube-system你應(yīng)該看到以下核心組件具體名字前綴可能不同coredns-xxxDNS服務(wù)通常有兩個(gè)副本。如果處于Pending或CrashLoopBackOff通常是網(wǎng)絡(luò)問題。etcd-master-hostname鍵值存儲(chǔ)數(shù)據(jù)庫(kù)Master節(jié)點(diǎn)獨(dú)有。如果異常整個(gè)集群控制面將癱瘓。kube-apiserver-master-hostnameAPI服務(wù)器。kube-controller-manager-master-hostname控制器管理器。kube-scheduler-master-hostname調(diào)度器。calico-node-xxx每個(gè)節(jié)點(diǎn)上都有一個(gè)負(fù)責(zé)本節(jié)點(diǎn)網(wǎng)絡(luò)。calico-kube-controllers-xxxCalico的控制器通常一個(gè)副本。任何一個(gè)組件異常都需要立即排查。使用kubectl describe pod pod-name -n kube-system和kubectl logs pod-name -n kube-system查看詳細(xì)原因。6.2 DNS與CoreDNS排錯(cuò)實(shí)戰(zhàn)CoreDNS是最容易出問題的地方之一。癥狀是Pod內(nèi)無(wú)法解析集群內(nèi)服務(wù)名如kubernetes.default.svc.cluster.local或外部域名。診斷步驟在任意Pod內(nèi)或臨時(shí)運(yùn)行一個(gè)busyboxPod執(zhí)行nslookup kubernetes.default。如果解析失敗檢查CoreDNS Pod日志kubectl logs -l k8s-appkube-dns -n kube-system。檢查CoreDNS的ConfigMapkubectl get configmap coredns -n kube-system -o yaml。默認(rèn)配置通常沒問題但如果你自定義了上游DNS或域名需要仔細(xì)核對(duì)。檢查節(jié)點(diǎn)上的/etc/resolv.conf。kubelet會(huì)使用該文件中的nameserver作為Pod的默認(rèn)上游DNS。如果這里面是127.0.0.1而節(jié)點(diǎn)本地沒有運(yùn)行DNS服務(wù)就會(huì)導(dǎo)致解析失敗。解決方法是在kubelet啟動(dòng)參數(shù)中配置--resolv-conf指向正確的文件或者確保本地有可用的DNS轉(zhuǎn)發(fā)服務(wù)。我遇到過(guò)一個(gè)經(jīng)典案例所有Pod內(nèi)部DNS解析超時(shí)。檢查CoreDNS Pod日志發(fā)現(xiàn)大量read udp i/o timeout錯(cuò)誤。原因是節(jié)點(diǎn)防火墻規(guī)則丟棄了UDP 53端口DNS查詢端口的流量。雖然Calico管理了Pod網(wǎng)絡(luò)但Pod訪問節(jié)點(diǎn)本地DNS服務(wù)器如/etc/resolv.conf中的8.8.8.8的流量仍然會(huì)經(jīng)過(guò)主機(jī)的網(wǎng)絡(luò)棧受主機(jī)防火墻規(guī)則影響。解決方案是調(diào)整主機(jī)防火墻允許DNS查詢流量。7. 存儲(chǔ)、Ingress與后續(xù)組件部署考量基礎(chǔ)集群穩(wěn)定后就可以考慮部署有狀態(tài)應(yīng)用了這涉及到存儲(chǔ)和外部訪問。7.1 存儲(chǔ)類StorageClass與本地路徑供給器測(cè)試環(huán)境中最簡(jiǎn)單的存儲(chǔ)方案是使用local-path-provisioner。它能為每個(gè)節(jié)點(diǎn)提供基于本地路徑的動(dòng)態(tài)持久卷PV。# 部署 local-path-provisioner kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.24/deploy/local-path-storage.yaml # 將其設(shè)為默認(rèn)StorageClass kubectl patch storageclass local-path -p {metadata: {annotations:{storageclass.kubernetes.io/is-default-class:true}}}部署后創(chuàng)建PVCPersistentVolumeClaim時(shí)如果不指定storageClassName就會(huì)自動(dòng)使用local-path來(lái)動(dòng)態(tài)創(chuàng)建PV。注意這種存儲(chǔ)是節(jié)點(diǎn)親和的Pod被調(diào)度到哪個(gè)節(jié)點(diǎn)存儲(chǔ)卷就在該節(jié)點(diǎn)的本地目錄創(chuàng)建。如果Pod被重新調(diào)度到其他節(jié)點(diǎn)將無(wú)法訪問原有數(shù)據(jù)因此僅適用于測(cè)試或可丟失的數(shù)據(jù)。7.2 Ingress Controller選型與部署要讓外部流量訪問集群內(nèi)的服務(wù)需要Ingress Controller。我們選擇Nginx Ingress Controller它功能全面、社區(qū)活躍。# 使用Helm安裝需先安裝Helm helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm repo update helm install ingress-nginx ingress-nginx/ingress-nginx --namespace ingress-nginx --create-namespace部署后需要確定Ingress Controller的Service類型。在云環(huán)境通常用LoadBalancer在裸機(jī)環(huán)境則常用NodePort。如果使用NodePort可以通過(guò)任意節(jié)點(diǎn)的IP和分配的端口如http://node-ip:30080來(lái)訪問Ingress。為了有一個(gè)固定的訪問入口我們可以在前面再部署一個(gè)負(fù)載均衡器如HAProxy或者使用MetalLB一個(gè)裸機(jī)負(fù)載均衡器實(shí)現(xiàn)。部署Ingress時(shí)常見的問題是404或503錯(cuò)誤。排查思路kubectl get ingress檢查Ingress資源是否被正確創(chuàng)建ADDRESS字段是否為空。kubectl describe ingress name查看Events是否有配置錯(cuò)誤。kubectl get pods -n ingress-nginx檢查Ingress Controller Pod是否Running。查看Ingress Controller Pod的日志kubectl logs -l app.kubernetes.io/nameingress-nginx -n ingress-nginx里面會(huì)有詳細(xì)的轉(zhuǎn)發(fā)規(guī)則和錯(cuò)誤信息。檢查Ingress中定義的backendserviceName和servicePort是否與集群內(nèi)真實(shí)的Service完全匹配包括命名空間。8. 日常維護(hù)與故障排查工具箱集群跑起來(lái)不是終點(diǎn)日常維護(hù)和故障排查能力同樣重要。8.1 必備的kubectl診斷命令掌握以下命令組合能解決80%的日常問題資源概覽kubectl get all -A查看所有命名空間所有資源Pod詳情kubectl describe pod pod-name -n namespace看事件、狀態(tài)詳情Pod日志kubectl logs -f pod-name -n namespace實(shí)時(shí)查看日志進(jìn)入Podkubectl exec -it pod-name -n namespace -- /bin/sh用于調(diào)試資源YAMLkubectl get resource-type resource-name -n namespace -o yaml獲取配置節(jié)點(diǎn)資源kubectl describe node node-name查看節(jié)點(diǎn)資源使用、事件、污點(diǎn)服務(wù)端點(diǎn)kubectl get endpoints service-name查看Service背后真實(shí)的Pod IP和端口8.2 集群重置與安全清理指南當(dāng)集群徹底混亂需要推倒重來(lái)時(shí)請(qǐng)按順序執(zhí)行驅(qū)逐節(jié)點(diǎn)可選kubectl drain node-name --ignore-daemonsets --delete-emptydir-data重置節(jié)點(diǎn)在每個(gè)節(jié)點(diǎn)上執(zhí)行sudo kubeadm reset -f清理網(wǎng)絡(luò)每節(jié)點(diǎn)sudo iptables -F sudo iptables -t nat -F sudo iptables -t mangle -F sudo iptables -X sudo ip link delete cni0 2/dev/null sudo ip link delete flannel.1 2/dev/null # 清理CNI配置和二進(jìn)制文件 sudo rm -rf /etc/cni/net.d sudo rm -rf /opt/cni/bin清理配置文件rm -rf $HOME/.kube sudo rm -rf /etc/kubernetes卸載軟件包如需要sudo apt-get purge kubeadm kubectl kubelet kubernetes-cni重要提醒kubeadm reset和清理操作會(huì)永久刪除所有集群數(shù)據(jù)和應(yīng)用僅用于測(cè)試環(huán)境或確定要銷毀集群時(shí)。生產(chǎn)環(huán)境務(wù)必先備份ETCD和數(shù)據(jù)卷。部署Kubernetes集群就像完成一個(gè)精密的拼圖每一塊組件、配置都必須嚴(yán)絲合縫。這次踩坑經(jīng)歷讓我深刻體會(huì)到理解其架構(gòu)原理如kubelet與容器運(yùn)行時(shí)的交互、CNI插件的工作機(jī)制、kube-apiserver的認(rèn)證流程遠(yuǎn)比死記硬背命令更重要。當(dāng)遇到問題時(shí)順著日志和事件這條“線索”結(jié)合對(duì)原理的理解總能找到問題的根源。最后保持耐心善用社區(qū)和文檔每一個(gè)坑踩過(guò)去都是對(duì)這套強(qiáng)大系統(tǒng)更深入的認(rèn)識(shí)。