Skip to content
第 5 章 运维 ⏱ 12 分钟阅读

第 5 章:Docker Compose ​

学习目标 ​

  • 用 docker-compose.yml 编排多容器
  • 掌握 up / down / logs 等命令
  • 配置网络、卷、环境变量
  • 避开依赖启动顺序和重启策略坑

一、docker-compose.yml 最小例 ​

yaml
# docker-compose.yml
version: "3.9"

services:
  web:
    image: nginx:1.25-alpine
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro
    restart: unless-stopped

  api:
    build: ./api                       # 用当前目录 api/ 的 Dockerfile 构建
    ports:
      - "3000:3000"
    environment:
      NODE_ENV: production
      DB_HOST: db                       # 引用服务名
    depends_on:
      - db
    restart: unless-stopped

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: rootpw
      MYSQL_DATABASE: appdb
    volumes:
      - dbdata:/var/lib/mysql
    restart: unless-stopped

volumes:
  dbdata:                               # 命名卷

二、核心命令 ​

bash
# 在 docker-compose.yml 同目录
docker compose up -d              # -d 后台
docker compose up --build         # 重新构建再起
docker compose ps                 # 看状态
docker compose logs -f api        # 实时日志(后面接服务名)
docker compose logs --tail 50     # 最近 50 行
docker compose exec api bash     # 进容器
docker compose restart web        # 重启单个
docker compose down               # 停掉并删容器、网络
docker compose down -v            # 连卷一起删(危险,慎用)
docker compose config             # 校验 yml + 看解析后的最终配置

⚠️ 坑 1:docker compose(新版,空格)是 Docker Desktop / 新版 Docker CLI 自带。docker-compose(连字符)是独立的 Python 工具,已停更。统一用 docker compose。

三、depends_on 不等于就绪 ​

yaml
services:
  api:
    depends_on:
      db:
        condition: service_healthy   # 等 db 健康才起
  db:
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 5s
      timeout: 3s
      retries: 10

⚠️ 坑 2:depends_on 只控制启动顺序,不等待服务就绪。MySQL 容器启动了但还要几秒初始化,api 起来连不上。不加 condition: service_healthy 的依赖,经常见到明明写了 depends_on 还是连不上数据库。

四、环境变量与 .env 文件 ​

yaml
services:
  api:
    image: myapi
    environment:
      DB_HOST: ${DB_HOST:-db}        # ${VAR:-default},带默认值
      DB_PORT: ${DB_PORT:-3306}
      DEBUG: ${DEBUG}                # 来自 .env
    env_file:
      - .env.production              # 整个文件载入

.env(同目录,docker compose 自动加载):

DEBUG=false
DB_HOST=mysql.prod.internal
DB_PORT=3306

⚠️ 坑 3:.env 文件只支持 KEY=VALUE 格式,不支持 export。写成 export FOO=bar 会报错或被忽略。

五、网络与卷细节 ​

yaml
services:
  api:
    networks:
      - backend

  web:
    networks:
      - frontend
      - backend                       # 网关角色跨两个网

networks:
  backend:
    driver: bridge
  frontend:
    driver: bridge

volumes:
  dbdata:
    driver: local
  shared:                             # 多服务共享

⚠️ 坑 4:跨 compose 文件用 external 网络,否则容器之间互相找不到:

yaml
networks:
  shared-net:
    external: true
    name: my-shared-network

六、重启策略 ​

yaml
services:
  web:
    restart: no                       # 默认,不自动重启
  api:
    restart: always                   # 永远重启
  worker:
    restart: on-failure               # 退出码非 0 才重启
    deploy:
      resources:
        limits:
          memory: 512M

⚠️ 坑 5:开发环境别用 restart: always,否则改了代码忘重启就一直跑老版本。生产用 always,开发用 no 或干脆不用 compose。

七、profiles(分组启动) ​

yaml
services:
  web:
    image: nginx
    profiles: [frontend]              # 只在 frontend 组启动

  mysql:
    image: mysql
    profiles: [backend]

  redis:
    image: redis
    profiles: [backend]               # backend 组包含两个服务

  adminer:
    image: adminer
    profiles: [tools]                 # 调试工具单独组
bash
docker compose --profile frontend up        # 只起 web
docker compose --profile backend up         # mysql + redis
docker compose --profile backend --profile tools up

⚠️ 坑 6:带 profiles 的服务 docker compose up 默认不起,必须显式 --profile。忘加参数起不来,不在服务列表里看清楚就懵。

八、实战:完整 Spring Boot + DB ​

yaml
services:
  app:
    build: .
    image: myapp:1.0
    container_name: myapp
    ports:
      - "8080:8080"
    environment:
      SPRING_PROFILES_ACTIVE: prod
      DB_HOST: mysql
      DB_PORT: "3306"
      DB_NAME: appdb
      DB_USER: appuser
      DB_PWD: apppass
    depends_on:
      mysql:
        condition: service_healthy
    restart: unless-stopped
    networks:
      - appnet

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: rootpw
      MYSQL_DATABASE: appdb
      MYSQL_USER: appuser
      MYSQL_PASSWORD: apppass
    volumes:
      - mysql-data:/var/lib/mysql
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-prootpw"]
      interval: 5s
      timeout: 3s
      retries: 20
    networks:
      - appnet

volumes:
  mysql-data:

networks:
  appnet:
bash
docker compose up -d --build        # 第一次构建 + 跑
docker compose logs -f app          # 看 app 启动日志

九、本章小结 ​

命令作用
up -d后台启动
down -v停 + 删卷
logs -f实时日志
exec进容器
--profile分组启动
depends_on + healthcheck控制真正启动顺序

动手练习 ​

  1. 用 compose 拉起 nginx + 一个静态页面,浏览器访问成功
  2. 加 MySQL + 健康检查,Spring Boot 应用通过服务名连 MySQL
  3. 用 profiles 分前端 / 后端两套环境
  4. docker compose down -v 后再 up -d,数据是否还在?(命名卷持久)

下一章:第 6 章:Kubernetes 入门 →

本站基于 VitePress 构建 · 由 StackHub 团队维护