控排查的完整路徑)
Docker 和 K8S 一直是 Linux 運(yùn)維繞不開的兩個(gè)關(guān)鍵詞。如果你剛接觸運(yùn)維崗位或者正準(zhǔn)備從傳統(tǒng)虛擬機(jī)轉(zhuǎn)向容器化部署大概率會(huì)在面試和日常工作中被這兩個(gè)詞反復(fù)轟炸。很多人在學(xué)習(xí)時(shí)最大的問題不是找不到資料而是資料太多不知道先裝哪個(gè)、先學(xué)哪個(gè)、跑到哪一步算學(xué)會(huì)。這篇文章按我實(shí)際帶人的順序來寫先搞清楚 Docker 和 K8S 各自解決了什么問題再把環(huán)境裝起來跑通第一個(gè)容器然后進(jìn)入 K8S 的 Pod、Service、監(jiān)控和故障排查最后給一份可以直接照著做的學(xué)習(xí)落地清單。如果你只有一臺(tái)普通機(jī)器甚至 Windows 筆記本也可以跟著走完大部分流程。1. 先理清概念Docker 和 K8S 到底解決什么問題很多新手一上來就急著裝環(huán)境結(jié)果被一堆鏡像、容器、YAML 文件繞暈。我建議先花 20 分鐘把概念理順因?yàn)楹竺嫠胁僮鞫冀⒃凇盀槭裁匆盟鼈儭边@個(gè)基礎(chǔ)上。1.1 沒有容器之前運(yùn)維最頭疼的是什么傳統(tǒng)的部署方式是直接在服務(wù)器上裝環(huán)境。Java 應(yīng)用要裝 JDKPython 應(yīng)用要裝特定版本的依賴數(shù)據(jù)庫(kù)要單獨(dú)維護(hù)實(shí)例。第一次部署還好第二次、第三次只要機(jī)器環(huán)境稍微不一樣就會(huì)出現(xiàn)“開發(fā)環(huán)境能跑測(cè)試環(huán)境跑不起來生產(chǎn)環(huán)境更跑不起來”的問題。這種“環(huán)境不一致”是最消耗時(shí)間的事情。你可能為了一個(gè)依賴版本差異排查一整天。虛擬機(jī)能解決一部分問題但虛擬機(jī)很重一個(gè)基礎(chǔ)系統(tǒng)鏡像要幾個(gè) GB啟動(dòng)要幾十秒甚至幾分鐘每臺(tái)虛擬機(jī)還要單獨(dú)分配 CPU、內(nèi)存和磁盤資源。容器化解決的就是“把應(yīng)用和它的運(yùn)行環(huán)境一起打包”。Docker 把程序、依賴、配置文件、啟動(dòng)命令都寫進(jìn)一個(gè)鏡像鏡像在任何裝有 Docker 的機(jī)器上都能以同樣的方式啟動(dòng)。啟動(dòng)一個(gè)容器通常只需要一兩秒比虛擬機(jī)輕量得多。隔離性是有的但不是完整的操作系統(tǒng)級(jí)隔離而是共享宿主機(jī)內(nèi)核。用一句話理解Docker 的核心價(jià)值是“一次構(gòu)建到處運(yùn)行”。它把過去繁瑣的環(huán)境配置工作提前打包好了。1.2 容器多了以后為什么需要 K8S單機(jī)環(huán)境下Docker 管理幾十個(gè)容器還勉強(qiáng)可以。容器少的時(shí)候你用docker run一條一條啟動(dòng)再配合 docker compose 編排基本夠用。但一旦應(yīng)用到多臺(tái)服務(wù)器問題就來了某臺(tái)機(jī)器掛了容器怎么自動(dòng)遷移到另一臺(tái)機(jī)器流量高峰期需要擴(kuò)容是手動(dòng)再啟動(dòng)幾個(gè)容器還是能自動(dòng)伸縮多個(gè)容器分布在多臺(tái)機(jī)器上它們之間怎么互相訪問發(fā)布新版本的時(shí)候能不能滾動(dòng)更新且不中斷服務(wù)這些問題 Docker 單機(jī)版都給不了完整答案。K8S 就是用來解決“多機(jī)環(huán)境下容器怎么調(diào)度、怎么管理、怎么恢復(fù)”的編排系統(tǒng)。K8S 里有一個(gè)核心思想叫“聲明式管理”你告訴它期望的狀態(tài)比如“我要運(yùn)行 3 個(gè) nginx 副本”它會(huì)自己去創(chuàng)建 Pod、調(diào)度到合適的節(jié)點(diǎn)、保持副本數(shù)始終是 3。節(jié)點(diǎn)掛了它會(huì)自動(dòng)在另一臺(tái)節(jié)點(diǎn)上重新創(chuàng)建 Pod直到集群恢復(fù)期望狀態(tài)。一個(gè)容易理解的比喻是Docker 像打包和拉貨的車負(fù)責(zé)把貨物打包成標(biāo)準(zhǔn)箱子并啟動(dòng)運(yùn)輸K8S 像物流調(diào)度中心它不負(fù)責(zé)造箱子但負(fù)責(zé)決定箱子放哪臺(tái)車、怎么分配路線、車壞了以后怎么補(bǔ)貨。1.3 Docker 和 K8S 的關(guān)系與區(qū)別很多資料會(huì)把 Docker 和 K8S 放在一起講導(dǎo)致新手誤以為它們是替代關(guān)系學(xué)了 K8S 就不需要 Docker。實(shí)際不是這樣。Docker 是一個(gè)容器管理工具負(fù)責(zé)構(gòu)建鏡像、啟動(dòng)容器、管理容器生命周期。K8S 是一個(gè)容器編排平臺(tái)負(fù)責(zé)管理多個(gè)節(jié)點(diǎn)上的容器調(diào)度。K8S 本身不直接啟動(dòng)容器它需要一個(gè)容器運(yùn)行時(shí)來執(zhí)行真正的容器操作。早期 K8S 經(jīng)常用 Docker 作為運(yùn)行時(shí)所以“Docker K8S”成了默認(rèn)組合。但現(xiàn)在 K8S 默認(rèn)使用 containerd 作為運(yùn)行時(shí)這是 Kubernetes 社區(qū)逐步演進(jìn)出來的方向。containerd 更輕量專門為容器運(yùn)行時(shí)設(shè)計(jì)而 Docker 更偏向端到端的開發(fā)者體驗(yàn)。學(xué)習(xí)時(shí)建議從 Docker 入手因?yàn)?Docker 的命令足夠直觀能幫你快速理解鏡像、容器、數(shù)據(jù)卷、端口映射這些基礎(chǔ)概念。進(jìn)入 K8S 后再逐步切換到 containerd、Pod、Service 這些新的表達(dá)方式。記住一點(diǎn)K8S 和 Docker 是不同層級(jí)的東西不是同一類工具的替代而是“編排調(diào)度”和“容器管理”的分工關(guān)系。2. Docker 落地裝好環(huán)境、跑通 MySQL 和 Redis概念清楚后進(jìn)入動(dòng)手環(huán)節(jié)。Docker 的落地路徑比較固定安裝、配置鏡像源、跑容器、管理容器。這里我按不同系統(tǒng)分別說明并給出兩個(gè)常見生產(chǎn)任務(wù)的完整案例。2.1 不同系統(tǒng)的安裝路徑如果你用的是 Windows 或 macOS最簡(jiǎn)單的方案是安裝 Docker Desktop。Docker Desktop 自帶圖形界面適合學(xué)習(xí)階段使用。但它對(duì)系統(tǒng)版本有要求安裝前先確認(rèn)兩點(diǎn)系統(tǒng)版本是否在支持范圍內(nèi)。Windows 上如果提示 incompatible version of windows說明當(dāng)前系統(tǒng)版本太舊要么升級(jí)系統(tǒng)要么換用 Linux 環(huán)境練習(xí)。是否開啟虛擬化。Windows 常見報(bào)錯(cuò)是virtualization support not detectedDocker Desktop 無法啟動(dòng)錯(cuò)誤信息里會(huì)直接提示沒有檢測(cè)到虛擬化支持。這時(shí)去 BIOS/UEFI 里找 Intel VT-x 或 AMD SVM 開關(guān)開啟后重啟。Linux 環(huán)境下安裝 Docker 更直接。Ubuntu 上可以用 apt 安裝docker.io也可以用 Docker 官方倉(cāng)庫(kù)安裝推薦用官方倉(cāng)庫(kù)版本更新更及時(shí)。CentOS 7 想升級(jí)到新版 Docker不能只靠yum update docker一般需要先卸載舊包再配置 Docker 官方或鏡像站倉(cāng)庫(kù)然后裝新版本。這里給的是通用排查順序?qū)嶋H命令要以當(dāng)前系統(tǒng)的官方文檔為準(zhǔn)。安裝完先跑一次驗(yàn)證docker --version docker run hello-worlddocker run hello-world會(huì)拉取一個(gè)很小的測(cè)試鏡像并打印一段成功信息。如果這一步能跑通說明 Docker 守護(hù)進(jìn)程和命令行都能正常工作。如果卡在拉取鏡像說明鏡像下載網(wǎng)絡(luò)有問題先進(jìn)入下一步配置鏡像源。2.2 安裝之后先配鏡像源Docker Hub 是默認(rèn)鏡像倉(cāng)庫(kù)但拉取慢是很多新手遇到的第一個(gè)問題。一個(gè)常見解決辦法是在 Docker 配置里設(shè)置鏡像加速源。在 Linux 下修改/etc/docker/daemon.json{ registry-mirrors: [ https://your-mirror-source.example.com ] }修改后重啟 Dockersudo systemctl restart docker在 Docker Desktop 里設(shè)置項(xiàng)中一般有 registry mirrors 配置填入可用地址后應(yīng)用并重啟。注意事項(xiàng)不同云廠商的鏡像源地址可能變化落地時(shí)以你所用環(huán)境對(duì)應(yīng)的官方文檔為準(zhǔn)不要照抄幾年前文章里的地址。配置鏡像源不保證所有鏡像都能加速個(gè)別鏡像可能仍然很慢或者不穩(wěn)定。如果鏡像拉取失敗先看報(bào)錯(cuò)是超時(shí)、連接拒絕還是 404。超時(shí)優(yōu)先檢查鏡像源連通性404 優(yōu)先確認(rèn)鏡像名和 tag 是否正確。配好之后重新執(zhí)行docker run hello-world能正常輸出版本信息說明鏡像源生效了。2.3 用 Docker 部署 MySQL 8.0MySQL 是運(yùn)維中最高頻的中間件之一。Docker 部署 MySQL 8.0 特別適合本地開發(fā)、測(cè)試環(huán)境快速起實(shí)例。先拉鏡像并運(yùn)行docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDyourpassword \ mysql:8.0參數(shù)含義-d后臺(tái)運(yùn)行。--name mysql8容器名稱方便后續(xù)用 docker 命令管理。-p 3306:3306宿主機(jī) 3306 端口映射到容器 3306 端口。-e MYSQL_ROOT_PASSWORDyourpassword設(shè)置 root 密碼。這是 MySQL 官方鏡像支持的初始化環(huán)境變量。mysql:8.0鏡像名和標(biāo)簽表示 MySQL 8.0 系列。啟動(dòng)后先不要急著連庫(kù)先看狀態(tài)和日志docker ps docker logs mysql8如果docker ps里沒有這個(gè)容器說明容器啟動(dòng)后立刻退出了這時(shí)必須看日志。常見情況是密碼策略、端口被占用、初始化腳本報(bào)錯(cuò)。日志會(huì)給出線索。進(jìn)入容器執(zhí)行命令驗(yàn)證docker exec -it mysql8 mysql -uroot -p輸入上面設(shè)置的密碼能進(jìn)入 MySQL Shell 說明服務(wù)正常。一個(gè)容易踩的坑是數(shù)據(jù)持久化。如果直接用上面的命令啟動(dòng)容器刪除后/var/lib/mysql里的數(shù)據(jù)也會(huì)一起刪除。正確做法是掛載數(shù)據(jù)卷docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDyourpassword \ -v $PWD/mysql-data:/var/lib/mysql \ mysql:8.0這樣數(shù)據(jù)會(huì)落到宿主機(jī)當(dāng)前目錄的mysql-data文件夾里。容器重建后只要掛載到同一個(gè)目錄數(shù)據(jù)就不會(huì)丟。另一個(gè)常見問題是 3306 端口沖突。如果本機(jī)已經(jīng)裝了 MySQL或者別的主機(jī)占用該端口可以換個(gè)端口docker run -d \ --name mysql8 \ -p 3307:3306 \ -e MYSQL_ROOT_PASSWORDyourpassword \ -v $PWD/mysql-data:/var/lib/mysql \ mysql:8.0連接時(shí)就要連127.0.0.1:3307連接工具和代碼里的端口都要跟著改。2.4 用 docker compose 部署 Redis 主從單個(gè) MySQL 用 docker run 還能接受如果要用 Docker 部署一整套 Redis 主從我建議直接上 docker compose。compose 把多個(gè)容器的配置寫進(jìn)一個(gè) YAML 文件一條命令就能啟動(dòng)和停止整套服務(wù)。先創(chuàng)建一個(gè)工作目錄比如redis-cluster里面放一個(gè)docker-compose.ymlservices: redis-master: image: redis:7.0 container_name: redis-master ports: - 6379:6379 command: redis-server --appendonly yes redis-slave: image: redis:7.0 container_name: redis-slave ports: - 6380:6379 command: redis-server --slaveof redis-master 6379 depends_on: - redis-master這個(gè)配置里有兩個(gè)服務(wù)master 和 slave。slave 啟動(dòng)時(shí)通過--slaveof redis-master 6379指定主節(jié)點(diǎn)地址和端口。在 compose 網(wǎng)絡(luò)里服務(wù)名redis-master可以直接作為域名訪問。啟動(dòng)整套服務(wù)docker compose up -d查看運(yùn)行狀態(tài)docker compose ps驗(yàn)證主從關(guān)系docker exec -it redis-master redis-cli info replication看到role:master并且有slave0連接信息說明主節(jié)點(diǎn)正常。再檢查從節(jié)點(diǎn)docker exec -it redis-slave redis-cli info replication看到role:slave并且master_link_status:up說明主從同步正常。這里有一個(gè)版本差異問題老版本 compose 使用獨(dú)立的docker-compose命令新版本 Docker 直接支持docker compose子命令。如果你執(zhí)行docker compose報(bào)錯(cuò)先確認(rèn) Docker 和 Docker Compose 的安裝版本不要強(qiáng)行套命令。數(shù)據(jù)掛載在 Redis 集群里同樣重要??梢栽诿總€(gè)服務(wù)下加volumes配置把/data目錄掛載到宿主機(jī)避免容器重建后數(shù)據(jù)丟失。除此之外Redis 主從只解決讀擴(kuò)展問題不解決自動(dòng)故障切換生產(chǎn)環(huán)境要考慮哨兵或 Redis Cluster這是另一個(gè)話題。3. K8S 入門從集群搭建到 Pod、Service 和啟動(dòng)命令Docker 跑順之后開始進(jìn)入 K8S。K8S 的入門曲線比 Docker 陡因?yàn)樗肓艘慌赂拍睢2灰噲D一次全看懂先掌握最常見的幾個(gè)再通過實(shí)際操作加深理解。3.1 先記住核心概念K8S 里的最小調(diào)度單元不是容器而是 Pod。Pod 是“一組容器的集合”通常一個(gè) Pod 里放一個(gè)主容器也可以放邊車容器。Pod 里的容器共享網(wǎng)絡(luò)命名空間和存儲(chǔ)卷所以它們之間可以通過 localhost 通信。Deployment 負(fù)責(zé)管理 Pod 的副本數(shù)。它告訴你“我要運(yùn)行幾個(gè)副本”實(shí)際創(chuàng)建、更新和刪除 Pod 都是 Deployment 去做。Service 是服務(wù)入口。Pod 的 IP 會(huì)隨著重啟變化直接訪問 Pod IP 不現(xiàn)實(shí)。Service 提供一個(gè)固定虛擬 IP 和域名把流量轉(zhuǎn)發(fā)到后端一組 Pod 上。Namespace 用于隔離資源。團(tuán)隊(duì)多、項(xiàng)目多的時(shí)候用 Namespace 區(qū)分環(huán)境或團(tuán)隊(duì)。不指定時(shí)默認(rèn)在 default 命名空間。控制平面組件里你最先要理解 API Server、etcd 和 kubelet。API Server 是所有請(qǐng)求的入口etcd 保存集群狀態(tài)kubelet 負(fù)責(zé)在節(jié)點(diǎn)上管理 Pod。理解這三個(gè)后面看任何報(bào)錯(cuò)都會(huì)更容易定位。一個(gè)關(guān)鍵思維方式是“聲明式”你聲明的不是一個(gè)動(dòng)作而是一個(gè)期望狀態(tài)。比如你寫清楚“副本數(shù) 3”K8S 會(huì)自己判斷當(dāng)前有幾個(gè)副本不夠就去創(chuàng)建多了就回收。3.2 本地或測(cè)試環(huán)境怎么搭學(xué)習(xí) K8S 有兩類路徑。如果只有一臺(tái)筆記本或者只想體驗(yàn)基礎(chǔ)功能推薦 minikube。minikube 會(huì)在本地創(chuàng)建一個(gè)小型 K8S 集群可以是單節(jié)點(diǎn)常用作學(xué)習(xí)環(huán)境。啟動(dòng)命令一般類似minikube start啟動(dòng)后可以用kubectl get nodes查看節(jié)點(diǎn)狀態(tài)。如果你對(duì)資源要求不高minikube 是成本最低的入門方式。如果想模擬真實(shí)集群建議準(zhǔn)備三臺(tái) Linux 虛擬機(jī)或云主機(jī)一臺(tái) master兩臺(tái) worker。系統(tǒng)建議選擇較新的長(zhǎng)期支持版本。搭建流程大致是關(guān)閉 swap保證 kubelet 能正常工作。加載內(nèi)核模塊調(diào)整網(wǎng)絡(luò)參數(shù)讓容器流量能正常轉(zhuǎn)發(fā)。安裝 kubeadm、kubelet、kubectl 三個(gè)核心組件。master 節(jié)點(diǎn)執(zhí)行kubeadm init初始化集群。初始化完成后按提示配置 kubeconfig并記錄生成的 join token。worker 節(jié)點(diǎn)執(zhí)行kubeadm join加入集群。安裝一個(gè)容器網(wǎng)絡(luò)插件讓不同節(jié)點(diǎn)上的 Pod 能互相通信。這里有一個(gè)容易忽略的點(diǎn)不同網(wǎng)絡(luò)插件對(duì)--pod-network-cidr參數(shù)的要求不同。不要盲目照搬某個(gè)教程里的 CIDR 值一定要看你實(shí)際選擇的網(wǎng)絡(luò)插件文檔。我在實(shí)際測(cè)試中見過很多次初始化失敗不是因?yàn)榧号渲缅e(cuò)而是 CIDR 和網(wǎng)絡(luò)插件對(duì)不上。初始化完成后驗(yàn)證kubectl get nodes能看到 master 和 worker 節(jié)點(diǎn)狀態(tài)為Ready說明集群基礎(chǔ)可用。3.3 用 YAML 描述 Pod 和 ServiceK8S 里最常用的是 YAML 文件。下面是一個(gè)最簡(jiǎn)單的 nginx Pod 示例apiVersion: v1 kind: Pod metadata: name: my-nginx spec: containers: - name: nginx image: nginx:1.25 ports: - containerPort: 80執(zhí)行kubectl apply -f pod-nginx.yaml kubectl get pods kubectl describe pod my-nginxkubectl describe是排查問題的第一入口。它會(huì)把 Pod 的事件、容器狀態(tài)、鏡像拉取情況全部列出來。如果 Pod 一直 Pending先看 describe 輸出里有沒有節(jié)點(diǎn)資源不足、鏡像拉取失敗等提示。直接訪問 Pod IP 不方便所以通常再創(chuàng)建一個(gè) ServiceapiVersion: v1 kind: Service metadata: name: my-nginx-service spec: selector: app: my-nginx ports: - port: 80 targetPort: 80 type: ClusterIP如果你想在本地瀏覽器直接訪問可以把 Service 類型改成NodePort或者用kubectl port-forward做端口轉(zhuǎn)發(fā)。學(xué)習(xí)階段我常用kubectl port-forward不用改 Service 類型也不用關(guān)心集群外的防火墻規(guī)則。kubectl port-forward service/my-nginx-service 8080:80然后訪問http://localhost:8080看到 nginx 默認(rèn)頁面說明 Pod 和 Service 都通了。3.4 entrypoint 和 cmd 在 K8S 中代表什么Dockerfile 里有 ENTRYPOINT 和 CMDK8S 的容器定義里有 command 和 args。很多人會(huì)混淆它們。Dockerfile 中的 CMD 是默認(rèn)啟動(dòng)命令ENTRYPOINT 是固定入口。運(yùn)行時(shí)最終執(zhí)行的命令是 ENTRYPOINT 加上 CMD 作為默認(rèn)參數(shù)。K8S 里可以通過command覆蓋 Dockerfile 的 ENTRYPOINT通過args覆蓋 Dockerfile 的 CMD。它們的關(guān)系是K8S 的command對(duì)應(yīng) Dockerfile 的 ENTRYPOINT。K8S 的args對(duì)應(yīng) Dockerfile 的 CMD。舉個(gè)例子鏡像默認(rèn)通過 ENTRYPOINT 啟動(dòng)某個(gè)腳本你希望在 K8S 里加一個(gè)額外參數(shù)就可以在 Pod 的 YAML 里只寫args不寫command這樣保留鏡像里的 ENTRYPOINT只覆蓋默認(rèn)參數(shù)spec: containers: - name: my-app image: my-app:latest args: [--config-file/etc/my-app/config.yaml]如果你同時(shí)寫了command和args就會(huì)完全覆蓋鏡像里的默認(rèn)設(shè)置。遇到啟動(dòng)命令不生效先看容器的啟動(dòng)命令和日志再確認(rèn)是 command 寫錯(cuò)了還是 args 里的路徑、參數(shù)名不對(duì)。4. 監(jiān)控告警與故障排查進(jìn)入真實(shí)運(yùn)維場(chǎng)景后不能只會(huì)在命令行里跑 pod、看日志。容器集群一旦多起來你更需要一套監(jiān)控體系來發(fā)現(xiàn)資源問題而不是等用戶報(bào)障才知道服務(wù)掛了。4.1 常用命令速查我不建議背命令而是建議按“查狀態(tài)、查日志、查資源”三個(gè)動(dòng)作去記命令。Linux 系統(tǒng)層面查系統(tǒng)運(yùn)行狀態(tài)top、free -h、df -h、du -sh *查服務(wù)和日志systemctl status 服務(wù)名、journalctl -u 服務(wù)名 -f查端口和連接ss -tlnp、netstat -tlnpDocker 層面查容器狀態(tài)docker ps -a查日志docker logs -f 容器名進(jìn)入容器docker exec -it 容器名 bash查資源占用docker stats查鏡像和容器詳情docker inspect 容器名K8S 層面查集群節(jié)點(diǎn)kubectl get nodes查資源對(duì)象kubectl get pods -A查詳細(xì)事件kubectl describe pod 名稱查容器日志kubectl logs -f pod名稱進(jìn)容器調(diào)試kubectl exec -it pod名稱 -- bash查資源用量kubectl top nodes、kubectl top pods實(shí)際排查時(shí)我發(fā)現(xiàn)很多新手會(huì)在命令本身上浪費(fèi)時(shí)間比如糾結(jié)kubectl logs和kubectl describe該用哪個(gè)。原則很簡(jiǎn)單先 describe 看事件再 logs 看應(yīng)用輸出。事件負(fù)責(zé)告訴你“K8S 層面發(fā)生了什么”日志負(fù)責(zé)告訴你“應(yīng)用內(nèi)部發(fā)生了什么”。4.2 監(jiān)控告警體系node-exporter Prometheus Grafana容器化環(huán)境里靠 ssh 到每臺(tái)機(jī)器去看top和df不現(xiàn)實(shí)。標(biāo)準(zhǔn)做法是搭建一套監(jiān)控告警體系常見組合是 node-exporter、Prometheus 和 Grafana。node-exporter 負(fù)責(zé)在每臺(tái)節(jié)點(diǎn)上采集系統(tǒng)指標(biāo)比如 CPU、內(nèi)存、磁盤、網(wǎng)絡(luò)。Prometheus 負(fù)責(zé)定時(shí)抓取這些指標(biāo)并存儲(chǔ)。Grafana 負(fù)責(zé)把指標(biāo)可視化并配置告警規(guī)則。這套體系可以用 docker compose 在單機(jī)跑通也可以部署進(jìn) K8S 集群。學(xué)習(xí)階段我建議先用 docker compose 跑一遍理解“采集、存儲(chǔ)、展示”三個(gè)環(huán)節(jié)再考慮部署到 K8S。一個(gè)最簡(jiǎn)單的鏈路是在目標(biāo)機(jī)器運(yùn)行 node-exporter默認(rèn)監(jiān)聽 9100 端口。Prometheus 配置文件里添加這個(gè) node-exporter 作為 scrape target。打開 Prometheus 的 targets 頁面看到該節(jié)點(diǎn)狀態(tài)為 UP。Grafana 添加 Prometheus 數(shù)據(jù)源導(dǎo)入一個(gè) Node Exporter 的儀表盤。在 Grafana 里配置告警規(guī)則或者通過 Alertmanager 發(fā)送通知。驗(yàn)證鏈路是否正常先看兩個(gè)地方Prometheus 的 targets 是否 UPGrafana 的 Dashboard 是否有數(shù)據(jù)。如果 target 是 DOWN先檢查 node-exporter 進(jìn)程和 9100 端口而不是急著改 Grafana。4.3 磁盤告警規(guī)則怎么寫磁盤告警是最常見的需求因?yàn)殓R像、容器日志、數(shù)據(jù)卷都會(huì)迅速消耗磁盤空間。只靠人工巡檢很被動(dòng)最好配置自動(dòng)告警。在 Prometheus 或 Grafana 里寫告警規(guī)則時(shí)核心是判斷“磁盤剩余空間是否低于閾值”。下面是 Prometheus 告警規(guī)則的常見寫法示例groups: - name: node-disk-alert rules: - alert: DiskUsageHigh expr: (1 - (node_filesystem_avail_bytes{fstype!~tmpfs|overlay} / node_filesystem_size_bytes{fstype!~tmpfs|overlay})) 0.9 for: 10m labels: severity: warning annotations: summary: 磁盤使用率超過 90%這段規(guī)則的作用是篩選出非 tmpfs、非 overlay 的文件系統(tǒng)計(jì)算磁盤使用率是否超過 90%持續(xù) 10 分鐘就觸發(fā)告警。需要提醒的是node-exporter 的指標(biāo)名會(huì)隨版本變化。有些版本里相關(guān)指標(biāo)可能叫node_filesystem_avail_bytes還有可能存在node_filesystem_avail之類的歷史指標(biāo)。寫規(guī)則前先在 Prometheus 的 Graph 頁面用 PromQL 查詢確認(rèn)指標(biāo)名否則規(guī)則可能永遠(yuǎn)不會(huì)觸發(fā)。告警通知渠道取決于你的部署方式。Grafana 支持郵件、釘釘、企業(yè)微信、Webhook 等Alertmanager 也能做更復(fù)雜的路由和收斂。關(guān)鍵是先保證“規(guī)則能觸發(fā)、通知能發(fā)出去”不要一開始就追求復(fù)雜的告警路由。4.4 常見故障排查鏈路K8S 和 Docker 的故障很多但排查思路是固定的先看現(xiàn)象再查輸入再查環(huán)境最后查參數(shù)。Docker Desktop 虛擬化報(bào)錯(cuò)。如果啟動(dòng)時(shí)提示virtualization support not detected優(yōu)先檢查 BIOS/UEFI 里的 CPU 虛擬化開關(guān)再檢查 Windows 虛擬機(jī)平臺(tái)功能是否開啟。報(bào)錯(cuò)信息本身一般已經(jīng)給了修復(fù)方向。容器啟動(dòng)后立刻退出。先docker logs看日志再docker ps -a看退出狀態(tài)。常見原因是端口被占、數(shù)據(jù)目錄權(quán)限不足、啟動(dòng)命令依賴的配置不存在。不要反復(fù)重啟容器先看退出前的日志。K8S Pod 一直 Pending。用kubectl describe pod看事件常見原因是節(jié)點(diǎn) CPU 或內(nèi)存不足或者節(jié)點(diǎn)有 taint 導(dǎo)致沒有可用節(jié)點(diǎn)。先解決資源問題或調(diào)整調(diào)度配置。K8S Pod 進(jìn)入 CrashLoopBackOff。說明容器啟動(dòng)后又崩潰了看kubectl logs是最直接的排查方式。常見原因是啟動(dòng)命令參數(shù)錯(cuò)誤、依賴服務(wù)沒就緒、環(huán)境變量缺失。K8S CPU throttling。這是一個(gè)比較隱蔽的問題。表現(xiàn)是 Pod 的 CPU 使用率看起來不高但接口響應(yīng)很慢日志里有大量延遲提升。原因是 Pod 設(shè)置了 CPU limit但業(yè)務(wù)在實(shí)際運(yùn)行時(shí)超過了 limit導(dǎo)致 CPU 被限流。排查時(shí)可以查看 Prometheus 里container_cpu_cfs_throttled_periods_total相關(guān)指標(biāo)判斷是否存在大量 throttled 周期。解決思路不是簡(jiǎn)單地取消 limit而是根據(jù)業(yè)務(wù)真實(shí)負(fù)載合理設(shè)置 requests 和 limits并在容量規(guī)劃時(shí)留出緩沖。權(quán)限問題。比如想給團(tuán)隊(duì)成員只讀權(quán)限查看 K8S 資源很多人會(huì)直接把管理員 kubeconfig 發(fā)出去這是非常危險(xiǎn)的。正確做法是創(chuàng)建一個(gè)只讀用戶或 ServiceAccount綁定只包含get、list、watch權(quán)限的 RBAC 角色。最小化權(quán)限是運(yùn)維的基本功。5. 學(xué)習(xí)落地清單和邊界最后這部分給新手一條可以照著走的路徑也把最容易踩的坑集中說一遍。5.1 建議的學(xué)習(xí)順序我的建議是分四個(gè)階段走不要跳級(jí)。第一階段Linux 基礎(chǔ)。至少會(huì)用cd、ls、top、free、df、journalctl、systemctl能看懂系統(tǒng)報(bào)錯(cuò)。沒有這個(gè)基礎(chǔ)Docker 和 K8S 的很多問題會(huì)卡在系統(tǒng)層面。第二階段Docker 單機(jī)。從安裝、拉鏡像、跑容器開始理解鏡像、容器、數(shù)據(jù)卷、端口映射。重點(diǎn)練習(xí)docker run、docker exec、docker logs、docker inspect。第三階段docker compose 和多服務(wù)編排。把 MySQL、Redis、Nginx 等常見組件用 docker compose 編排起來理解容器之間的網(wǎng)絡(luò)通信和數(shù)據(jù)持久化。第四階段K8S。先掌握 Pod、Deployment、Service、Namespace再往上加監(jiān)控、日志、持久化存儲(chǔ)。不要一開始就去研究 Operator、service mesh 這些進(jìn)階內(nèi)容。5.2 典型踩坑記錄鏡像下載慢配置鏡像源確認(rèn)網(wǎng)絡(luò)連通性不要反復(fù)重試同一個(gè)失敗任務(wù)。容器數(shù)據(jù)丟失沒有掛載數(shù)據(jù)卷。無論 MySQL、Redis 還是業(yè)務(wù)應(yīng)用只要需要持久化都要先規(guī)劃數(shù)據(jù)目錄。端口沖突啟動(dòng)前先看端口占用不要等bind failed才去改端口。版本不匹配Docker Compose 新老命令差異、MySQL 8.0 初始化參數(shù)變化、K8S 鏡像版本過多都會(huì)導(dǎo)致照搬教程失敗。遇到版本報(bào)錯(cuò)第一反應(yīng)是核對(duì)版本。權(quán)限問題K8S 不要隨便發(fā) admin kubeconfig云主機(jī)不要隨意放行所有端口。權(quán)限最小化操作留日志。資源耗盡容器不設(shè)置 requests/limitsK8S 集群容易被某個(gè)異常服務(wù)拖垮。學(xué)習(xí)階段可以不調(diào)但生產(chǎn)環(huán)境一定要設(shè)置。5.3 學(xué)習(xí)環(huán)境和生產(chǎn)環(huán)境的邊界學(xué)習(xí)環(huán)境可以用單節(jié)點(diǎn)、可以不開資源限制、可以隨便刪除重建。生產(chǎn)環(huán)境要考慮的東西更多etcd 備份、Master 高可用、網(wǎng)絡(luò)插件選型、Ingress 規(guī)劃、數(shù)據(jù)持久化、日志采集、監(jiān)控告警、權(quán)限審計(jì)、鏡像倉(cāng)庫(kù)安全。低配置機(jī)器能跑 K8S不代表它能扛住生產(chǎn)流量。學(xué)習(xí)時(shí)用 minikube 或單節(jié)點(diǎn)集群沒問題放到生產(chǎn)環(huán)境要按實(shí)際負(fù)載和可用性要求設(shè)計(jì)。默認(rèn)配置適合入門不適合生產(chǎn)。很多教程里的“一鍵部署”只是為了教學(xué)生產(chǎn)環(huán)境必須有明確的參數(shù)、容量、監(jiān)控和回滾方案。如果只是學(xué)習(xí)默認(rèn)配置夠用。如果要長(zhǎng)期維護(hù)就要把日志、輸出目錄、任務(wù)隊(duì)列、監(jiān)控規(guī)則提前整理好。不是等出事之后才補(bǔ)而是第一天就把基礎(chǔ)打牢。踩過幾次之后我發(fā)現(xiàn)很多問題不是工具能力不夠而是前置環(huán)境和輸入材料沒有處理干凈。先把 Docker 單機(jī)跑順再進(jìn)入 K8S 編排先把監(jiān)控鏈路搭通再談告警閾值先學(xué)會(huì)看日志和事件再去找參數(shù)和配置。這套順序看起來慢但實(shí)際落地時(shí)能省下大量返工時(shí)間。