大家好,前九篇我们已经搭建了一个 “高可用、高并发、可管理、可排查、高安全、可观测” 的生产级微服务基础集群:通过 Nacos 实现配置的统一管理与加密,通过 OpenFeign+Ribbon 实现服务通信与负载均衡,通过 Resilience4j 实现贴合业务的降级兜底,通过 Spring Cloud Gateway 实现统一入口管控,通过 Sleuth+Zipkin+ELK 实现链路追踪与日志集中收集,通过 Spring Boot Admin 实现实时监控告警。但在实际落地过程中,还存在一个核心痛点:微服务部署繁琐—— 本地开发时需要逐个启动 Nacos、ES、Kibana、Filebeat、多个微服务,步骤多且易出错;服务器部署时环境配置不一致,导致 “本地能跑、服务器报错”。今天就聚焦微服务 “服务编排” 核心需求,手把手教大家用 Docker+Compose 实现微服务容器化部署,一键启动所有服务,解决环境不一致、部署繁琐的痛点,全程实操,新手跟着走就能掌握!

温馨提示:实操前请确认前提(避免踩坑):
① 已完成前九篇实操,所有微服务能本地正常运行;
② 版本保持一致:Spring Boot 2.6.13 + Spring Cloud Hoxton.SR12 + Nacos 2.0.7 + Docker 20.10.x + Docker Compose 2.20.x;
③ 已安装 Docker Desktop(Windows/Mac)或 Docker 引擎(Linux),并确保 Docker 正常运行;④ 重点注意:容器化核心是 “镜像构建 + 服务编排”,无需修改微服务业务代码,仅需添加配置文件;⑤ 建议提前备份本地微服务代码(避免实操中误改)。

一、先搞懂:容器化部署,解决微服务部署核心痛点

前九篇我们采用 “本地手动启动” 的方式运行微服务,这种方式在开发 / 测试 / 生产环境中都存在致命问题,核心痛点有 3 个:

  1. 部署步骤繁琐:启动一个完整的微服务集群需要依次启动 Nacos→Zipkin→ES→Kibana→Filebeat→user-service→order-service→gateway-service→SBA Server,共 9 个服务,手动操作耗时且易漏启动;
  2. 环境不一致:开发机、测试服务器、生产服务器的 JDK 版本、依赖库、配置路径可能不同,导致 “本地能跑、服务器报错”(经典的 “我本地没问题” 问题);
  3. 资源隔离差:所有服务运行在同一台机器的同一个 JVM / 进程中,一个服务占用过多资源会影响其他服务,且服务崩溃可能导致整个机器进程异常;

而 Docker+Compose 容器化部署正是解决这些痛点的最优方案:

  • Docker:将每个服务(微服务 / Nacos/ES 等)打包成 “镜像”,镜像包含服务运行所需的所有环境(JDK、依赖、配置),实现 “一次打包、到处运行”,彻底解决环境不一致问题;
  • Docker Compose:通过一个docker-compose.yml文件定义所有服务的启动规则(镜像、端口、依赖、网络、数据持久化),执行docker-compose up -d即可一键启动所有服务,无需逐个操作;
  • 核心价值:环境一致化、部署一键化、资源隔离化,适配开发 / 测试 / 生产全环境的部署需求,是微服务落地的必经之路。

核心概念拆解(新手必记,避免混淆)

  1. Docker 核心概念:
  • 镜像(Image):服务的 “安装包”,包含运行服务所需的代码、依赖、环境配置,只读不可修改;
  • 容器(Container):镜像的运行实例,一个镜像可以启动多个容器,容器之间资源隔离;
  • Dockerfile:构建镜像的 “脚本”,定义如何从基础镜像(如 JDK8)构建出当前服务的镜像;
  1. Docker Compose 核心概念:
  • 服务(Service):一个服务对应一个容器(如 nacos 服务、order-service 服务);
  • 网络(Network):Compose 会自动创建专属网络,所有服务在同一网络内可通过服务名互相访问(如 order-service 容器可通过nacos:8848访问 Nacos);
  • 数据卷(Volume):实现容器内数据持久化(如 Nacos/ES 的数据存储到宿主机,容器删除后数据不丢失)。

补充:为什么选择 Docker+Compose 而非直接用 K8s?(新手必看)
K8s(Kubernetes)是生产级的容器编排工具,功能强大但配置复杂,适合大规模微服务集群(数十 / 数百个服务);
Docker Compose 轻量、配置简单,适合中小规模微服务集群(10 个以内服务),新手易上手,能快速实现 “一键部署”;
学习路径:先掌握 Docker+Compose(入门),再进阶学习 K8s(生产),符合新手循序渐进的学习逻辑。

二、实操核心:微服务容器化部署(Docker+Compose)

本篇实操分为三大模块、8 个核心步骤,从 “镜像构建” 到 “一键编排”,完整实现所有微服务的容器化部署:
模块一:环境准备(2 步)
① 验证 Docker 环境;
② 配置 Docker 国内镜像源(加速镜像下载);

模块二:构建微服务镜像(3 步)
① 给每个微服务编写 Dockerfile;
② 构建微服务镜像;
③ 验证镜像构建成功;

模块三:Compose 一键编排(3 步)
① 编写docker-compose.yml(定义所有服务);
② 一键启动所有服务;
③ 验证容器化部署效果;

重点说明:本次实操覆盖的服务包括:Nacos、Zipkin、ES、Kibana、Filebeat、user-service、order-service、gateway-service、SBA Server,共 9 个服务,全部通过 Compose 一键启动。

三、模块一:环境准备(核心前提)

3.1 第一步:验证 Docker 环境

  1. 打开终端(Windows:CMD/PowerShell,Mac/Linux:Terminal),执行以下命令验证 Docker 是否安装成功:
# 查看Docker版本
docker -v
# 查看Docker Compose版本
docker compose version
# 验证Docker服务是否运行
docker info
  1. 预期结果:命令无报错,显示 Docker/Compose 版本信息,说明环境正常;
    (若报错 “Docker daemon is not running”,需启动 Docker Desktop 或 Docker 服务)

3.2 第二步:配置 Docker 国内镜像源(加速下载)

Docker 默认镜像源在国外,下载速度慢,配置国内镜像源(阿里云 / 网易):

  1. Windows/Mac:打开 Docker Desktop → Settings → Docker Engine → 在registry-mirrors中添加:
{
  "registry-mirrors": [
    "https://docker.mirrors.ustc.edu.cn",
    "https://hub-mirror.c.163.com",
    "https://cr.console.aliyun.com/",
    "https://docker.1ms.run",
        "https://docker.xuanyuan.me"
  ]
}
  1. Linux:编辑/etc/docker/daemon.json文件,添加上述镜像源,执行systemctl restart docker重启 Docker;

  2. 验证:执行docker info,在输出中能看到配置的镜像源,说明生效。

四、模块二:构建微服务镜像(核心,一次打包到处运行)

我们以order-service为例讲解 Dockerfile 编写和镜像构建,user-service、gateway-service、sba-server的配置几乎一致,仅需修改少量参数。

4.1 第一步:给微服务编写 Dockerfile

  1. 进入order-service项目根目录,新建文件Dockerfile(无后缀),内容如下:
# 基础镜像:JDK8(和Spring Boot 2.6.x兼容)
FROM openjdk:8-jdk-alpine
# 维护者信息(可选)
MAINTAINER xxx <your-email@xxx.com>
# 设置工作目录
WORKDIR /app
# 复制打包后的jar包到容器中(注意:需先打包微服务为jar包)
COPY target/order-service-0.0.1-SNAPSHOT.jar /app/order-service.jar
# 暴露端口(和微服务配置的端口一致)
EXPOSE 8082
# 启动命令(指定Nacos地址为容器名,后续Compose网络中可访问)
ENTRYPOINT ["java","-jar","/app/order-service.jar","--spring.cloud.nacos.discovery.server-addr=nacos:8848","--spring.cloud.nacos.config.server-addr=nacos:8848"]

关键说明:

  • FROM openjdk:8-jdk-alpine:选择轻量的 Alpine 版本 JDK8,减少镜像体积;
  • COPY:需先执行mvn clean package -DskipTests将微服务打包为 jar 包,放在target目录;
  • ENTRYPOINT:启动命令中指定 Nacos 地址为nacos:8848(Compose 中 Nacos 服务名),而非localhost:8848(容器内localhost≠宿主机localhost);
  • 暴露端口需和微服务配置的server.port一致(order-service 为 8082)。
  1. 给其他微服务编写 Dockerfile(仅修改标注部分):
  • user-service:
FROM openjdk:8-jdk-alpine
MAINTAINER xxx <your-email@xxx.com>
WORKDIR /app
COPY target/user-service-0.0.1-SNAPSHOT.jar /app/user-service.jar
EXPOSE 8081
ENTRYPOINT ["java","-jar","/app/user-service.jar","--spring.cloud.nacos.discovery.server-addr=nacos:8848","--spring.cloud.nacos.config.server-addr=nacos:8848"]
  • gateway-service:
FROM openjdk:8-jdk-alpine
MAINTAINER xxx <your-email@xxx.com>
WORKDIR /app
COPY target/gateway-service-0.0.1-SNAPSHOT.jar /app/gateway-service.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app/gateway-service.jar","--spring.cloud.nacos.discovery.server-addr=nacos:8848","--spring.cloud.nacos.config.server-addr=nacos:8848"]
  • sba-server:
FROM openjdk:8-jdk-alpine
MAINTAINER xxx <your-email@xxx.com>
WORKDIR /app
COPY target/sba-server-0.0.1-SNAPSHOT.jar /app/sba-server.jar
EXPOSE 8088
ENTRYPOINT ["java","-jar","/app/sba-server.jar","--spring.cloud.nacos.discovery.server-addr=nacos:8848"]

4.2 第二步:打包微服务并构建镜像

  1. 打包每个微服务:进入每个微服务根目录,执行 Maven 打包命令(需安装 Maven):
# 跳过测试打包,避免测试用例影响
mvn clean package -DskipTests
  1. 构建镜像:进入每个微服务根目录,执行docker build命令构建镜像:
# 构建order-service镜像,标签为springcloud/order-service:1.0
docker build -t springcloud/order-service:1.0 .
# 构建user-service镜像
docker build -t springcloud/user-service:1.0 .
# 构建gateway-service镜像
docker build -t springcloud/gateway-service:1.0 .
# 构建sba-server镜像
docker build -t springcloud/sba-server:1.0 .

说明:-t指定镜像标签(名称:版本),. 表示 Dockerfile 在当前目录。

4.3 第三步:验证镜像构建成功
执行以下命令查看已构建的镜像:

docker images

预期结果:列表中能看到springcloud/order-service:1.0、springcloud/user-service:1.0等镜像,说明构建成功。

五、模块三:Compose 一键编排(核心,一键启动所有服务)

我们编写docker-compose.yml文件,定义所有服务的启动规则,实现 “一键启动”。
5.1 第一步:编写 docker-compose.yml
在任意目录(建议新建springcloud-compose目录)新建docker-compose.yml文件,内容如下:

version: '3.8'  # Compose版本,和Docker版本匹配

# 定义网络(所有服务在同一网络,可通过服务名访问)
networks:
  springcloud-network:
    driver: bridge

# 定义数据卷(持久化Nacos/ES数据)
volumes:
  nacos-data:
  es-data:

# 定义所有服务
services:
  # 1. Nacos服务
  nacos:
    image: nacos/nacos-server:v2.0.7  # Nacos镜像版本和之前一致
    container_name: nacos
    ports:
      - "8848:8848"  # 端口映射:宿主机8848→容器8848
    environment:
      - MODE=standalone  # 单机模式
      - JVM_XMS=512m
      - JVM_XMX=512m
    volumes:
      - nacos-data:/home/nacos/data  # 数据持久化
    networks:
      - springcloud-network
    restart: always  # 容器异常退出时自动重启

  # 2. Zipkin服务
  zipkin:
    image: openzipkin/zipkin:2.24  # Zipkin镜像
    container_name: zipkin
    ports:
      - "9411:9411"
    networks:
      - springcloud-network
    restart: always

  # 3. Elasticsearch服务
  elasticsearch:
    image: elasticsearch:7.17.0  # ES版本和之前一致
    container_name: elasticsearch
    ports:
      - "9200:9200"
      - "9300:9300"
    environment:
      - discovery.type=single-node  # 单机模式
      - ES_JAVA_OPTS=-Xms512m -Xmx512m
      - xpack.security.enabled=false
    volumes:
      - es-data:/usr/share/elasticsearch/data
    networks:
      - springcloud-network
    restart: always

  # 4. Kibana服务(依赖ES)
  kibana:
    image: kibana:7.17.0
    container_name: kibana
    ports:
      - "5601:5601"
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200  # 访问ES的地址(服务名)
    depends_on:
      - elasticsearch  # 依赖ES,ES启动后再启动Kibana
    networks:
      - springcloud-network
    restart: always

  # 5. Filebeat服务(依赖ES)
  filebeat:
    image: elastic/filebeat:7.17.0
    container_name: filebeat
    volumes:
      # 挂载Filebeat配置文件(需提前编写filebeat.yml)
      - ./filebeat.yml:/usr/share/filebeat/filebeat.yml
      # 挂载微服务日志目录(宿主机→容器)
      - /var/lib/docker/volumes/springcloud-compose_order-service-logs/_data:/app/logs/order-service
      - /var/lib/docker/volumes/springcloud-compose_user-service-logs/_data:/app/logs/user-service
      - /var/lib/docker/volumes/springcloud-compose_gateway-service-logs/_data:/app/logs/gateway-service
    depends_on:
      - elasticsearch
    networks:
      - springcloud-network
    restart: always

  # 6. user-service服务(依赖Nacos)
  user-service:
    image: springcloud/user-service:1.0  # 本地构建的镜像
    container_name: user-service
    ports:
      - "8081:8081"
    volumes:
      - user-service-logs:/app/logs  # 日志持久化
    depends_on:
      - nacos
      - zipkin
    networks:
      - springcloud-network
    restart: always

  # 7. order-service服务(依赖Nacos、user-service)
  order-service:
    image: springcloud/order-service:1.0
    container_name: order-service
    ports:
      - "8082:8082"
    volumes:
      - order-service-logs:/app/logs
    depends_on:
      - nacos
      - zipkin
      - user-service
      - elasticsearch
    networks:
      - springcloud-network
    restart: always

  # 8. gateway-service服务(依赖Nacos、order-service)
  gateway-service:
    image: springcloud/gateway-service:1.0
    container_name: gateway-service
    ports:
      - "8080:8080"
    volumes:
      - gateway-service-logs:/app/logs
    depends_on:
      - nacos
      - order-service
    networks:
      - springcloud-network
    restart: always

  # 9. SBA Server服务(依赖Nacos)
  sba-server:
    image: springcloud/sba-server:1.0
    container_name: sba-server
    ports:
      - "8088:8088"
    depends_on:
      - nacos
      - user-service
      - order-service
    networks:
      - springcloud-network
    restart: always

# 新增日志数据卷(微服务日志持久化)
volumes:
  user-service-logs:
  order-service-logs:
  gateway-service-logs:

补充:Filebeat 配置文件(filebeat.yml)
在docker-compose.yml同级目录新建filebeat.yml,内容如下:

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /app/logs/user-service/*.log
    - /app/logs/order-service/*.log
    - /app/logs/gateway-service/*.log
  fields:
    service: "springcloud-demo"
  fields_under_root: true

output.elasticsearch:
  hosts: ["elasticsearch:9200"]
  index: "springcloud-log-%{+yyyy.MM.dd}"

setup.dashboards.enabled: false
setup.template.enabled: false

5.2 第二步:一键启动所有服务

  1. 进入docker-compose.yml所在目录,执行启动命令:
# 后台启动所有服务(-d:后台运行)
docker compose up -d
  1. 查看启动状态:
# 查看所有服务状态
docker compose ps

预期结果:所有服务的状态为Up,说明启动成功;若某服务状态为Exit,执行docker logs 容器名查看报错原因。

5.3 第三步:验证容器化部署效果

  1. 验证 Nacos:访问http://localhost:8848/nacos,能登录控制台,且服务列表中能看到user-service、order-service等服务;
  2. 验证接口访问:用 Postman 访问http://localhost:8080/gateway/order/create/1(携带 Token),能正常返回结果;
  3. 验证 ELK:访问http://localhost:5601,在 Kibana 中能看到微服务日志;
  4. 验证 SBA:访问http://localhost:8088,能看到所有微服务的监控状态;
  5. 验证数据持久化:停止容器(docker compose down)后重启,Nacos 配置、ES 日志数据不丢失。

六、实操总结与易错点复盘

本篇我们完成了微服务容器化部署的核心实操,实现了 “一次打包、一键部署”,核心收获如下:

  1. Docker 镜像构建核心:
  • 核心流程:编写 Dockerfile → 打包微服务 jar 包 → 构建镜像 → 验证镜像;
  • 关键知识点:基础镜像选择轻量版(Alpine)、容器内访问其他服务用 “服务名:端口”、暴露端口需和微服务一致;
  • 核心价值:镜像包含完整运行环境,解决 “环境不一致” 问题;
  1. Compose 编排核心:
  • 核心流程:编写 docker-compose.yml → 定义网络 / 数据卷 / 服务 → 一键启动 → 验证效果;
  • 关键知识点:所有服务在同一网络可通过服务名访问、数据卷实现持久化、depends_on定义服务依赖顺序;
  • 核心价值:一键启动所有服务,解决 “部署繁琐” 问题,提升部署效率;

新手必看易错点(重点避坑)

  1. 镜像构建失败:未执行mvn package打包 jar 包,或 Dockerfile 中COPY路径错误,需确保 jar 包在target目录;
  2. 容器内访问 Nacos 失败:启动命令中 Nacos 地址写localhost:8848(容器内localhost≠宿主机),需改为nacos:8848;
  3. ES 启动失败:内存配置不足,需在docker-compose.yml中设置ES_JAVA_OPTS=-Xms512m -Xmx512m;
  4. 服务依赖顺序错误:比如 gateway-service 先于 order-service 启动,导致网关无法注册,需通过depends_on定义依赖;
  5. 日志收集失败:Filebeat 挂载的日志目录路径错误,需确保宿主机日志目录正确映射到容器内;
  6. 端口冲突:宿主机端口被占用(如 8848 被本地 Nacos 占用),需关闭本地服务或修改 Compose 端口映射。

七、下一篇预告

本篇我们完成了微服务的容器化部署,解决了 “部署繁琐、环境不一致” 的核心痛点,让微服务集群具备了 “一键部署” 的能力。下一篇将讲解微服务进阶的核心痛点 ——分布式事务(Seata)实操,教大家解决 “跨服务数据一致性” 问题(比如下单扣库存时订单创建成功但库存扣减失败),实现微服务数据的最终一致性,筑牢生产环境的数据安全防线!
如果这篇实操教程对你有帮助,欢迎点赞、收藏、关注,实操过程中遇到任何问题(比如镜像构建失败、Compose 启动报错、容器间通信失败),都可以在评论区留言,我会逐一回复,帮大家解决新手踩坑问题~

更多推荐