
Docker 和 K8s 的關系每隔一段時間就會有人拿出來問一次既然 Docker 已經把應用打包成鏡像一條命令就能啟動為什么還要搞出 Kubernetes 這么重的東西我先給出一個直接判斷Docker 解決的是“單臺機器上如何把應用跑起來”的問題K8s 解決的是“很多臺機器上如何保證這些應用不掛、可調度、能擴容、好管理”的問題。短期單機開發(fā)Docker 足夠生產環(huán)境、多實例、微服務、流量波動、節(jié)點故障只有 Docker 往往會失控。這篇就圍繞“為什么還要 K8s”拆開講包括兩者到底差在哪、K8s 多做了什么、什么時候才需要上、以及從 Docker 平滑過渡到 K8s 的實際路徑。很多人學容器技術時最先接觸的都是 Docker鏡像、容器、端口映射、數(shù)據(jù)卷、docker-compose。這套東西確實好用開發(fā)環(huán)境一條命令拉起來打包鏡像發(fā)給別人也能復現(xiàn)。但一旦應用規(guī)模變大比如你手上有 10 個服務部署在 3 臺機器上問題很快就來了流量高了想把某個服務多開幾個誰來調度某個節(jié)點宕機了上面的容器怎么遷移新加一臺機器怎么讓服務自動用上新資源這些都不是 Docker 本身能直接回答的。K8s 就是在這個層面把事情接過去的。下面按實際理解路徑拆開講先解決兩者關系再看 K8s 做了什么然后討論什么場景必須上 K8s最后聊怎么從 Docker 平滑過渡。1. 先用一句話理清 Docker 和 K8s 的分工1.1 Docker 是單機容器引擎K8s 是集群編排系統(tǒng)Docker 的核心能力圍繞“單個容器”展開拉鏡像、建容器、啟停、刪除、端口映射、數(shù)據(jù)卷掛載。你可以在一個節(jié)點上同時跑多個容器但所有容器都共享這臺機器的 CPU、內存、磁盤和網絡沒有跨節(jié)點的調度概念。K8s 的核心能力圍繞“一批容器”展開它管理的是一個集群由多個 Node節(jié)點組成Kubernetes 決定每個 Pod 放在哪個節(jié)點、資源夠不夠、要不要重啟、要不要擴容。K8s 不直接操作容器而是通過容器運行時常見的就是 containerd以前很多環(huán)境用 Docker來拉起容器。換句話說Docker 是 K8s 集群中單個節(jié)點上可能用到的容器運行層K8s 是更高一層的控制系統(tǒng)。這個關系經常被誤解成“K8s 是 Docker 的升級版”不準確。更貼切的比喻是Docker 像你手里的集裝箱單個箱子怎么裝、怎么搬它管得不錯K8s 像整個港口的調度系統(tǒng)哪個箱子放哪個泊位、哪艘船先裝卸、什么時候調幾臺吊車過來Docker 管不了。1.2 為什么“有了 Docker”還會覺得不夠單機場景下Docker docker-compose 已經能解決很多問題比如 LNMP 環(huán)境一鍵拉起、MySQL 和 Redis 主從測試、開發(fā)環(huán)境隔離。但生產環(huán)境面對的問題不一樣故障恢復一個容器進程掛了Docker 單機重啟策略有限節(jié)點宕機之后容器不會自動跑到另一臺機器上。流量調度業(yè)務漲了需要從 1 個實例擴到 10 個實例Docker 沒有自動伸縮、負載均衡和統(tǒng)一入口。服務發(fā)現(xiàn)A 服務要調用 B 服務B 有多份實例Docker 默認不會自動維護一個可用的服務地址列表。升級發(fā)布滾動更新、回滾、金絲雀發(fā)布Docker 本身沒有這套流程。配置和密鑰管理多套環(huán)境、多個配置項Docker 不是不能做但集群規(guī)模一大就非常零散。這些痛點疊加起來才是“為什么還要 K8s”的真正答案。2. K8s 到底多做了什么單機 Docker 做不到的事2.1 調度把 Pod 放到合適的節(jié)點上K8s 里最小的調度單位不是容器而是 Pod。一個 Pod 可以包含一個或多個容器這些容器共享網絡和存儲。調度器會綜合考慮每個節(jié)點的資源、標簽、污點和親和性決定 Pod 最終落到哪臺機器。這個能力在單機 Docker 里完全不存在。你在 Docker 里跑一個容器它就在當前這臺機器上要跑在別的機器你得手動登錄那臺機器再 docker run。K8s 則是你告訴它“我要 3 個副本每個副本需要 1 核 2G”調度器自己去選節(jié)點。機器有多臺、資源不均衡、部分節(jié)點有特殊硬件時這個差異會非常明顯。2.2 自愈不用半夜爬起來重啟服務K8s 的 Deployment 和 ReplicaSet 會持續(xù)對比“期望副本數(shù)”和“實際副本數(shù)”。某個 Pod 掛了控制器立刻創(chuàng)建新 Pod 頂上節(jié)點宕機默認情況下過一段時間后會將該節(jié)點上的 Pod 在其他節(jié)點重建容器存活但業(yè)務異常ReadinessProbe 和 LivenessProbe 會配合探針做更精細的處理。Docker 單機也有 restart 策略比如 always、on-failure但那只是解決“這臺機器上容器退出了要不要拉起來”的問題。節(jié)點斷電、磁盤故障、整機網絡隔離Docker 的 restart 無能為力。K8s 的自愈能力是集群級別的。2.3 服務發(fā)現(xiàn)與統(tǒng)一入口集群內服務之間的調用K8s 通過 Service、DNS 和 Endpoints 來做。每個 Service 有固定的虛擬 IP 和 DNS 名稱Pod 變化、IP 變化都不會影響服務間的調用關系。對外流量再多加一層 Ingress比如 Nginx Ingress Controller 或 Traefik按域名和路徑路由到不同 Service。Docker 場景下服務間調用通常靠手動維護 IP 或者自定義配置docker-compose 里用服務名也能互相訪問但那只局限于一個 compose 項目內部。跨機、跨網絡、跨環(huán)境Docker 的方式會變得很辛苦而 K8s 把“服務發(fā)現(xiàn)”做成了平臺能力。2.4 彈性伸縮從 1 個副本到 20 個副本K8s 的 HPAHorizontalPodAutoscaler可以根據(jù) CPU、內存或自定義指標自動調整副本數(shù)。這個能力在流量波動明顯的業(yè)務里非常實用。Docker 要擴容就必須手動執(zhí)行 docker run或者自己寫腳本、接 CI/CD 和外部調度平臺本質還是沒有內生的“按指標自動擴容”機制。需要注意的是HPA 不是銀彈。指標采集和延遲、應用啟動時間、Pod 快速擴容時的資源競爭都會影響實際效果。但 K8s 至少把這道自動化能力直接開放出來了。2.5 聲明式管理把系統(tǒng)狀態(tài)變成數(shù)據(jù)這是 K8s 和 Docker 使用模式上最本質的區(qū)別。Docker 是命令式的你執(zhí)行 docker run、docker stop、docker rm每一步都是你主動操作。K8s 是聲明式的你編寫 YAML聲明“我要什么狀態(tài)”剩下的由控制器不斷調解讓集群狀態(tài)逼近你的聲明。這個差異帶來的好處是配置可以版本化變更可以走 Git 工作流出問題可以快速回滾到上一版 YAML。團隊協(xié)作時K8s 的對象描述比一堆 shell 歷史記錄可靠得多。3. 什么時候才真正需要 K8s什么時候沒必要3.1 沒必要上 K8s 的典型場景不是所有項目都要上 K8s。以下場景用 Docker docker-compose 反而更輕個人學習和小型實驗單機跑一個 LNMP 環(huán)境、裝 MySQL、Redis 做測試docker-compose 足夠。公司內部一次性工具比如臨時起一個數(shù)據(jù)庫、跑一次數(shù)據(jù)遷移任務不需要長期穩(wěn)定集群。節(jié)點數(shù)量很少、沒有橫向擴容需求兩三臺機器服務總量固定手動維護成本可以接受。團隊沒有容器編排經驗強行上 K8s控制面組件、網絡插件、存儲插件、升級流程每一個都可能成為新的故障源。在這些場景里K8s 帶來的復雜度遠大于收益。這也是我一直強調“低配置能跑不代表適合能跑通也不代表當前就該上”的原因。3.2 值得上 K8s 的典型信號以下情況碰到兩三條就可以認真評估 K8s服務數(shù)量超過 10 個手動維護部署腳本越來越亂。需要多副本部署某幾個核心服務且副本數(shù)經常變化。節(jié)點數(shù)量超過 3 臺需要統(tǒng)一管理資源。發(fā)布頻率高需要滾動更新、回滾和金絲雀發(fā)布。業(yè)務對故障恢復要求高不能接受節(jié)點宕機后長時間不可用。需要按環(huán)境隔離配置、密鑰又不希望散落在各個服務器上。多個服務間調用頻繁需要穩(wěn)定的服務發(fā)現(xiàn)和 DNS 機制。有一個常見誤區(qū)認為“上了 K8s 就一定比 Docker 穩(wěn)定”。其實 K8s 只是把很多原來運維手工做的事情自動化了但 K8s 本身也有升級、網絡、存儲、證書過期等問題。如果你的應用架構和團隊能力沒有準備好K8s 會把原本顯性的單機故障變成隱性的集群調度故障。4. 從 Docker 到 K8s 的平滑過渡路線4.1 先做好容器化再談編排不管最終是否上 K8s第一步都是把應用正確容器化。Docker 階段要關注的不是“鏡像能不能 build 出來”而是鏡像是否足夠小基礎鏡像是否包含大量無關依賴。容器是否有非 root 用戶運行是否適合安全掃描。日志是否輸出到 stdout而不是寫在容器內某個文件。配置文件是否通過環(huán)境變量或掛載注入而不是打進鏡像。有狀態(tài)數(shù)據(jù)是否落在命名卷或外部存儲而不是寫在容器可寫層。容器化不規(guī)范后面上 K8s 會把這些問題放大幾十倍。比如日志不輸出到 stdoutK8s 里你就看不到有效排障信息有狀態(tài)數(shù)據(jù)寫在容器可寫層Pod 一重建數(shù)據(jù)就丟了。4.2 用 docker-compose 模擬多服務部署在單機上先跑通多服務的編排是很好的過渡練習。把應用拆成 web、api、db、cache 等幾個服務用 docker-compose 管理網絡、依賴順序和數(shù)據(jù)卷。這個階段你會自然理解“服務之間如何通過服務名通信”“外部如何訪問內部服務”“數(shù)據(jù)應該如何持久化”。等這些概念都清楚了再遷移到 K8s很多 YAML 里的字段就不會顯得那么抽象。比如 compose 里的 service 對應 K8s 里的 Servicecompose 里的 restart 對應 K8s 里的 restartPolicy 和控制器自動重啟邏輯compose 里的 volumes 對應 K8s 里的 PersistentVolumeClaim。4.3 從最小的 K8s 集群開始不要一上來就生產學習階段推薦先用輕量方案搭一個單節(jié)點或三節(jié)點集群。常見的選擇包括 k3s、minikube、kind、kubeadm。沒有哪個是絕對最好的取決于你想學什么minikube適合在本地電腦快速體驗 K8s 的基礎對象啟動快但和真實多節(jié)點集群有差距。kind適合用容器模擬節(jié)點做 CI、測試、本地實驗很方便。k3s占用資源少適合低配機器或邊緣場景也能跑正式工作負載。kubeadm更接近生產環(huán)境安裝方式適合想了解 K8s 組件交互的讀者。我建議先在 minikube 或 kind 上把 Deployment、Service、Ingress、ConfigMap、Secret 這些對象跑一遍再考慮用 kubeadm 搭多節(jié)點集群。不要一上來就去網上找一條命令安裝生產集群的腳本裝完之后你不知道里面發(fā)生了什么出了問題很難排查。4.4 把 LNMP 這類經典架構從 Docker 搬到 K8s網絡上常見的 LNMP 實驗即 Nginx PHP MySQL 的部署方式是一個很好的 K8s 練習項目。Docker 里你會寫一個 compose 文件定義 nginx、php-fpm、mysql 三個服務。K8s 里則需要拆成這套對象Deployment 或 StatefulSetMySQL 有狀態(tài)數(shù)據(jù)適合 StatefulSet至少需要 PersistentVolumeClaim。DeploymentNginx 和 PHP-FPM 分別作為無狀態(tài)服務Nginx 通過 FastCGI 轉發(fā)給 PHP-FPM。Service每個服務暴露一個穩(wěn)定 DNS 地址。ConfigMapNginx 配置和 PHP 配置通過 ConfigMap 掛載進容器。SecretMySQL 密碼通過 Secret 注入。這個實驗做完你基本就理解了 K8s 的配置、存儲、網絡和服務發(fā)現(xiàn)核心概念也會發(fā)現(xiàn) K8s 里做 LNMP 比 Docker compose 多好幾倍的文件這正是“編排能力換復雜度”的實際感受。4.5 漸進式遷移不要重寫一切如果已經有服務在 Docker 里跑得好好的完全沒必要一次性把所有服務都遷到 K8s。建議按優(yōu)先級逐步遷移優(yōu)先遷移無狀態(tài)服務比如 Web API、前端靜態(tài)資源、任務處理 Worker。數(shù)據(jù)庫、Redis、消息隊列這類有狀態(tài)組件先評估是否有成熟的 Operator 或外部托管方案。保持一段時間混合模式部分服務在 K8s部分服務仍在原 Docker 環(huán)境通過網絡打通或統(tǒng)一入口轉發(fā)。把遷移過程中遇到的配置、存儲、日志、監(jiān)控問題記錄下來形成自己的檢查清單。遷移過程中最容易被忽略的是日志和監(jiān)控。Docker 里你可以在節(jié)點上 docker logsK8s 換節(jié)點、滾動更新后日志會散落在多個節(jié)點沒有集中收集很難排查。建議在上 K8s 前先搭建日志收集方案比如 Loki、Elasticsearch 或云廠商日志服務再把應用日志輸出規(guī)范同步處理。5. K8s 學習中最容易踩的坑和排查思路5.1 網絡問題大多和 CNI 插件有關K8s 集群中 Pod 之間、Pod 與 Service 之間通信依賴 CNI 網絡插件常見的有 Calico、Flannel、Cilium、Weave。新手經常遇到“Pod 起來了但互相 ping 不通”或“Service 地址訪問超時”大多數(shù)不是應用問題而是網絡插件沒有調好。排查順序建議先看kubectl get pods -n kube-system確認網絡插件 Pod 都是 Running??垂?jié)點內核模塊是否開啟比如 Calico 依賴的 ipip、veth、nf_conntrack 等。檢查防火墻或安全組是否放行節(jié)點間通信端口。再看網絡策略是否誤攔截。不要一遇到 Pod 之間連不通就懷疑應用代碼先確認集群網絡數(shù)據(jù)面是正常的。5.2 資源不足導致的連環(huán)故障K8s 集群最隱蔽的問題之一是對每個容器不設置 requests 和 limits。完全不設置Pod 可能把節(jié)點內存打爆觸發(fā) OOM Killer系統(tǒng) Pod 也可能被擠出最后整個控制面都不穩(wěn)定。設置得太緊又會導致 Pod 不斷重啟、調度失敗。我的建議是每個工作負載至少設置 requestslimits 可以按業(yè)務需求決定但不要長期不設置。requests 決定了調度器怎么判斷節(jié)點是否合適limits 決定了容器是否會被 cgroup 限制。發(fā)布到生產前先用壓測或歷史監(jiān)控數(shù)據(jù)確定合理區(qū)間。5.3 Pod 一直 CrashLoopBackOff先看日志再改代碼CrashLoopBackOff 是新手最容易慌的報錯。遇到時不要急著改代碼先按順序確認kubectl describe pod pod-name看事件確認是鏡像拉取失敗、還是探針失敗、還是容器退出。kubectl logs pod-name看應用日志確認啟動時缺了哪個配置或依賴。確認 ConfigMap 和 Secret 是否掛載正確環(huán)境變量是否注入。確認資源限制是否太小導致容器剛啟動就被 OOM Kill。大多數(shù) CrashLoopBackOff 是配置和環(huán)境問題真正的代碼問題反而好定位。5.4 服務升級后不回滾依賴版本混亂團隊剛上 K8s 時常見的壞習慣是直接改 YAML 或者用kubectl edit在線改對象。這樣改完雖然能生效但配置沒有入庫下次重裝集群、新成員接手都不知道當前版本長什么樣。更穩(wěn)妥的做法是所有 YAML 都放進 Git 倉庫用 Git 記錄每次變更能用 Helm Chart 就用 Helm把版本號、鏡像 Tag、副本數(shù)這些變量抽出來發(fā)布走 CI/CD 流程而不是手動執(zhí)行 kubectl apply。5.5 別把“能啟動”當成“可以上生產”K8s 里把服務跑起來不難難的是跑起來之后還能長期穩(wěn)定。生產環(huán)境至少要額外考慮監(jiān)控指標CPU、內存、帶寬、Pod 重啟次數(shù)、錯誤率。告警規(guī)則核心服務不可用、Pod 長時間重啟、磁盤使用率過高。備份策略數(shù)據(jù)庫定時備份、對象存儲冗余、跨區(qū)域容災。升級演練控制面組件升級、節(jié)點替換、網絡插件升級。安全基線鏡像掃描、密鑰掃描、RBAC 權限最小化。這些都不是 K8s 安裝完成后自動有的需要團隊規(guī)劃和持續(xù)迭代。6. 給不同學習階段讀者的實操建議6.1 剛學完 Docker準備了解 K8s可以先在自己的電腦上用 Docker Desktop 或 minikube 起一個單節(jié)點集群然后跑這個練習清單創(chuàng)建 Deployment副本數(shù)為 3觀察 Pod 分布和滾動更新。創(chuàng)建 Service用 ClusterIP 方式在集群內訪問再用 NodePort 從宿主機訪問。創(chuàng)建 ConfigMap 和 Secret掛載到 Pod修改配置后滾動更新。創(chuàng)建 Ingress給兩個不同服務設置兩個不同路徑。手動刪除一個 Pod觀察 ReplicaSet 是否自動創(chuàng)建新 Pod。每個練習都用kubectl get和kubectl describe查看狀態(tài)變化。6.2 有一定 K8s 基礎想進一步了解生產落地這時候重點要關注的是網絡插件的工作原理Calico 的 BGP 模式和 IPIP 模式有什么區(qū)別。存儲方案本地存儲、NFS、CSI 插件的區(qū)別和適用場景。有狀態(tài)應用如何用 StatefulSet 和 Operator 管理。多集群、多環(huán)境的管理方式比如 Kustomize 和 Helm 怎么選。故障演練主動模擬節(jié)點宕機、Pod 驅逐、網絡分區(qū)看看系統(tǒng)是否真的自愈。6.3 準備面試可以關注這些高頻考點網上關于 K8s 的面試題很多核心考點通常集中在為什么有 Docker 還需要 K8s兩者的分工和邊界。K8s 控制面組件有哪些每個組件負責什么。Pod、Deployment、Service 的關系和區(qū)別。如何保證服務滾動更新不中斷。節(jié)點資源不足時會發(fā)生什么驅逐策略是什么。如何排查 Pod 一直 Pending、ImagePullBackOff、CrashLoopBackOff。這些題看起來很散但背后都指向同一個能力你能否在故障發(fā)生時從現(xiàn)象倒推原因而不是只會背概念。7. 最后幾條真心話Docker 和 K8s 不是二選一的對立關系而是容器技術棧里的上下游配合。K8s 離不開容器運行時但容器運行時不等于編排平臺。生產環(huán)境里K8s 也不一定是你唯一的選擇Docker Swarm、HashiCorp Nomad、云廠商的 Serverless 容器服務都可能在某些場景更合適。但就目前的主流趨勢、社區(qū)生態(tài)、資料完整度、人才儲備來看K8s 依然是容器編排方向最值得投入的學習對象。學習節(jié)奏上我更建議先把 Docker 的單機能力和 Compose 多服務編排練熟再進 K8s。不要跳步也不要反向“鄙視”Docker。很多 K8s 里的疑難問題追根溯源還是容器鏡像不規(guī)范、依賴版本不明確、環(huán)境配置沒收斂。最重要的一點K8s 的能力不是裝好就自然擁有的也不是把 YAML 復制到生產環(huán)境就萬事大吉。它把原本手工運維的流程平臺化同時也把“責任”集中到了控制面上。你會發(fā)現(xiàn)很多服務沒有上 K8s 時問題出在某臺機器上了 K8s 之后問題變成“為什么會選中這個節(jié)點”“為什么這個 Pod 被驅逐”“為什么升級后流量有抖動”排查鏈路更長、更抽象了。所以面對“有了 Docker為什么還要 K8s”這個問題我會這樣回答如果你只有一臺機器、幾個服務、流量穩(wěn)定Docker 就夠如果你想解決多機器調度、故障自愈、自動擴縮容、統(tǒng)一發(fā)布流程K8s 是當前最通用的一套答案。但答案本身不會替你消除復雜度它只是讓復雜度從“人肉處理”轉成“平臺處理”前提是你得先學會跟平臺對話。