一、為什麼要遷移到 K8s?Docker Compose 的 3 個不可逾越瓶頸
1. Docker Compose vs K8s:核心能力對比(遷移的本質原因)
|
能力維度 |
Docker Compose(單機) |
K8s(分佈式) |
業務影響 |
|
部署範圍 |
僅支持單台主機 |
支持多節點集羣(幾十到幾千台) |
單機無法承載高併發,需多節點擴容 |
|
服務可用性 |
容器掛了需手動重啓 |
自動重啓故障 Pod(自愈能力) |
生產環境需 7×24 小時無間斷服務 |
|
擴縮容能力 |
需手動修改配置重啓服務 |
一鍵擴容(kubectl scale)+ 自動擴縮容 |
秒殺場景需快速擴容,流量降後自動縮容 |
|
網絡管理 |
依賴主機端口映射,衝突風險高 |
內置 Service 網絡(Pod 間通信用域名) |
多服務通信無需暴露主機端口,更安全 |
|
資源調度 |
所有容器共享主機資源,無隔離 |
按服務需求分配 CPU / 內存,支持資源限制 |
避免單服務佔用過多資源導致整體卡頓 |
2. 典型遷移場景(你該何時動手?)
- 場景 1:Docker Compose 單機運行 5 + 服務,CPU 使用率長期超 80%,無法再新增服務;
- 場景 2:業務高峯期(如大促)需臨時擴容訂單服務,手動啓動容器來不及;
- 場景 3:生產環境要求服務 “零停機更新”,Docker Compose 重啓服務會中斷業務。
二、K8s 核心概念入門:用 Docker Compose 知識映射(降低理解成本)
對習慣 Docker Compose 的開發者,K8s 概念無需從零學起 —— 核心是 “將 Compose 的服務配置拆分為更精細的 K8s 資源”,對應關係如下:
|
Docker Compose 概念 |
K8s 對應資源 |
核心作用 |
|
容器(Container) |
Pod |
K8s 最小部署單元,一個 Pod 可包含 1 個或多個容器(如業務容器 + 日誌收集容器) |
|
服務配置(Service) |
Deployment |
定義 Pod 的 “部署規則”,如鏡像版本、副本數、重啓策略(對應 Compose 的 service 塊) |
|
端口映射(ports) |
Service(ClusterIP) |
暴露 Pod 網絡,實現 Pod 間通信(對應 Compose 的ports,但不依賴主機端口) |
|
外部訪問(ports) |
Service(NodePort) |
暴露服務到集羣外部,供外部請求訪問(類似 Compose 的-p 8080:8080) |
|
數據卷(volumes) |
PersistentVolume(PV) |
持久化存儲數據,解決 Pod 刪除後數據丟失問題(對應 Compose 的volumes) |
關鍵認知:K8s 的 “自愈” 與 “擴縮容” 依賴這兩個核心機制
- 自愈:Deployment 配置restartPolicy: Always,當 Pod 因內存溢出、網絡故障崩潰時,K8s 會自動銷燬故障 Pod 並啓動新 Pod;
- 擴縮容:Deployment 通過replicas: 3定義 Pod 副本數,執行kubectl scale deployment user-service --replicas=5可快速擴容到 5 個副本,流量會自動負載均衡到所有副本。
三、實戰 1:搭建 K8s 本地環境(用 Minikube,適合新手)
K8s 集羣部署複雜,本地測試推薦用Minikube(單節點 K8s 集羣,一鍵啓動,無需多台主機)。
1. 環境準備(需滿足以下條件)
- 操作系統:Windows 10+(需開啓 WSL2)、macOS(需安裝 HyperKit)、Linux;
- 資源:至少 2 核 CPU、4GB 內存(Minikube 默認要求);
- 工具:已安裝 Docker(Minikube 可複用 Docker 環境)。
2. 安裝 Minikube 與 kubectl(K8s 命令行工具)
(1)安裝 kubectl(操作 K8s 集羣的核心工具)
# Linux/macOS(Windows用WSL2執行)curl -LO "https://dl.k8s.io/release/v1.28.3/bin/linux/amd64/kubectl"chmod +x ./kubectlsudo mv ./kubectl /usr/local/bin/kubectl# 驗證:kubectl version --client 輸出版本即成功
(2)安裝 Minikube 並啓動 K8s 集羣
# 安裝Minikube(Linux/macOS)curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64sudo install minikube-linux-amd64 /usr/local/bin/minikube# 啓動K8s集羣(指定用Docker驅動,複用本地Docker環境)minikube start --driver=docker --cpus=2 --memory=4g# 參數説明:--cpus=2(分配2核CPU),--memory=4g(分配4GB內存)# 驗證集羣狀態:minikube status 顯示「host: Running」「kubelet: Running」即成功
(3)查看 K8s 集羣信息
# 查看集羣節點(Minikube單節點,名為minikube)kubectl get nodes# 輸出示例:# NAME STATUS ROLES AGE VERSION# minikube Ready control-plane 5m v1.28.3# 查看集羣命名空間(默認所有資源在default命名空間)kubectl get namespaces
四、實戰 2:微服務遷移核心步驟(以用户服務為例)
遷移邏輯:將 Docker Compose 的 user-service 配置,拆分為 K8s 的「Deployment(部署 Pod)」和「Service(暴露網絡)」,步驟如下:
1. 步驟 1:準備遷移前提(確保鏡像可訪問)
K8s 需能拉取用户服務鏡像(user-service:v1.0.1),本地鏡像需先推到鏡像倉庫(或用 Minikube 加載本地鏡像,避免拉取失敗):
# 方法1:Minikube加載本地鏡像(無需推到遠程倉庫,適合本地測試)minikube image load user-service:v1.0.1# 驗證:minikube image ls | grep user-service 能看到鏡像即成功
2. 步驟 2:編寫 K8s Deployment 配置(對應 Compose 的 service 塊)
創建user-service-deployment.yaml,定義 Pod 的部署規則(鏡像、環境變量、資源限制等):
apiVersion: apps/v1 # K8s API版本(Deployment屬於apps組)kind: Deployment # 資源類型:Deployment(管理Pod的部署與自愈)metadata: name: user-service # Deployment名稱(唯一標識) labels: app: user-service # 標籤(用於和Service關聯)spec: replicas: 2 # Pod副本數(初始2個,支持後續擴縮容) selector: matchLabels: app: user-service # 選擇匹配標籤的Pod進行管理 template: metadata: labels: app: user-service # Pod的標籤(需和selector.matchLabels一致) spec: containers: # 容器配置(一個Pod可多個容器,這裏僅業務容器) - name: user-service # 容器名稱 image: user-service:v1.0.1 # 鏡像(Minikube已加載的本地鏡像) imagePullPolicy: Never # 鏡像拉取策略:Never(僅用本地鏡像,不遠程拉取) ports: - containerPort: 8081 # 容器內部端口(和服務端口一致) env: # 環境變量(對應Compose的environment) - name: SPRING_CLOUD_NACOS_DISCOVERY_SERVER_ADDR value: "nacos-service:8848" # Nacos的Service名稱(後續部署Nacos後可用) - name: SPRING_DATASOURCE_URL value: "jdbc:mysql://tidb-service:4000/test_db?useSSL=false&serverTimezone=Asia/Shanghai" - name: SPRING_DATASOURCE_USERNAME value: "root" - name: SPRING_DATASOURCE_PASSWORD value: "" resources: # 資源限制(避免單Pod佔用過多資源) limits: # 最大資源 cpu: "1" # 最多1核CPU memory: "512Mi" # 最多512MB內存 requests: # 最小資源(K8s調度時確保分配) cpu: "0.5" memory: "256Mi" livenessProbe: # 存活探針(檢測Pod是否存活,失敗則重啓) httpGet: path: /actuator/health # 健康檢查端點 port: 8081 initialDelaySeconds: 30 # 啓動30秒後開始探測 periodSeconds: 10 # 每10秒探測一次 readinessProbe: # 就緒探針(檢測Pod是否就緒,未就緒則不分配流量) httpGet: path: /actuator/health port: 8081 initialDelaySeconds: 20 periodSeconds: 5
3. 步驟 3:編寫 K8s Service 配置(對應 Compose 的 ports+Nginx 轉發)
創建user-service-service.yaml,暴露 Pod 網絡,實現 Pod 間通信與外部訪問:
apiVersion: v1 # Service屬於v1組kind: Service # 資源類型:Servicemetadata: name: user-service # Service名稱(Pod間通信用此名稱)spec: type: NodePort # 服務類型:NodePort(暴露到集羣外部,適合測試) selector: app: user-service # 關聯標籤匹配的Pod(和Deployment的Pod標籤一致) ports: - port: 8081 # Service內部端口(Pod間通信用此端口) targetPort: 8081 # 映射到Pod的端口(和containerPort一致) nodePort: 30081 # 集羣節點暴露的端口(範圍30000-32767,外部訪問用)
4. 步驟 4:部署用户服務到 K8s 並驗證
# 1. 應用Deployment配置(創建Pod)kubectl apply -f user-service-deployment.yaml# 2. 應用Service配置(創建Service)kubectl apply -f user-service-service.yaml# 3. 查看Deployment狀態(確認Pod正在創建)kubectl get deployments# 輸出示例:# NAME READY UP-TO-DATE AVAILABLE AGE# user-service 2/2 2 2 1m# 説明:READY 2/2表示2個Pod均就緒# 4. 查看Pod狀態(確認Pod運行正常)kubectl get pods -l app=user-service # 按標籤篩選Pod# 輸出示例:# NAME READY STATUS RESTARTS AGE# user-service-7f98d7c6b4-2xqzk 1/1 Running 0 1m# user-service-7f98d7c6b4-5r7k8 1/1 Running 0 1m# 5. 查看Service狀態(確認NodePort暴露)kubectl get services user-service# 輸出示例:# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE# user-service NodePort 10.96.123.45 <none> 8081:30081/TCP 1m# 説明:外部可通過「Minikube節點IP:30081」訪問服務# 6. 獲取Minikube節點IP並訪問服務minikube ip # 輸出Minikube節點IP,如192.168.49.2# 訪問服務:http://192.168.49.2:30081/user/get/1(返回用户數據即成功)# 7. 查看Pod日誌(排查問題用)kubectl logs user-service-7f98d7c6b4-2xqzk # 替換為實際Pod名稱
5. 步驟 5:遷移訂單服務(複用用户服務邏輯)
訂單服務遷移與用户服務類似,核心差異是環境變量中需配置 Feign 調用的用户服務地址(用 K8s Service 名稱):
# order-service-deployment.yaml 關鍵環境變量配置env:- name: FEIGN_CLIENT_USER_SERVICE_URL value: "http://user-service:8081" # 用Service名稱通信,無需IP
部署命令與驗證步驟完全複用用户服務,最終實現「訂單服務 Pod 調用用户服務 Pod」的 K8s 內部通信。
五、實戰 3:K8s 部署 Nacos 與 TiDB(確保微服務依賴可用)
微服務依賴 Nacos(註冊中心)和 TiDB(數據庫),需先部署到 K8s(或用外部服務,這裏以 K8s 部署為例)。
1. 部署 Nacos 到 K8s(簡化版,適合測試)
創建nacos-deployment.yaml:
apiVersion: apps/v1kind: Deploymentmetadata: name: nacos-servicespec: replicas: 1 selector: matchLabels: app: nacos template: metadata: labels: app: nacos spec: containers: - name: nacos image: nacos/nacos-server:v2.2.3 ports: - containerPort: 8848 env: - name: MODE value: "standalone" # 單機模式---# 同時創建Nacos的ServiceapiVersion: v1kind: Servicemetadata: name: nacos-servicespec: type: NodePort selector: app: nacos ports: - port: 8848 targetPort: 8848 nodePort: 30088
部署並驗證:
kubectl apply -f nacos-deployment.yaml# 訪問Nacos:http://MinikubeIP:30088/nacos(賬號nacos/nacos),確認用户/訂單服務已註冊
2. 部署 TiDB 到 K8s(用 TiDB Operator 簡化部署,可選)
生產環境推薦用 TiDB Operator 部署 TiDB 集羣,本地測試可簡化為單 Pod 部署(僅用於驗證):
# tidb-deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata: name: tidb-servicespec: replicas: 1 selector: matchLabels: app: tidb template: metadata: labels: app: tidb spec: containers: - name: tidb image: pingcap/tidb:v7.0.0 ports: - containerPort: 4000 env: - name: TIDB_CONFIG value: "log-level: info"---apiVersion: v1kind: Servicemetadata: name: tidb-servicespec: type: NodePort selector: app: tidb ports: - port: 4000 targetPort: 4000 nodePort: 30090
部署後,微服務通過tidb-service:4000訪問數據庫,與 Docker Compose 邏輯一致。
六、避坑指南:遷移過程中的 6 個高頻問題
1. 坑 1:K8s 拉取不到本地鏡像(報 ImagePullBackOff)
- 現象:kubectl get pods顯示 Pod 狀態為ImagePullBackOff,日誌報 “ErrImagePull: image not found”;
- 原因:K8s 默認從遠程倉庫拉取鏡像,本地鏡像未加載到 Minikube;
- 解決:執行minikube image load 鏡像名:版本,並在 Deployment 中設置imagePullPolicy: Never。
2. 坑 2:Pod 間通信失敗(訂單服務調用用户服務報 Connection refused)
- 現象:訂單服務日誌報 “connect to user-service:8081 failed”;
- 原因 1:Service 未關聯 Pod(Deployment 的 Pod 標籤與 Service 的selector不匹配);
- 原因 2:Service 未就緒(kubectl get services顯示 Service 的ENDPOINTS為空);
- 解決:
- 核對 Deployment 的template.metadata.labels與 Service 的selector.matchLabels是否一致;
- 執行kubectl describe service user-service查看 Service 關聯的 Pod,確保ENDPOINTS有值。
3. 坑 3:外部無法訪問 Service(報 Connection timed out)
- 現象:訪問http://MinikubeIP:30081超時,無法連接;
- 原因 1:NodePort 端口範圍錯誤(需在 30000-32767 之間,超出範圍 K8s 不生效);
- 原因 2:Minikube 網絡模式問題(Windows 用 WSL2 時,需通過minikube service user-service --url獲取正確訪問地址);
- 解決:
- 確認 Service 的nodePort在 30000-32767 之間;
- 執行minikube service user-service --url,用輸出的臨時 URL 訪問(如http://127.0.0.1:51234)。
4. 坑 4:Pod 頻繁重啓(報 CrashLoopBackOff)
- 現象:Pod 狀態頻繁從Running變為CrashLoopBackOff,日誌報 “Java out of memory”;
- 原因:Deployment 的resources.limits.memory設置過小(如 256MB),服務啓動時內存不足;
- 解決:增大內存限制,如memory: "512Mi",重新應用 Deployment:kubectl apply -f user-service-deployment.yaml。
5. 坑 5:健康檢查失敗(Pod 狀態為 Running 但 Ready 為 0/1)
- 現象:kubectl get pods顯示user-service-xxx 0/1 Running,READY為 0;
- 原因:就緒探針(readinessProbe)配置錯誤,如path寫錯(應為/actuator/health,而非/health);
- 解決:核對探針的path和port,確保與服務的健康檢查端點一致,查看探針日誌:kubectl describe pod Pod名稱(在 Events 中查看失敗原因)。
6. 坑 6:擴縮容後流量未負載均衡
- 現象:執行kubectl scale deployment user-service --replicas=3擴容到 3 個 Pod,但請求僅分發到 2 個;
- 原因:K8s Service 的負載均衡依賴kube-proxy,需等待kube-proxy更新端點列表(約 10 秒);
- 解決:等待 10-20 秒後再測試,或執行kubectl delete pod -l app=user-service重啓 Pod,觸發端點更新。
七、遷移總結:從 Docker 到 K8s 的核心步驟梳理
- 環境準備:用 Minikube 搭建本地 K8s 集羣,加載本地微服務鏡像;
- 配置轉換:將 Compose 的 service 拆分為 K8s 的 Deployment(部署規則)和 Service(網絡暴露);
- 依賴部署:部署 Nacos、TiDB 等依賴服務,確保微服務能正常連接;
- 服務遷移:先遷移無依賴的服務(如用户服務),再遷移有依賴的服務(如訂單服務);
- 驗證與優化:驗證 Pod 通信、外部訪問、擴縮容功能,根據問題調整資源配置與探針。
八、系列終章:從技術選型到 K8s 部署的全鏈路回顧
本系列從「Java 分佈式框架 + 國產數據庫 + Docker 部署」的技術選型出發,歷經 12 篇實戰,完成了從 “開發環境搭建” 到 “生產級 K8s 部署” 的全鏈路落地:
- 基礎篇:環境準備(JDK/MySQL/TiDB)、國產數據庫選型(TiDB/OceanBase/ 達夢);
- 框架篇:Spring Cloud Alibaba 整合(Nacos/Sentinel/OpenFeign/Gateway)、TiDB 優化;
- 部署篇:數據遷移(MySQL→TiDB)、微服務容器化(Docker 鏡像構建)、多服務編排(Docker Compose)、生產級優化(監控 / 日誌 / 灰度)、K8s 遷移;
通過這套技術棧,你已具備「分佈式微服務設計 + 國產數據庫落地 + 容器化部署」的完整能力,可支撐從中小項目到大型高併發系統的技術需求。後續可深入 K8s 高級特性(如 StatefulSet 部署有狀態服務、ConfigMap 管理配置、Ingress 替代 NodePort),進一步提升系統的可維護性與擴展性。