)
簡介這份資源面向需要在阿里云Kubernetes集群上落地前后端分離項目的開發(fā)與運維人員圍繞Vue2前端、Nginx、SpringBoot2.5后端與Nacos2.0.3注冊配置中心提供一套可直接參考的容器化部署編排方案適合已具備一定K8s基礎(chǔ)、希望打通微服務(wù)上線流程的中高級讀者。壓縮包共16個文件約34.69MB以8個yaml編排清單為核心配合2個sh部署腳本、2個Dockerfile鏡像構(gòu)建文件以及Nacos所需的sql初始化腳本、nginx.conf配置、jar應(yīng)用包和gz前端產(chǎn)物覆蓋從鏡像構(gòu)建到服務(wù)發(fā)布的完整鏈路。資源已有1342人學(xué)習(xí)下載具備一定參考熱度。讀者可從中獲得Vue與SpringBoot應(yīng)用的鏡像構(gòu)建思路、Nacos基于StatefulSet與Headless Service的集群化部署寫法、MySQL數(shù)據(jù)初始化方式及Ingress對外暴露配置并借助一鍵部署腳本快速復(fù)現(xiàn)環(huán)境減少自行拼裝清單時的試錯成本。1. 一套能跑通的前后端分離部署鏈路到底卡在哪很多團(tuán)隊第一次把 Vue2 前端、SpringBoot2.5 后端和 Nacos2.0.3 注冊中心往 K8s 上搬卡點往往不在鏡像構(gòu)建而在“服務(wù)發(fā)現(xiàn)怎么接、配置怎么灌、Nginx 怎么把請求轉(zhuǎn)進(jìn)集群”。本地 docker-compose 跑得好好的一上集群就出現(xiàn)前端 502、后端注冊不上 Nacos、Pod 反復(fù)重啟。這套部署方案要解決的就是這條完整鏈路Vue2 靜態(tài)資源交給 Nginx 托管SpringBoot 以 Deployment 形式注冊進(jìn) NacosNacos 自身用 StatefulSet 保證數(shù)據(jù)一致。適合已經(jīng)會寫 Dockerfile、但對 K8s 編排還停留在kubectl apply階段的后端和運維同學(xué)照著走能少踩幾輪“玄學(xué)”網(wǎng)絡(luò)坑。2. 鏡像與配置先行三個組件的構(gòu)建邊界上集群之前先把三個組件的鏡像和配置邊界劃清楚。這一步做扎實后面 K8s 清單只是“搬運”做不扎實Pod 起來了也是黑匣子。2.1 Vue2 前端多階段構(gòu)建把 dist 塞進(jìn) NginxVue2 項目常見做法是本地npm run build再手動拷 dist上了 CI 就不可復(fù)現(xiàn)。我一般用多階段構(gòu)建把 Node 編譯環(huán)境和 Nginx 運行環(huán)境分開最終鏡像只留靜態(tài)文件和 Nginx 配置。# 階段一編譯 Vue2 FROM node:14-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm install --registryhttps://registry.npmmirror.com COPY . . RUN npm run build # 階段二Nginx 托管靜態(tài)資源 FROM nginx:1.21-alpine COPY --frombuilder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80邏輯說明第一階段用 Node14 編譯npm install單獨 COPY package 文件是為了利用鏡像層緩存源碼改動不會觸發(fā)依賴重裝。第二階段只拷 dist 和自定義 nginx.conf鏡像體積能壓到 30MB 左右。參數(shù)上注意npm run build的產(chǎn)物目錄要和 COPY 路徑一致Vue CLI 默認(rèn)是distVite 項目要改成dist對應(yīng)實際輸出。Nginx 配置里最關(guān)鍵的是把/api轉(zhuǎn)發(fā)到后端 Service而不是寫死 Pod IPserver { listen 80; location / { root /usr/share/nginx/html; try_files $uri $uri/ /index.html; # Vue history 路由回退 } location /api/ { proxy_pass http://springboot-svc:8080/; # 指向 K8s Service proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }try_files那行是 Vue Router history 模式的后悔藥不加的話刷新子路由直接 404。proxy_pass末尾的斜杠決定路徑是否截斷/api/配http://svc:8080/會把/api/user轉(zhuǎn)成/user配成不帶斜杠則保留/api/user這個細(xì)節(jié)翻車的人不少。2.2 SpringBoot2.5Nacos 客戶端版本要對齊SpringBoot2.5 對應(yīng) Spring Cloud 2020.0.xNacos 客戶端要用2021.1這個 starter 版本別拿2.2.x的老 starter 硬配否則啟動時報NoSuchMethodError。pom 里關(guān)鍵依賴dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId version2021.1/version /dependency dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-config/artifactId version2021.1/version /dependencybootstrap.yml里把 Nacos 地址指向集群內(nèi) Service不要寫公網(wǎng) IPspring: application: name: springboot-svc cloud: nacos: discovery: server-addr: nacos-svc:8848 config: server-addr: nacos-svc:8848 file-extension: yaml參數(shù)說明spring.application.name必須和 K8s Service 名一致Nacos 注冊的服務(wù)名就是它前端 Nginx 轉(zhuǎn)發(fā)也認(rèn)這個名字。server-addr用nacos-svc:8848依賴集群 DNS前提是 Nacos 的 Service 已經(jīng)建好所以部署順序是先 Nacos 后后端。配置中心拉取失敗時先kubectl exec進(jìn) Pod 里nslookup nacos-svc確認(rèn) DNS 通不通比看日志快。2.3 Nacos2.0.3StatefulSet 而非 DeploymentNacos2.0 默認(rèn)用內(nèi)嵌 Derby單機(jī)夠用但集群模式必須外接 MySQL且每個節(jié)點要有穩(wěn)定網(wǎng)絡(luò)標(biāo)識所以用 StatefulSet。鏡像用nacos/nacos-server:2.0.3環(huán)境變量里指定數(shù)據(jù)庫env: - name: MODE value: cluster - name: SPRING_DATASOURCE_PLATFORM value: mysql - name: MYSQL_SERVICE_HOST value: mysql-svc - name: MYSQL_SERVICE_DB_NAME value: nacos_config - name: MYSQL_SERVICE_USER value: nacos - name: MYSQL_SERVICE_PASSWORD value: nacos123 - name: NACOS_SERVERS value: nacos-0.nacos-headless:8848 nacos-1.nacos-headless:8848 nacos-2.nacos-headless:8848NACOS_SERVERS必須用 headless Service 的完整域名普通 ClusterIP Service 解析不出每個 Pod 的獨立地址集群選主會失敗。MySQL 庫要先導(dǎo)入 Nacos 自帶的mysql-schema.sql2.0.3 的表結(jié)構(gòu)和 1.x 有差異別拿舊腳本湊合。3. K8s 清單落地從 Service 到探針的編排細(xì)節(jié)鏡像推上去之后K8s 清單決定服務(wù)能不能穩(wěn)定對外。這一章按“先通后穩(wěn)”的順序拆先讓三個組件互相能訪問再補(bǔ)探針和資源限制。3.1 三類 Service 的選型與端口映射前端用 NodePort 或 Ingress 暴露后端和 Nacos 用 ClusterIP 內(nèi)部通信。Nacos 額外需要一個 headless Service 給 StatefulSet 用apiVersion: v1 kind: Service metadata: name: nacos-headless spec: clusterIP: None selector: app: nacos ports: - port: 8848 name: client - port: 9848 name: grpc注意 9848 端口Nacos2.0 新增了 gRPC 通信端口偏移量是主端口 1000客戶端連 8848 時會自動連 9848。只開 8848 不開 9848服務(wù)注冊能成功但配置監(jiān)聽會斷現(xiàn)象是配置改了不生效這個坑很隱蔽。后端 Service 就常規(guī) ClusterIPapiVersion: v1 kind: Service metadata: name: springboot-svc spec: selector: app: springboot ports: - port: 8080 targetPort: 8080port是 Service 暴露端口targetPort是容器實際監(jiān)聽端口兩者不一致時排查先看kubectl get endpoints springboot-svc有沒有后端地址為空說明 selector 沒匹配上 Pod 標(biāo)簽。3.2 Deployment 的探針與啟動順序SpringBoot 啟動慢Nacos 客戶端注冊還要時間liveness 探針配太激進(jìn)會導(dǎo)致還沒注冊完就被殺掉重啟。我一般給 startupProbe 留足窗口startupProbe: httpGet: path: /actuator/health port: 8080 failureThreshold: 30 periodSeconds: 5 livenessProbe: httpGet: path: /actuator/health port: 8080 periodSeconds: 10 readinessProbe: httpGet: path: /actuator/health port: 8080 periodSeconds: 5failureThreshold: 30乘periodSeconds: 5等于 150 秒啟動窗口夠 SpringBoot2.5 加 Nacos 注冊走完。/actuator/health要確認(rèn)management.endpoints.web.exposure.includehealth已開否則探針 404 一直失敗。readiness 控制流量接入Nacos 注冊完成前不讓 Nginx 轉(zhuǎn)發(fā)過來避免前端 502。3.3 配置注入ConfigMap 與環(huán)境變量怎么分工非敏感配置走 ConfigMap 掛載數(shù)據(jù)庫密碼走 Secret。SpringBoot 的application.yml里 Nacos 地址這類集群相關(guān)配置用環(huán)境變量覆蓋比改鏡像更靈活env: - name: SPRING_CLOUD_NACOS_DISCOVERY_SERVER_ADDR value: nacos-svc:8848 - name: SPRING_PROFILES_ACTIVE value: k8sSpringBoot 的 relaxed binding 會把SPRING_CLOUD_NACOS_DISCOVERY_SERVER_ADDR映射到spring.cloud.nacos.discovery.server-addr這樣同一鏡像能在測試和生產(chǎn)復(fù)用。ConfigMap 掛載的 yml 用subPath掛單個文件別整個目錄覆蓋否則鏡像里自帶的配置全丟。4. 避坑排查五個真實翻車現(xiàn)場部署鏈路上有些問題日志不報錯只能靠現(xiàn)象反推。下面五條是我和同事踩過的按“現(xiàn)象 → 原因 → 解決”記下來。4.1 前端刷新 404現(xiàn)象首頁能開點進(jìn)子路由再刷新就 404。原因是 Nginx 沒配try_files請求/user/list時去找對應(yīng)靜態(tài)文件找不到。解決location /里加try_files $uri $uri/ /index.html;讓所有未命中路徑回退到 index.html 交給 Vue Router。4.2 后端注冊不上 Nacos現(xiàn)象Pod 日志報failed to req API:/nacos/v1/ns/instance但nslookup nacos-svc能通。原因多半是 Nacos 集群沒起來headless Service 的 Pod 沒 Ready或者 9848 端口沒開。解決先kubectl get pods -l appnacos確認(rèn)三個副本 Running再檢查 Service 是否暴露 9848最后看 Nacos 日志里Nacos started successfully有沒有出現(xiàn)。4.3 配置中心改了不生效現(xiàn)象Nacos 控制臺改了配置后端日志顯示監(jiān)聽成功但值沒變。原因是bootstrap.yml沒生效SpringBoot2.5 默認(rèn)不加載 bootstrap 上下文需要引入spring-cloud-starter-bootstrap依賴。解決加這個 starter或者把 Nacos 配置挪到application.yml用spring.config.import方式引入。4.4 Pod 反復(fù)重啟現(xiàn)象kubectl get pods顯示 RESTARTS 持續(xù)增長describe 里L(fēng)ast State: Terminated, Reason: Error。原因是 liveness 探針在啟動階段就判死。解決加 startupProbe 兜住啟動期liveness 的initialDelaySeconds別小于 60或者干脆讓 liveness 依賴 startupProbe 成功后再計時。4.5 Nacos 數(shù)據(jù)丟失現(xiàn)象重啟 Nacos 后配置和服務(wù)列表清空。原因是用了內(nèi)嵌 Derby 且沒掛持久卷或者集群模式?jīng)]連 MySQL。解決集群模式必須配SPRING_DATASOURCE_PLATFORMmysql并掛 PVC 給日志目錄MySQL 數(shù)據(jù)單獨做備份Nacos 本身不存業(yè)務(wù)數(shù)據(jù)。5. 上線前的驗證清單與一個壓測技巧清單跑通不等于能上線最后一章給一套驗證順序和一個我常用的壓測手法。驗證按依賴方向走先 Nacos 三副本 Ready再curl nacos-svc:8848/nacos/v1/ns/operator/servers看集群節(jié)點列表是否三個都在然后后端 Pod 起來后curl springboot-svc:8080/actuator/health返回 UP同時 Nacos 控制臺服務(wù)列表里能看到springboot-svc且實例數(shù)為副本數(shù)最后前端 NodePort 訪問用瀏覽器 Network 面板確認(rèn)/api請求打到后端而不是 404。壓測技巧不要一上來壓全鏈路先用kubectl run起一個臨時 Pod 在集群內(nèi)壓后端排除 Nginx 和外部網(wǎng)絡(luò)干擾kubectl run loadtest --imagewilliamyeh/hey --restartNever -- \ -n 200 -c 20 -z 30s http://springboot-svc:8080/api/health-n總請求數(shù)、-c并發(fā)、-z持續(xù)時間集群內(nèi)壓測能拿到后端真實吞吐。觀察kubectl top pods里 CPU 和內(nèi)存曲線如果 Pod 內(nèi)存持續(xù)上漲不回落多半是 Nacos 配置監(jiān)聽沒釋放或者連接池沒配上限這時候再回去查spring.cloud.nacos.config的 refresh 邏輯。有個習(xí)慣我保持了幾年每次改完 K8s 清單先在本地kubectl apply --dry-runserver過一遍再kubectl diff看變更范圍最后才真 apply。這套流程幫我攔下過好幾次誤刪 Service 的事故。希望這套部署鏈路能幫到你少走幾輪重啟。本文還有配套的精品資源點擊獲取