容器化部署:服务镜像与 docker compose 编排要点

微服务最终要跑在容器里,才能获得一致的运行环境与可复制的部署。Spring Boot 应用容器化很简单,但“能跑”和“生产可跑”之间有不少要点:镜像怎么建、Compose 怎么编排、健康检查怎么做。

构建服务镜像

Spring Boot 应用构建镜像,最省事的是把可执行 jar 放进 JRE 镜像。注意不要用体积巨大的 JDK 全量镜像,基础镜像尽量小。

# Dockerfile(示例:Java 17 + Boot 3)
FROM eclipse-temurin:17-jre
WORKDIR /app
# 利用 Spring Boot 分层 jar,先拷依赖层再拷业务层,提高构建缓存命中
COPY target/order-service-1.0.0.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-XX:MaxRAMPercentage=75.0", "-jar", "app.jar"]

要点:

  • 通过 spring-boot-maven-plugin 生成分层(layered)jar 后,可用 COPY --from 只复制需要的层,实现“依赖没变就不重新拉层”的加速。
  • 设置 JVM 内存比例参数(-XX:MaxRAMPercentage)让容器内的 JVM 感知容器配额,避免 OOM 与资源浪费。
  • 每个服务一个镜像仓库地址 + 版本标签,如 registry.example.com/order-service:20250601-1,标签唯一且可追溯源码提交。
# 构建与推送示意(示例仓库地址)
docker build -t registry.example.com/order-service:1.0.0 ./order-service
docker push registry.example.com/order-service:1.0.0

docker compose 编排

本地开发或小规模部署时,用 compose 一键拉起整套环境:注册中心、数据库、Redis 与各服务。

services:
  nacos:
    image: nacos/nacos-server:v2.3.2   # 教程锚点 Nacos 3.x,2.x 亦可运行,tag 以官方为准
    ports: ["8848:8848", "9848:9848"]
    environment:
      MODE: standalone
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8848/nacos/v1/console/health/readiness"]
      interval: 10s
      retries: 10
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: example
    volumes: ["mysql-data:/var/lib/mysql"]
  order-service:
    build: ./order-service
    depends_on:
      nacos: { condition: service_healthy }
      mysql: { condition: service_started }
    environment:
      SPRING_PROFILES_ACTIVE: docker
      SPRING_CLOUD_NACOS_SERVER_ADDR: nacos:8848
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/order_db?useSSL=false
    ports: ["8081:8080"]
volumes:
  mysql-data:

编排要点:

  • 容器间用服务名互访(nacos:8848),不写死 IP;应用配置通过环境变量注入,配置文件里不留明文口令。
  • depends_on 只保证启动顺序,不代表依赖“就绪”,配合 healthcheck 的 condition: service_healthy 才可靠。
  • 配置差异用 profile 或环境变量区分(本地/测试/生产),镜像本身不区分环境。
  • 日志统一输出到 stdout,交给 docker 日志驱动或采集器,不要写容器内文件。

镜像瘦身与安全

  • 优先官方维护的基础镜像并固定版本 tag;定期升级修补 CVE。
  • 容器内以非 root 用户运行(如 USER app),减小被攻破后的影响面。
  • 不需要的构建产物(源码、.m2 缓存)不进镜像,用 .dockerignore 排除 target/.git/
  • 同时给每个服务配资源限额(compose 的 deploy.resources.limits 或 k8s 的 requests/limits),防止单个服务吃光宿主机。

从 compose 走向编排平台

compose 适合单机与小规模验证;当需要多副本、自动伸缩、滚动发布时,就迁移到 Kubernetes 等编排平台(见 Kubernetes 章节)。迁移时保持“镜像与运行环境解耦、配置外置、无状态化”这三条原则,容器化阶段的投入才不会白费。

小结

容器化的关键是产出一致的镜像与声明式的编排:Dockerfile 负责把应用和环境打包,compose 负责把多服务拓扑管起来,环境变量负责把配置差异隔离出去。先在本机用 compose 跑通整套调用链,再谈上编排平台。

笔记加载中…