
微服務 Docker 容器化部署與 CI/CD 上線開發“在我電腦上跑得好好兒的” 運維“你那叫開發環境我這叫生產環境兩者之間隔了100個環境變量、50個依賴版本和無數個’我以為是一樣的’。” Docker 站出來說“別吵了打包一下——到我這兒都是同一個環境。”一、Docker 為什么是微服務的最佳拍檔微服務架構下你有 10 個 Java 服務、2 個前端、1 個 Python AI 引擎。每個服務依賴不同的運行時版本、環境變量、系統庫。傳統部署方式你得上 13 臺虛擬機/物理機每臺安裝不同的 JDK 版本——這是運維噩夢。Docker 解決的就是這個環境不一致問題痛點Docker 怎么解決“我機器上能跑”鏡像包含完整運行環境部署慢容器秒級啟動VM 要分鐘級資源浪費共享宿主機內核比VM輕量近百倍配置不一致鏡像環境變量完全可控回滾難舊鏡像還在秒級回滾二、核心概念速覽概念一句話類比鏡像Image打包好的程序環境只讀一個安裝包容器Container鏡像的運行時實例安裝后打開的程序倉庫Registry存放和分發鏡像的地方程序下載站Dockerfile鏡像的構建配方安裝腳本Docker Compose多容器編排定義文件一鍵啟動全家桶三、Dockerfile 編寫實戰# 多階段構建階段1 —— Maven構建 FROM maven:3.8.6-openjdk-17-slim AS builder WORKDIR /build COPY pom.xml . RUN mvn dependency:go-offline -B COPY src ./src RUN mvn clean package -DskipTests # 階段2 —— 運行鏡像只保留JAR包 FROM eclipse-temurin:17-jdk-alpine RUN apk add --no-cache curl # 健康檢查用 WORKDIR /app COPY --frombuilder /build/target/*.jar app.jar # 非 root 用戶運行安全最佳實踐 RUN addgroup --system app adduser --system --ingroup app app USER app EXPOSE 8080 ENTRYPOINT [java, -jar, -Dspring.profiles.active${PROFILE}, app.jar]多階段構建的好處第一階段用 Maven 鏡像編譯800MB但最終運行鏡像只保留 JRE JAR 包200MB。編譯工具鏈全扔了鏡像瘦身 75%。構建和運行# 構建鏡像dockerbuild-torder-service:1.0.0.# 運行容器dockerrun-d\--nameorder-service\-p8080:8080\-ePROFILEprod\-eNACOS_ADDR192.168.1.100:8848\order-service:1.0.0四、Docker Compose 一鍵編排一個微服務項目通常包含 6-8 個服務外加依賴中間件。手動 docker run 每個容器配網絡、配依賴、配環境變量——鍵盤都能敲冒煙。docker-compose.yml讓你一條命令搞定一切version:3.8services:nacos:image:nacos/nacos-server:v2.2.3environment:MODE:standaloneports:-8848:8848mysql:image:mysql:8.0environment:MYSQL_ROOT_PASSWORD:root123ports:-3306:3306volumes:-mysql_data:/var/lib/mysqlredis:image:redis:7.0ports:-6379:6379command:redis-server--requirepass redis123gateway:build:./gatewayports:-80:8080environment:NACOS_ADDR:nacos:8848depends_on:-nacosorder-service:build:./order-serviceports:-8081:8080environment:PROFILE:prodNACOS_ADDR:nacos:8848DB_URL:jdbc:mysql://mysql:3306/order_dbREDIS_ADDR:redis:6379depends_on:-nacos-mysql-redisproduct-service:build:./product-serviceports:-8082:8080environment:PROFILE:prodNACOS_ADDR:nacos:8848depends_on:-nacos-mysqlvolumes:mysql_data:關鍵點depends_on控制啟動順序但不等待服務就緒生產環境建議用 healthcheck容器間通過服務名直接通信Docker 內置 DNS 自動解析如nacos:8848volumes持久化 MySQL 數據容器刪除后數據不丟動命令dockercompose up-d# 后臺啟動所有服務dockercomposeps# 查看運狀態dockercompose logs-forder-service# 查看某個服務的日志dockercompose down# 停止并刪除所有容器五、CI/CD從人肉部署到自動化流水線CI/CD 就是讓你的代碼從提交到上線全自動化。一條流水線 Click Wait取代打JAR包→上傳服務器→殺進程→啟動→祈禱的手動操作。代碼提交 → 自動構建 → 自動測試 → 自動打包鏡像 → 自動推送到倉庫 → 自動部署 │ │ └──────────────── 持續集成(CI) ──────────────┘ │ └──────────────── 持續交付(CD) ──────────────────────────────┘六、GitLab CI/CD 配置# .gitlab-ci.ymlstages:-test-build-docker-deployvariables:MAVEN_OPTS:-Dmaven.repo.local$CI_PROJECT_DIR/.m2IMAGE:registry.example.com/$CI_PROJECT_NAME:$CI_COMMIT_SHORT_SHA# 階段1單元測試test:stage:testimage:maven:3.8.6-openjdk-17-slimscript:-mvn testartifacts:reports:junit:target/surefire-reports/*.xml# 階段2編譯打包build:stage:buildimage:maven:3.8.6-openjdk-17-slimscript:-mvn clean package-DskipTestsartifacts:paths:-target/*.jaronly:-main-tags# 階段3構建 Docker 鏡像并推送docker-build:stage:dockerimage:docker:24.0.5services:-docker:24.0.5-dindscript:-docker build-t $IMAGE .-docker login-u $CI_REGISTRY_USER-p $CI_REGISTRY_PASSWORD registry.example.com-docker push $IMAGEonly:-main# 階段4自動部署到服務器deploy:stage:deployimage:alpine:3.18before_script:-apk add--no-cache openssh-clientscript:-mkdir-p ~/.ssh-echo $SSH_PRIVATE_KEY~/.ssh/id_rsachmod 600 ~/.ssh/id_rsa-ssh-o StrictHostKeyCheckingno deploy192.168.1.100 docker pull $IMAGEdocker stop order-service||truedocker rm order-service||truedocker run-d--name order-service--network micro_net-e PROFILEprod-e NACOS_ADDR192.168.1.100:8848$IMAGEonly:-main這條流水線實現push 代碼到 main 分支 → 自動測 → 自動編譯 → 自動打鏡像 → 自動推鏡像倉庫 → 自動拉取/重啟容器。七、Jenkins Pipeline 方案如果你的團隊用的是 Jenkins 而不是 GitLab CI下面是一個聲明式流水線pipeline{agent any environment{IMAGEorder-service:${env.BUILD_NUMBER}REGISTRYregistry.example.com}stages{stage(拉取代碼){steps{git url:https://gitlab.example.com/order-service.git}}stage(Maven 構建){steps{shmvn clean package -DskipTests}}stage(Docker 鏡像){steps{shdocker build -t${IMAGE}.shdocker tag${IMAGE}${REGISTRY}/${IMAGE}}}stage(推送倉庫){steps{withCredentials([string(credentialsId:docker-registry,variable:PWD)]){shdocker login -u admin -p${PWD}${REGISTRY}shdocker push${REGISTRY}/${IMAGE}}}}stage(部署到生產){steps{sh docker pull ${REGISTRY}/${IMAGE} docker stop order-service || true docker rm order-service || true docker run -d --name order-service -p 8080:8080 ${REGISTRY}/${IMAGE} }}}post{success{echo部署成功}failure{echo構建失敗請檢查日志}}}八、部署策略策略做法適用滾動更新逐個替換舊容器不停服常規發布最常用藍綠部署保留舊版本新版本就緒后切流量重要系統快速回滾金絲雀發布新版本先放 5% 流量沒問題再全量高風險變更逐步驗證配合 Kubernetes 或 Docker Swarm這些策略都是原生支持。用 Docker Compose 手動部署的話滾動更新最簡單dockercompose up-d--no-deps --force-recreate--buildorder-service九、完整 CI/CD 流程速覽Git Push ──┬── GitLab CI 觸發 ── 執行 .gitlab-ci.yml ──┐ │ │ ├── 編譯 → 測試 → 打鏡像 → 推送 Harbor ───────┤ │ │ └── SSH 到服務器 → docker pull → docker run ──┘ │ ▼ □ 應用更新完成一條git push做完所有事開發人員再也不用碰生產服務器——這是 CI/CD 最核心的價值。小結Docker 是微服務的標準集裝箱CI/CD 是自動化上線的傳送帶。從 Dockerfile 到 Docker Compose從 GitLab CI 到 Jenkins Pipeline一條自動化的流水線讓團隊從手動部署2小時變成push代碼2分鐘上線。但記住工具只是手段真正的目的不是速度而是可靠性和可重復性——你今天上午部署成功的流程半夜3點按下去也應該是同樣的結果。