CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Docker 容器入门/课时/Docker Compose
RawBlame
课时目录12 节

Docker 容器入门

  1. 01容器是什么
  2. 02安装与环境
  3. 03Docker CLI 基础
  4. 04镜像与分层
  5. 05编写 Dockerfile
  6. 06构建与优化
  7. 07镜像仓库
  8. 08数据卷与挂载
  9. 09网络
  10. 10Docker Compose
  11. 11容器安全基础
  12. 12综合练习与 K8s 方向

Docker Compose

多容器编排、backend + MySQL 一键起。

40 分钟

Docker Compose

这一课你将能做到

  1. 把 Spring Boot + MySQL + Redis 三个容器写进一份 docker-compose.yml,用 docker compose up -d 一键拉起整个后端环境
  2. 用 healthcheck + depends_on 解决「MySQL 还没就绪 Spring Boot 就启动」的经典时序问题
  3. 熟练使用 compose 的日常命令:up/down/logs/ps/exec,并掌握改代码后的标准更新流程

为什么要学

前 9 课里,为了跑通一个后端环境你敲了多少条命令:建网络、起 MySQL(带卷)、起 Redis(带密码)、起应用(带一长串 -e)……每次重启机器都要来一遍,参数靠翻历史记录。Compose 把这些全部固化成一个 YAML 文件:环境即代码,一键复现,提交进 git 团队共享。

生产上 compose 同样有用武之地:单机部署的中小项目(一台云服务器跑全套)用它管理服务最省心;它也是从「手动 docker run」迈向 K8s 之前的最后一站——你在这课养成的「服务、健康检查、依赖编排」概念,全部可以平移到 K8s。

先建立图像

一份 compose 文件 = 你前 9 课所有 docker run 参数的声明式版本:

命令式(前面课程):                声明式(compose):
docker network create app-net      services: 定义每个容器
docker run ... mysql        →     volumes: 定义数据卷
docker run ... redis        →     networks: 定义网络
docker run ... -e ... app   →     depends_on: 定义启动顺序与就绪条件

docker compose up -d = 按声明一次性对齐现实

文件结构五要素:

services:     # 每个容器一个服务,服务名即 DNS 名
volumes:      # 声明 named volume
networks:     # 声明网络
environment:  # 环境变量注入
depends_on:   # 启动依赖与就绪条件

跟着做

步骤 1:编写 docker-compose.yml

放在项目根目录(与 Dockerfile 同级)。这份配置直接可用:

services:
  mysql:
    image: mysql:8.0
    container_name: app-mysql
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: appdb
    volumes:
      - mysql-data:/var/lib/mysql
    networks:
      - app-net
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-p${MYSQL_ROOT_PASSWORD}"]
      interval: 5s
      timeout: 3s
      retries: 12
      start_period: 30s
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    container_name: app-redis
    command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}"]
    networks:
      - app-net
    volumes:
      - redis-data:/data
    restart: unless-stopped

  app:
    build: .                      # 用当前目录 Dockerfile 构建
    image: demo-app:1.0           # 构建后的镜像名
    container_name: app-backend
    ports:
      - "8080:8080"
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/appdb
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      SPRING_DATA_REDIS_HOST: redis
      SPRING_DATA_REDIS_PASSWORD: ${REDIS_PASSWORD}
    depends_on:
      mysql:
        condition: service_healthy    # 等 MySQL 健康检查通过才启动
      redis:
        condition: service_started
    networks:
      - app-net
    restart: unless-stopped

volumes:
  mysql-data:
  redis-data:

networks:
  app-net:

注意:服务间连接用服务名(mysql、redis),不是 container_name。Compose 自动创建网络并内置 DNS。

步骤 2:编写 .env 管理密码

同目录新建 .env:

MYSQL_ROOT_PASSWORD=StrongPass_2024
REDIS_PASSWORD=RedisDev_2024

.gitignore 里加上 .env,另提交一份 .env.example(只有 key 无 value)给同事参考。密码永远不进 git。

步骤 3:一键启动

docker compose up -d
docker compose ps          # 三个服务都应显示 running,mysql 显示 (healthy)
docker compose logs -f app # 盯着 Spring Boot 启动日志
curl http://localhost:8080/actuator/health

第一次会自动构建 app 镜像。depends_on: service_healthy 保证了 MySQL 完全就绪后 app 才启动——本课最关键的一处配置。

步骤 4:常用命令速练

docker compose logs --tail 50 mysql    # 看单个服务日志
docker compose exec mysql mysql -uroot -pStrongPass_2024   # 进 MySQL
docker compose restart app             # 重启单个服务
docker compose stop                    # 全部停止(容器保留)
docker compose start                   # 全部启动
docker compose down                    # 停止并删除容器与网络(卷保留!)
docker compose down -v                 # 连卷一起删(数据没了,生产禁用)

步骤 5:改代码后的标准更新流程

mvn clean package -DskipTests       # ① 本地(或 CI)出新 jar
docker compose up -d --build app    # ② 只重建并替换 app 服务,mysql/redis 不动
docker compose logs -f app          # ③ 验证

up -d --build 只会影响配置或镜像发生变化的服务——这也是 compose 的编排价值:改一个服务,不用重建整个环境。

步骤 6:多环境配置(了解机制)

Compose 支持 override 合并:docker-compose.yml 放基础配置,docker-compose.override.yml 自动叠加开发差异;或显式多文件:

docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

生产差异(资源限制、log 策略)放 override 文件,基础文件保持团队一致。

讲清楚要点

  1. 服务名 = DNS 名 = Spring Boot 里的主机名:SPRING_DATASOURCE_URL 写 jdbc:mysql://mysql:3306/...,mysql 是服务名。container_name 只是容器别名,跨服务连接一律用服务名。
  2. depends_on 有两种深度:默认只管「启动顺序」(容器进程起了就算);condition: service_healthy 才管「就绪顺序」(健康检查通过才算)。数据库类服务必须用后者,否则 Spring Boot 大概率抢跑失败。
  3. down 与 down -v 的天壤之别:down 删容器和网络、保留卷(数据安全);down -v 连卷一起删(数据清零)。把 down -v 当成 drop database 级别的危险操作对待。
  4. restart: unless-stopped 的工程意义:进程崩溃自动拉起、宿主机重启后自动恢复(除非你手动 stop 过)。单机生产部署的可用性底线。
  5. compose 会给资源加项目前缀:目录名(如 demo)成为项目名,卷名实际是 demo_mysql-data、网络是 demo_app-net。换目录执行命令会操作到「另一个项目」——在 compose 文件所在目录操作最稳。
  6. Compose 是单机编排:它不知道另一台服务器的存在。多机、自动扩缩容、滚动发布,是 K8s 的领域(第 12 课的桥就架在这里)。

你可能会懵的地方

  • MySQL 健康检查为什么用 mysqladmin ping? 它探活 MySQL 进程是否响应,成本低且不需要业务表。更严格的场景可以改成执行一条 SELECT 1。注意 start_period 要给足首次初始化时间(导入初始数据可能要几十秒)。

  • app 启动还是报连不上 MySQL,怎么办? 三步排查:docker compose ps 看 mysql 是否 (healthy);docker compose logs app 看连接错误细节;进 app 容器验证 DNS:docker compose exec app getent hosts mysql。高频根因是 healthcheck 没配或密码变量没注入(.env 缺失)。

  • build: . 和 image: 同时写是什么意思? build 指定怎么构建;image 给构建结果命名。两者同写时,up --build 会构建并打上该镜像名;不写 image 则自动命名为 项目名-服务名。

  • 为什么我换了目录,compose 说找不到服务? 项目按目录绑定。切到别的目录执行 docker compose down 操作的是那个目录的项目(或报无服务)。固定在 yml 所在目录操作,或用 -p 项目名 显式指定。

  • compose 能做生产部署吗? 单机中小项目完全可以(配合 restart 策略 + 卷备份 + 日志限制),很多公司内部系统就这么跑。需要多机高可用、滚动发布、自动扩缩容时,再上 K8s——compose 里的 service/volume/healthcheck 概念全部平移。

错法对照

错法问题正解
depends_on 只写服务名只保证顺序,MySQL 未就绪 app 抢跑崩condition: service_healthy + healthcheck
Spring Boot URL 写 jdbc:mysql://app-mysql:...(container_name)跨服务应该用服务名写服务名 mysql
密码明文写进 compose 并提交 git凭据泄漏.env + .gitignore + .env.example
以为 down 会删数据,或以为 down 后数据还在就放心 down -v前者过度担心,后者真删数据记住:down 保卷,down -v 删卷
YAML 缩进用 Tab解析报错一律空格,建议编辑器装 yaml 校验
改代码后 down + up 全量重建MySQL/Redis 也重启,浪费时间up -d --build app 只更新 app

卡点急救

  1. docker compose 命令不存在:老版用法是 docker-compose(带横线)。装了 docker-compose-plugin 后统一用 docker compose(空格),docker compose version 验证。
  2. up 时报变量为空警告:.env 文件不在 compose 文件同目录,或变量名拼写不一致。docker compose config 可以预渲染最终配置,直接看变量是否注入。
  3. app 反复重启(Restarting 状态):通常是连不上数据库崩了又被 restart 拉起。先看 docker compose logs app 的第一次报错,再按「步骤 6 排查三步」走。
  4. 端口 8080 被宿主机占用:compose 的 ports 改成 "8081:8080",或停掉占用进程(netstat -ano | findstr 8080)。
  5. 误执行了 down -v 数据没了:只剩备份可救——执行第 8 课的恢复流程把备份卷挂回来。养成「down 前看一眼命令结尾」的习惯。

面试常问

  • Compose 解决什么问题?和直接 docker run 比优势在哪? 把多容器拓扑(服务、网络、卷、依赖、环境变量)声明进一个 YAML,实现环境即代码:一键 up/down、版本化进 git、团队一键复现。对比手敲 docker run:无遗漏参数、可重复、可审查。

  • depends_on 如何保证 MySQL 就绪后应用再启动? depends_on 默认只控制容器启动顺序;需要配合服务端 healthcheck + condition: service_healthy,让依赖方等健康检查通过后再启动。应用侧再加连接重试/重启策略做双保险。

  • Compose 和 Kubernetes 的定位区别? Compose 面向单机编排,简单直接,适合开发环境与单机部署;K8s 面向多机集群,提供调度、自愈、扩缩容、滚动发布、服务发现。K8s 没有「主机名直连」而是 Service 抽象,但健康检查、声明式配置思想一脉相承。

  • 生产上如何管理 compose 的敏感配置? 密码放 .env(不入 git)或部署机手写的环境文件;更严格用 docker secrets(swarm)或外部配置中心(Nacos/Vault)。镜像里出现任何明文密钥都是事故。

自测三问

  1. 写出「等 MySQL 健康后才启动 app」的完整 compose 配置片段(含 healthcheck)。
  2. docker compose down 和 down -v 分别删除什么?restart: unless-stopped 补上了什么能力?
  3. 改了一行 Java 代码,写出把新版本部署到 compose 环境的完整命令序列。

小结一句话

Compose 把「一堆 docker run 参数 + 网络 + 卷 + 依赖时序」收进一份可版本化的 YAML——服务名即 DNS、healthcheck 管就绪、down 不碰卷,是单机编排的完整答案。

延伸

  • Compose 官方文档
  • 下一课预告:容器安全基础——非 root 运行、密钥管理、镜像扫描,把「能跑」升级成「敢上生产」。
加载本节练习…
← 上一课网络下一课 →容器安全基础