Skip to content

Docker Compose

简介

docker-compose 是用于定义和运行多容器 Docker 应用的工具,通过一个 docker-compose.yml 文件统一管理多个服务的启动、网络和数据卷。

Docker Compose V2 已内置于 Docker CLI,使用 docker compose(无连字符)命令

安装

Docker Desktop(macOS/Windows)已内置 Docker Compose V2,无需单独安装。

Linux 服务器推荐通过插件方式安装(随 Docker CE 一起带入):

bash
# CentOS/RHEL(添加 Docker CE 源后)
yum install -y docker-compose-plugin

# Ubuntu/Debian
apt-get install -y docker-compose-plugin

# 验证
docker compose version

如需手动安装独立二进制文件(备选):

bash
# 自动获取当前系统架构对应的二进制文件
curl -SL "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" \
  -o /usr/local/bin/docker-compose

chmod +x /usr/local/bin/docker-compose
docker-compose --version

Docker Compose V1(docker-compose,有连字符)已于 2023 年 7 月停止维护,推荐使用 V2(docker compose

常用命令

bash
# 启动
docker compose up            # 前台启动所有服务
docker compose up -d         # 后台启动所有服务
docker compose up -d <服务> # 后台启动指定服务

# 重建并启动(代码变更后使用)
docker compose up -d --build
docker compose up -d --build <服务>

# 查看
docker compose ps            # 查看服务状态
docker compose logs -f       # 跟踪所有服务日志
docker compose logs -f <服务> # 跟踪指定服务日志

# 进入容器(交互式 shell)
docker compose exec <服务> bash

# 在容器内执行单条命令(不进入交互模式)
docker compose exec <服务> <>
docker compose exec nginx nginx -s reload  # 平滑重载 Nginx 配置(不中断连接)

# 停止 / 删除
docker compose stop          # 停止所有服务(保留容器和网络)
docker compose start         # 重新启动已停止的服务
docker compose down          # 停止并删除容器、网络
docker compose down -v       # 同时删除数据卷

# 删除指定服务容器(网络不会删除)
docker compose rm <服务>

配置文件说明

yml
services: # 服务集合,每个服务对应一个容器
  app: # 服务名,自定义,同网络内其他服务通过此名访问
    image: node:22 # 使用现有镜像(与 build 互斥)
    build: # 从 Dockerfile 构建镜像
      context: ./app # 构建上下文目录
      dockerfile: Dockerfile
    restart: unless-stopped # 重启策略:always / no / on-failure / unless-stopped
    # 生产建议用 unless-stopped 代替 always,避免错误状态下无限重启
    ports:
      - '3000:3000' # 宿主机端口:容器端口
    volumes:
      - ./app:/code # 绑定挂载(宿主机目录:容器目录)
      - app_logs:/var/log # 具名数据卷,卷名对应下方 volumes 顶级声明
    environment:
      - NODE_ENV=production
      - TZ=Asia/Shanghai
    command: node index.js # 覆盖默认 CMD
    depends_on: # 仅控制启动顺序,不保证依赖服务已就绪
      - db
    # 若需等待依赖服务真正就绪(如等 MySQL 启动完毕),用 condition 写法:
    # depends_on:
    #   db:
    #     condition: service_healthy  # 需要依赖服务配置 healthcheck
    networks:
      - app_net

volumes: # 顶级声明,等同于提前执行 docker volume create
  app_logs: # 值为空表示使用默认驱动(local),Docker 自动管理存储位置
  # 若需指定驱动或选项:
  # app_logs:
  #   driver: local

networks: # 声明自定义网络(等同于 docker network create)
  app_net:
    driver: bridge
  external_net: # 引用外部已存在的网络(如另一个 compose 创建的)
    external: true
    name: shared_network # compose down 时不会删除此网络

同一 compose 网络内,服务之间直接通过服务名 + 端口访问,如 mysql:3306redis:6379


服务间通信(关键)

同一 compose 项目内,服务之间以服务名作为主机名,以容器内端口(非宿主机映射端口)互相访问。

Nginx 反向代理到 Node 服务nginx/config/default.conf):

nginx
server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://server:3000;  # server 是 compose 服务名,3000 是容器内端口
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

应用服务通过服务名连接数据库

yml
services:
  server:
    environment:
      - MYSQL_HOST=mysql   # "mysql" 是 compose 服务名
      - MYSQL_PORT=3306    # 容器内端口,不是宿主机映射端口
      - REDIS_HOST=redis   # "redis" 是 compose 服务名
      - REDIS_PORT=6379

更改服务名时,所有通过该服务名访问它的地方(nginx 配置、环境变量等)都需要同步修改


restart 重启策略

行为适用场景
no容器退出后不自动重启(默认值)开发调试
always无论何种退出原因,始终重启;docker 重启后也会启动需要开机自启的服务
on-failure仅在非零退出码(错误退出)时重启,正常退出不重启批处理任务
unless-stoppedalways 类似,但手动 docker stop 后不再自启生产服务(推荐)

生产环境推荐 unless-stopped:手动停止容器维护时不会被自动拉起,而 always 会在重启 Docker 服务后强制恢复所有容器。

完整配置示例

Node 服务 + Nginx + MySQL + Redis 的典型生产配置:

yml
services:
  server:
    build:
      context: ./server
      dockerfile: Dockerfile
    restart: always
    networks:
      - myweb
    env_file:
      - .env # 从 .env 文件读取环境变量,避免密码明文写入版本控制
    environment:
      - TZ=Asia/Shanghai
      - MYSQL_HOST=mysql
      - MYSQL_USERNAME=root
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
      - MYSQL_DATABASE=mydb
      - REDIS_HOST=redis
      - REDIS_PASSWORD=${REDIS_PASSWORD}

  nginx:
    image: nginx:stable
    restart: always
    ports:
      - '80:80'
      - '443:443'
    networks:
      - myweb
    volumes:
      - ./nginx/config:/etc/nginx/conf.d
      - ./nginx/cert:/etc/nginx/cert
      - ./nginx/logs:/var/log/nginx
      - ./nginx/html:/usr/share/nginx/html
    environment:
      - TZ=Asia/Shanghai
    depends_on:
      - server

  mysql:
    image: mysql:8.4
    restart: always
    ports:
      - '3306:3306'
    networks:
      - myweb
    volumes:
      - ./mysql/data:/var/lib/mysql
      - ./mysql/log:/var/log/mysql
      - ./mysql/init:/docker-entrypoint-initdb.d
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD}
      - TZ=Asia/Shanghai
    healthcheck:
      test: ['CMD', 'mysqladmin', 'ping', '-h', 'localhost', '-u', 'root', '-p${MYSQL_PASSWORD}']
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

  redis:
    image: redis:7
    restart: always
    ports:
      - '6379:6379'
    networks:
      - myweb
    volumes:
      - ./redis/conf/redis.conf:/etc/redis/redis.conf
      - ./redis/data:/data
    command: redis-server /etc/redis/redis.conf

networks:
  myweb:
    driver: bridge

关于 .env 文件:docker-compose.yml 同目录创建 .env 文件,Docker Compose 会自动加载其中的变量。.env 应加入 .gitignore,避免密码泄露。

bash
# .env 文件示例
MYSQL_PASSWORD=你的密码
REDIS_PASSWORD=你的密码

跨 compose 服务通信

当多个 docker-compose.yml 分别管理基础服务和应用服务时,可通过引用外部网络实现跨 compose 通信:

yml
# 基础服务的 compose(先启动)
networks:
  myweb:
    driver: bridge
yml
# 应用服务的 compose
networks:
  myweb:
    external: true
    name: myweb # 引用基础服务创建的网络

通信时同样使用服务名,如 Nginx 反向代理到 Node 服务:

nginx
location / {
    proxy_pass http://server:3000;  # server 是 compose 中的服务名
}

项目目录结构建议

project/
├── docker-compose.yml
├── server/                # Node 服务
│   ├── Dockerfile
│   ├── package.json
│   └── src/
├── nginx/
│   ├── config/            # nginx 配置文件
│   │   └── default.conf
│   ├── cert/              # SSL 证书
│   └── logs/
├── mysql/
│   ├── data/              # 数据持久化
│   ├── log/
│   └── init/              # 初始化 SQL 文件
└── redis/
    ├── conf/
    │   └── redis.conf
    └── data/

如果服务较多,建议将 MySQL、Nginx、Redis 等基础服务拆分为一个 docker-compose.base.yml,应用服务单独一个,通过外部网络连通

Vue 项目部署

Vue 是静态页面,推荐用多阶段构建直接产出 Nginx 镜像,无需在服务器安装 Node 环境:

dockerfile
# 构建阶段
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# 生产阶段
FROM nginx:stable-alpine
COPY --from=builder /app/dist /usr/share/nginx/html
# 若使用 Vue Router history 模式,需拷贝自定义 nginx 配置
# COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

若使用 Vue Router history 模式,需创建以下 nginx.conf

nginx
server {
    listen 80;
    root /usr/share/nginx/html;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;  # 关键:所有路由回退到 index.html
    }
}
bash
# 构建并运行
docker build -t my-vue-app .
docker run -d -p 80:80 my-vue-app

try_files $uri $uri/ /index.html 是 Nginx 支持 Vue Router history 模式的关键配置,使用哈希模式(createWebHashHistory)则不需要

待补充

  • [ ] Compose 与 Docker Swarm 的关系
  • [ ] depends_on: condition: service_healthy 等待依赖就绪

持续学习,持续成长