Docker Compose 从入门到实战:核心概念、YAML 配置详解、常用命令与多容器部署

Docker Compose 从入门到实战:核心概念、YAML 配置详解、常用命令与多容器部署

前言: 在实际开发中,一个完整的项目往往不只有一个应用,还可能依赖 MySQL、Redis、Nginx 等多个服务。如果使用 docker run 命令逐个启动和管理容器,不仅操作繁琐,还需要手动处理网络、数据持久化和服务依赖等问题。

Docker Compose 就是为了解决这类问题而设计的。通过一个 YAML 配置文件,我们可以定义多个服务,并通过简单的命令完成整个项目的创建、启动、停止和管理。

本文将从 Docker Compose 的基本概念开始,详细介绍常用配置参数、容器通信机制、数据持久化、服务依赖以及实际部署案例,帮助大家系统掌握 Docker Compose。

一、Docker Compose 简介

1.1 什么是 Docker Compose?

Docker Compose 是 Docker 官方提供的多容器应用定义和管理工具。

它允许我们使用一个 YAML 文件描述应用所需要的各个服务,包括:

  • 容器使用的镜像
  • 容器端口映射
  • 环境变量
  • 数据卷挂载
  • 容器网络
  • 启动依赖
  • 重启策略
  • 健康检查

然后使用一条命令:

bash 复制代码
docker compose up -d

就可以创建并启动整个项目。

一句话理解:Docker Compose 就是通过配置文件统一管理多个 Docker 容器。

1.2 为什么需要 Docker Compose?

假设我们正在开发一个 Java Web 项目,需要运行三个服务:

text 复制代码
Java Web 应用
     |
     |---- MySQL 数据库
     |
     |---- Redis 缓存

如果直接使用 Docker,我们可能需要分别执行:

bash 复制代码
# 启动 MySQL
docker run -d \
  --name mysql \
  -e MYSQL_ROOT_PASSWORD=123456 \
  -p 3306:3306 \
  mysql:8.4

# 启动 Redis
docker run -d \
  --name redis \
  -p 6379:6379 \
  redis:7

# 启动 Java 应用
docker run -d \
  --name java-app \
  -p 8080:8080 \
  my-java-app:1.0

随着服务数量增加,命令会越来越复杂。

我们还需要考虑网络配置、服务依赖、数据存储以及容器重启等问题。

使用 Docker Compose 后,可以统一编写配置:

yaml 复制代码
services:
  mysql:
    image: mysql:8.4
    environment:
      MYSQL_ROOT_PASSWORD: example-password

  redis:
    image: redis:7

  app:
    image: my-java-app:1.0
    ports:
      - "8080:8080"

然后执行:

bash 复制代码
docker compose up -d

即可统一启动这些服务。

注意:以上只是用于说明 Compose 配置结构的简化示例,实际项目还需要配置数据库持久化、账号密码等内容。

1.3 Docker、Dockerfile、Docker Compose 的区别

这三个概念经常一起出现,但职责不同。

工具 核心作用
Docker 构建镜像、创建和运行容器
Dockerfile 定义如何构建 Docker 镜像
Docker Compose 定义并管理多容器应用

例如,我们有一个 Spring Boot 项目。

首先通过 Dockerfile 构建应用镜像:

dockerfile 复制代码
FROM eclipse-temurin:21-jre

WORKDIR /app

COPY app.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]

构建镜像:

bash 复制代码
docker build -t my-java-app:1.0 .

也可以在 Compose 中指定构建方式:

yaml 复制代码
services:
  app:
    build: .
    ports:
      - "8080:8080"

执行:

bash 复制代码
docker compose up -d --build

Compose 会根据 Dockerfile 构建应用镜像,并创建和启动容器。

因此:

  • Dockerfile 负责描述镜像如何构建。
  • Docker 负责构建镜像和运行容器。
  • Docker Compose 负责组织和管理多个容器。

二、Docker Compose 的核心概念

学习 Docker Compose,需要重点理解四个概念。

2.1 Service(服务)

Service 是 Docker Compose 最核心的概念。

一个 Service 用于描述一类容器应该如何运行。

例如:

yaml 复制代码
services:
  mysql:
    image: mysql:8.4

  redis:
    image: redis:7

这里定义了两个服务:

  • mysql
  • redis

每个服务都可以配置镜像、端口、环境变量、网络和数据卷等信息。

2.2 Container(容器)

Container 是服务实际运行的实例。

例如:

yaml 复制代码
services:
  redis:
    image: redis:7

当执行:

bash 复制代码
docker compose up -d

Compose 会为 Redis 服务创建并启动容器。

需要注意:

Service 是服务定义,Container 是实际运行的容器实例。

一个服务也可以运行多个容器副本。

2.3 Network(网络)

Docker Compose 中的不同容器通常需要相互通信。

例如:

text 复制代码
Spring Boot → MySQL
Spring Boot → Redis

Compose 默认会为项目创建一个网络。

处于同一个 Compose 网络中的服务,可以使用服务名称相互访问。

例如:

text 复制代码
mysql:3306
redis:6379

这里的 mysql 和 redis 都是服务名称。

2.4 Volume(数据卷)

容器通常具有临时性。

如果数据库文件只保存在容器的可写层,那么删除容器时,这部分数据也可能丢失。

为了解决这个问题,我们可以使用 Volume 实现数据持久化。

例如:

yaml 复制代码
services:
  mysql:
    image: mysql:8.4
    volumes:
      - mysql-data:/var/lib/mysql

volumes:
  mysql-data:

这里定义了一个名称为 mysql-data 的数据卷。

MySQL 的数据目录会保存到该数据卷中。

即使数据库容器被删除并重新创建,只要继续使用这个数据卷,数据就可以保留。


三、Docker Compose 配置文件详解

Docker Compose 通常使用以下文件名:

text 复制代码
compose.yaml

也可以使用:

text 复制代码
compose.yml
docker-compose.yml
docker-compose.yaml

其中 compose.yaml 是现代 Compose 推荐的文件名。

下面介绍工作中常见的配置参数。

3.1 services:定义服务

yaml 复制代码
services:
  nginx:
    image: nginx:alpine

  redis:
    image: redis:7

services 用来定义项目中的所有服务。

其下一级的 nginx 和 redis 是服务名称。

3.2 image:指定镜像

yaml 复制代码
image: nginx:alpine

镜像通常遵循以下格式:

text 复制代码
镜像名称:标签

例如:

yaml 复制代码
image: mysql:8.4
image: redis:7
image: nginx:alpine

建议实际项目尽量固定经过测试的镜像版本,而不是直接依赖 latest 标签。

3.3 container_name:指定容器名称

yaml 复制代码
services:
  nginx:
    image: nginx:alpine
    container_name: my-nginx

启动后,容器名称为:

text 复制代码
my-nginx

如果不指定,Compose 会根据项目名、服务名和实例序号自动生成名称。

例如:

text 复制代码
myproject-nginx-1

实际开发中,通常可以不配置 container_name。固定容器名可能造成不同项目间的命名冲突,也不利于同一服务扩容多个副本。

3.4 ports:端口映射

这是 Docker Compose 中最常用的配置之一。

yaml 复制代码
ports:
  - "8080:80"

格式:

text 复制代码
宿主机端口:容器端口

例如:

yaml 复制代码
services:
  nginx:
    image: nginx:alpine
    ports:
      - "8080:80"

表示:

text 复制代码
浏览器访问 localhost:8080
              |
              v
宿主机 8080 端口
              |
              v
Nginx 容器 80 端口

因此可以通过:

text 复制代码
http://localhost:8080

访问 Nginx。

常见端口映射:

映射配置 说明
"8080:80" 宿主机 8080 映射到容器 80
"3307:3306" 宿主机 3307 映射到容器 3306
"6380:6379" 宿主机 6380 映射到容器 6379
"127.0.0.1:8080:80" 仅监听宿主机本地回环地址

需要特别注意:

容器之间通过内部网络通信时,通常不需要进行宿主机端口映射。

例如 MySQL 只提供给同一个 Compose 网络中的 Java 应用使用,就不一定需要开放 3306 端口。

3.5 environment:环境变量

environment 用于向容器传递环境变量。

例如:

yaml 复制代码
services:
  mysql:
    image: mysql:8.4
    environment:
      MYSQL_ROOT_PASSWORD: example-password
      MYSQL_DATABASE: shop
      TZ: Asia/Shanghai

这里配置了:

  • MySQL root 用户的初始化密码
  • 初始化数据库名称
  • 时区变量

也可以使用列表写法:

yaml 复制代码
environment:
  - MYSQL_ROOT_PASSWORD=example-password
  - MYSQL_DATABASE=shop

两种写法都可以。

注意:示例密码仅用于学习。实际项目应避免将真实密码直接写在配置文件中并提交到 Git。

3.6 volumes:数据卷挂载

volumes 主要用于持久化数据和共享文件。

常见方式有两种。

方式一:Bind Mount(绑定宿主机目录)

yaml 复制代码
volumes:
  - ./html:/usr/share/nginx/html

表示将宿主机当前目录下的 html 目录挂载到容器的 /usr/share/nginx/html 目录。

可以理解为:

text 复制代码
宿主机目录
./html
   |
   | 映射
   v
容器目录
/usr/share/nginx/html

这种方式适合挂载:

  • 配置文件
  • 前端静态文件
  • 开发环境中的源代码
  • 需要直接访问的日志文件

方式二:Named Volume(命名数据卷)

yaml 复制代码
services:
  mysql:
    image: mysql:8.4
    volumes:
      - mysql-data:/var/lib/mysql

volumes:
  mysql-data:

数据卷由 Docker 管理。

这种方式通常适合数据库等需要持久化存储的服务。

两者的主要区别:

对比项 Bind Mount Named Volume
存储位置 用户指定宿主机路径 Docker 管理
直接访问文件 比较方便 通常需要借助 Docker
数据持久化 支持 支持
常见用途 配置、代码、静态文件 数据库、持久化存储

另外,也可以在挂载后面添加:

yaml 复制代码
:ro

例如:

yaml 复制代码
volumes:
  - ./html:/usr/share/nginx/html:ro

ro 表示只读挂载,容器不能通过该挂载修改对应文件。

3.7 networks:配置容器网络

例如:

yaml 复制代码
services:
  app:
    image: my-app:1.0
    networks:
      - backend

  mysql:
    image: mysql:8.4
    networks:
      - backend

networks:
  backend:
    driver: bridge

这里定义了一个名为 backend 的网络。

app 和 mysql 连接到该网络后,就可以通过服务名称进行通信。

例如:

text 复制代码
mysql:3306

如果没有特殊网络隔离要求,也可以不显式配置 networks,Compose 会自动为项目创建默认网络。

3.8 restart:容器重启策略

常用配置:

yaml 复制代码
restart: unless-stopped

重启策略如下:

参数 含义
no 默认,不自动重启
always 容器退出后自动重启
on-failure 容器异常退出时自动重启
unless-stopped 自动重启,但保留人为停止状态

例如:

yaml 复制代码
services:
  redis:
    image: redis:7
    restart: unless-stopped

该配置常用于希望持续运行的服务。

3.9 build:根据 Dockerfile 构建镜像

除了使用现成的 Docker 镜像,也可以让 Compose 构建自定义镜像。

例如项目结构:

text 复制代码
project/
├── compose.yaml
├── Dockerfile
└── app.jar

Dockerfile:

dockerfile 复制代码
FROM eclipse-temurin:21-jre

WORKDIR /app

COPY app.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]

Compose:

yaml 复制代码
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile

    ports:
      - "8080:8080"

执行:

bash 复制代码
docker compose up -d --build

Compose 就会根据 Dockerfile 构建镜像并启动容器。


四、Docker Compose 实战:部署 MySQL + Redis + Nginx

前面介绍了 Compose 的基本配置。

接下来我们使用 Docker Compose 实际部署三个服务:

text 复制代码
Docker Compose
     |
     |---- MySQL
     |
     |---- Redis
     |
     |---- Nginx

这三个服务将运行在同一个 Docker 网络中。

4.1 环境准备

首先检查 Docker 是否安装成功:

bash 复制代码
docker --version

然后检查 Compose:

bash 复制代码
docker compose version

现代 Docker Compose 主要使用:

bash 复制代码
docker compose

旧版独立命令为:

bash 复制代码
docker-compose

4.2 创建项目目录

创建项目:

bash 复制代码
mkdir docker-demo

cd docker-demo

项目结构如下:

text 复制代码
docker-demo/
├── compose.yaml
├── .env
└── html/
    └── index.html

创建 html/index.html:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Docker Compose Demo</title>
</head>
<body>
    <h1>Hello Docker Compose!</h1>
    <p>Nginx 服务启动成功!</p>
</body>
</html>

4.3 配置环境变量

在项目根目录创建 .env:

dotenv 复制代码
MYSQL_ROOT_PASSWORD=demo_root_123456
MYSQL_DATABASE=shop
MYSQL_USER=shop_user
MYSQL_PASSWORD=demo_user_123456

这些密码仅用于本地演示。

正式项目应使用安全凭证,并将包含敏感信息的文件加入 .gitignore。

4.4 编写 Compose 文件

创建 compose.yaml:

yaml 复制代码
name: docker-demo

services:

  # MySQL 服务
  mysql:
    image: mysql:8.4

    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}

    volumes:
      - mysql-data:/var/lib/mysql

    networks:
      - app-network

    healthcheck:
      test:
        - CMD-SHELL
        - "MYSQL_PWD=$$MYSQL_ROOT_PASSWORD mysqladmin ping -h 127.0.0.1 --silent"
      interval: 10s
      timeout: 5s
      retries: 10
      start_period: 30s

    restart: unless-stopped

  # Redis 服务
  redis:
    image: redis:7-alpine

    command:
      - redis-server
      - --appendonly
      - "yes"

    volumes:
      - redis-data:/data

    networks:
      - app-network

    restart: unless-stopped

  # Nginx 服务
  nginx:
    image: nginx:alpine

    ports:
      - "8080:80"

    volumes:
      - ./html:/usr/share/nginx/html:ro

    networks:
      - app-network

    restart: unless-stopped

# 定义数据卷
volumes:
  mysql-data:
  redis-data:

# 定义网络
networks:
  app-network:
    driver: bridge

这份配置主要实现了:

  1. 使用 MySQL 8.4 镜像创建数据库服务。
  2. 通过命名数据卷持久化 MySQL 数据。
  3. 创建 Redis 服务并开启 AOF 持久化。
  4. 使用 Nginx 提供静态页面。
  5. 将 Nginx 的 80 端口映射到宿主机 8080。
  6. 让三个容器加入同一个 Docker 网络。
  7. 配置容器自动重启策略。
  8. 通过健康检查观察 MySQL 的运行状态。

注意:本例没有将 MySQL 和 Redis 端口暴露给宿主机,主要是为了演示容器内部网络和减少不必要的端口暴露。

4.5 检查配置

执行:

bash 复制代码
docker compose config

该命令会解析 Compose 文件,检查配置,并展示最终结果。

例如 .env 中的:

dotenv 复制代码
MYSQL_DATABASE=shop

会替换 Compose 中的:

yaml 复制代码
MYSQL_DATABASE: ${MYSQL_DATABASE}

4.6 启动服务

执行:

bash 复制代码
docker compose up -d

其中:

  • up:创建和启动服务。
  • -d:后台运行(detached)。

Compose 会根据配置拉取镜像、创建网络和数据卷,并启动容器。

4.7 查看容器状态

执行:

bash 复制代码
docker compose ps

正常情况下,可以看到 MySQL、Redis、Nginx 三个服务正在运行。

MySQL 可能先处于 starting 状态,完成初始化后才变为 healthy。

4.8 测试 Nginx

浏览器访问:

text 复制代码
http://localhost:8080

页面应该显示:

text 复制代码
Hello Docker Compose!

Nginx 服务启动成功!

说明 Nginx 服务成功启动。

4.9 测试 MySQL

执行:

bash 复制代码
docker compose exec mysql \
  mysql -u shop_user -p shop

输入 .env 中的用户密码。

进入数据库后:

sql 复制代码
SHOW DATABASES;

SELECT VERSION();

可以验证 MySQL 是否正常工作。

4.10 测试 Redis

执行:

bash 复制代码
docker compose exec redis redis-cli

输入:

text 复制代码
PING

如果返回:

text 复制代码
PONG

说明 Redis 正常运行。

至此,我们已经使用 Docker Compose 部署了 MySQL、Redis 和 Nginx 三个服务。


五、Docker Compose 容器之间如何通信?

这是 Docker Compose 中非常重要的一个知识点。

假设我们有两个服务:

yaml 复制代码
services:
  app:
    image: my-app:1.0

  mysql:
    image: mysql:8.4
    environment:
      MYSQL_ROOT_PASSWORD: example-password

Compose 默认会为项目创建网络,使两个服务可以相互通信。

5.1 为什么不能使用 localhost?

很多初学者在 Spring Boot 中配置 MySQL 时,会直接写:

yaml 复制代码
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/shop

当 Spring Boot 运行在 Docker 容器中时,这个配置通常是错误的。

因为:

容器中的 localhost 指的是当前容器自己,而不是其他容器。

例如:

text 复制代码
Docker 网络
|
|---- app 容器
|       |
|       |---- localhost 指 app 自己
|
|---- mysql 容器
        |
        |---- localhost 指 mysql 自己

因此,Java 容器访问 MySQL 时,应该使用 MySQL 服务名称:

text 复制代码
mysql:3306

Spring Boot 配置:

yaml 复制代码
spring:
  datasource:
    url: jdbc:mysql://mysql:3306/shop
    username: shop_user
    password: ${DB_PASSWORD}

  data:
    redis:
      host: redis
      port: 6379

需要注意,这种配置适用于 Spring Boot、MySQL、Redis 位于同一个可通信的 Compose 网络中。

5.2 宿主机访问容器与容器访问容器

两种访问方式需要区分。

第一种:宿主机访问容器

例如:

yaml 复制代码
ports:
  - "3307:3306"

在宿主机上可以通过:

text 复制代码
localhost:3307

访问 MySQL。

第二种:容器访问容器

同一 Compose 网络中的 Java 容器可以通过:

text 复制代码
mysql:3306

访问 MySQL。

总结:

访问场景 常用地址
宿主机访问 MySQL localhost:3307(需要对应端口映射)
Java 容器访问 MySQL mysql:3306
Java 容器访问 Redis redis:6379

重点:容器之间通信通常使用服务名,而不是 localhost。


六、Docker Compose 常用命令

掌握下面这些命令,基本可以满足日常开发中的大部分需求。

6.1 启动所有服务

bash 复制代码
docker compose up

前台启动,可以直接查看日志。

后台启动:

bash 复制代码
docker compose up -d

6.2 重新构建并启动

bash 复制代码
docker compose up -d --build

适用于需要根据 Dockerfile 重新构建镜像的场景。

6.3 查看服务状态

bash 复制代码
docker compose ps

6.4 停止服务

bash 复制代码
docker compose stop

仅停止容器,不删除容器。

6.5 启动已存在的容器

bash 复制代码
docker compose start

6.6 停止并删除项目容器

bash 复制代码
docker compose down

会停止并移除项目容器及相关网络。

默认不会删除命名数据卷。

6.7 删除项目容器和相关数据卷

bash 复制代码
docker compose down -v

注意:该命令可能删除数据库对应的命名数据卷,造成数据丢失,使用前需要确认。

6.8 重启容器

bash 复制代码
docker compose restart

需要注意,restart 不会自动根据 Dockerfile 重新构建镜像。

6.9 查看日志

查看所有服务日志:

bash 复制代码
docker compose logs

实时查看:

bash 复制代码
docker compose logs -f

查看 MySQL 日志:

bash 复制代码
docker compose logs -f mysql

查看最近 100 行:

bash 复制代码
docker compose logs --tail=100 mysql

6.10 进入容器

bash 复制代码
docker compose exec redis sh

这里的 redis 是服务名。

有些精简镜像不包含 bash,因此使用 sh 通常兼容性更好。

6.11 单独启动指定服务

bash 复制代码
docker compose up -d redis

6.12 拉取镜像

bash 复制代码
docker compose pull

6.13 检查配置

bash 复制代码
docker compose config

6.14 常用命令汇总

命令 作用
docker compose up -d 后台创建并启动服务
docker compose up -d --build 构建镜像并启动
docker compose down 停止并删除项目容器和网络
docker compose down -v 额外删除相关数据卷
docker compose stop 停止容器
docker compose start 启动已有容器
docker compose restart 重启容器
docker compose ps 查看服务状态
docker compose logs -f 实时查看日志
docker compose exec 在运行中的容器执行命令
docker compose config 检查最终配置
docker compose pull 拉取镜像

七、depends_on 与 healthcheck 详解

在实际项目中,服务之间可能存在依赖关系。

例如:

text 复制代码
Spring Boot
    |
    |---- MySQL
    |
    |---- Redis

Spring Boot 启动时,可能需要连接数据库和缓存服务。

7.1 depends_on 的作用

yaml 复制代码
services:
  app:
    image: my-app:1.0

    depends_on:
      - mysql
      - redis

  mysql:
    image: mysql:8.4

  redis:
    image: redis:7

该配置告诉 Compose,app 服务依赖 mysql 和 redis。

Compose 会先启动依赖服务,再启动 App。

但是这里有一个问题:

容器已经启动,不代表应用已经准备好。

例如 MySQL 容器启动之后,数据库可能还在初始化。

此时如果 Java 应用立即连接 MySQL,就可能连接失败。

7.2 healthcheck 健康检查

为了解决这个问题,可以使用健康检查。

yaml 复制代码
services:
  mysql:
    image: mysql:8.4

    environment:
      MYSQL_ROOT_PASSWORD: example-password

    healthcheck:
      test:
        - CMD-SHELL
        - "MYSQL_PWD=$$MYSQL_ROOT_PASSWORD mysqladmin ping -h 127.0.0.1 --silent"

      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

配置解释:

参数 作用
test 健康检查命令
interval 检查间隔
timeout 单次检查超时时间
retries 判定不健康所需的连续失败次数
start_period 启动宽限期

其中,$$MYSQL_ROOT_PASSWORD 用来避免 Compose 在解析配置时提前替换变量,使变量可以在容器内部展开。

7.3 depends_on + service_healthy

yaml 复制代码
services:
  app:
    image: my-app:1.0

    depends_on:
      mysql:
        condition: service_healthy

  mysql:
    image: mysql:8.4

    environment:
      MYSQL_ROOT_PASSWORD: example-password

    healthcheck:
      test:
        - CMD-SHELL
        - "MYSQL_PWD=$$MYSQL_ROOT_PASSWORD mysqladmin ping -h 127.0.0.1 --silent"

      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

这样 Compose 会等待 MySQL 通过健康检查后,再启动依赖它的 App。

需要注意:

depends_on 并不等于完整的故障恢复机制。

即使应用启动时依赖服务是健康的,运行过程中数据库也可能出现故障。因此,实际业务程序还应该具备连接重试、超时处理等能力。


八、.env、environment、env_file 的区别

这三个配置比较容易混淆。

8.1 .env 文件

创建 .env:

dotenv 复制代码
APP_PORT=8080
MYSQL_PASSWORD=example-password

Compose:

yaml 复制代码
services:
  nginx:
    image: nginx:alpine

    ports:
      - "${APP_PORT}:80"

Compose 会读取变量并进行替换。

需要注意:

.env 中的变量不会因为文件存在,就全部自动进入容器。

8.2 environment

yaml 复制代码
services:
  app:
    image: my-app:1.0

    environment:
      SPRING_PROFILES_ACTIVE: prod
      DB_PASSWORD: ${MYSQL_PASSWORD}

environment 会显式地把变量配置到容器中。

8.3 env_file

例如创建:

text 复制代码
app.env

内容:

dotenv 复制代码
SPRING_PROFILES_ACTIVE=dev
SERVER_PORT=8080

Compose:

yaml 复制代码
services:
  app:
    image: my-app:1.0

    env_file:
      - ./app.env

这样 app.env 中的变量就可以被加载到 App 容器。

8.4 对比总结

配置 作用
.env 为 Compose 变量替换提供默认值
environment 显式向容器设置环境变量
env_file 从指定文件加载容器环境变量

九、Docker Compose 与 Kubernetes 的区别

Docker Compose 和 Kubernetes 都能管理容器化应用,但是定位不同。

对比项 Docker Compose Kubernetes
主要用途 多容器应用管理 容器集群编排
学习难度 相对简单 相对复杂
典型部署方式 单台 Docker 主机 支持多节点集群
自动扩缩容 能力有限 支持
自动故障恢复 依靠重启等基础机制 具有更丰富的调度和自愈机制
常见场景 本地开发、测试、中小型部署 较大规模集群部署

需要说明的是,Docker Compose 也可以用于生产环境,并不只是本地开发工具。

对于学习 Java 后端开发的同学,可以先掌握 Docker Compose,再进一步学习 Kubernetes。


十、Docker Compose 常见问题及解决方案

10.1 容器启动成功,但是访问不了服务

首先检查容器是否运行:

bash 复制代码
docker compose ps

然后查看日志:

bash 复制代码
docker compose logs -f nginx

重点检查:

  1. 容器是否正常运行。
  2. 宿主机端口是否正确映射。
  3. 容器内部程序是否监听对应端口。
  4. 应用监听地址是否正确。
  5. 防火墙是否阻止了访问。

10.2 Java 连接不上 MySQL

常见错误:

text 复制代码
Connection refused

首先检查数据库连接地址。

错误示例:

text 复制代码
jdbc:mysql://localhost:3306/shop

如果 Spring Boot 和 MySQL 处于同一个 Compose 网络中,应该使用:

text 复制代码
jdbc:mysql://mysql:3306/shop

还需要检查数据库是否初始化完成、网络是否连通,以及账号密码是否正确。

10.3 修改 Dockerfile 后没有生效

如果只是执行:

bash 复制代码
docker compose restart

容器通常不会重新构建镜像。

应该使用:

bash 复制代码
docker compose up -d --build

10.4 修改 MySQL 初始化密码没有生效

例如原来是:

yaml 复制代码
MYSQL_ROOT_PASSWORD: old-password

修改成:

yaml 复制代码
MYSQL_ROOT_PASSWORD: new-password

如果 MySQL 数据目录已经初始化,修改环境变量通常不会自动改变数据库现有账号的密码。

原因是 MySQL 官方镜像的初始化环境变量主要在首次创建数据库数据目录时生效。

正确做法是通过 MySQL 提供的账号管理命令修改密码,而不是依靠删除数据卷重新初始化。

10.5 宿主机端口被占用

报错可能类似:

text 复制代码
port is already allocated

说明宿主机的对应端口已经被其他程序或容器占用。

例如:

yaml 复制代码
ports:
  - "3306:3306"

可以修改为:

yaml 复制代码
ports:
  - "3307:3306"

如果只需要本机访问数据库,还可以绑定到回环地址:

yaml 复制代码
ports:
  - "127.0.0.1:3307:3306"

如果数据库只需要供其他容器访问,也可以不配置端口映射。

10.6 docker compose down 后数据库数据还在吗?

如果使用的是命名数据卷:

yaml 复制代码
volumes:
  - mysql-data:/var/lib/mysql

正常执行:

bash 复制代码
docker compose down

通常不会删除命名卷中的数据。

但如果执行:

bash 复制代码
docker compose down -v

则会额外删除项目声明的命名数据卷以及相关匿名卷。

对于生产数据库,执行删除卷相关操作前,一定要确认数据备份。


十一、Docker Compose 最佳实践

在实际项目中,建议遵循以下原则。

11.1 为数据库配置数据持久化

不要只把数据库数据放在容器可写层中。

建议使用命名数据卷:

yaml 复制代码
volumes:
  - mysql-data:/var/lib/mysql

11.2 避免直接暴露不必要的端口

例如 MySQL 和 Redis 只给后端容器使用时,不一定需要配置:

yaml 复制代码
ports:
  - "3306:3306"

可以直接使用内部 Docker 网络通信。

11.3 固定镜像版本

避免随意使用:

yaml 复制代码
image: mysql:latest

建议选择经过测试的版本:

yaml 复制代码
image: mysql:8.4

如果生产环境需要严格保证镜像内容一致,可以进一步使用镜像 digest。

11.4 合理使用健康检查

例如数据库等启动时间较长的服务,可以结合:

yaml 复制代码
healthcheck:

和:

yaml 复制代码
depends_on:
  mysql:
    condition: service_healthy

提高应用初始化阶段的可靠性。

11.5 合理管理配置和密钥

可以使用 .env 或 env_file 管理非敏感环境配置。

对于数据库密码、API Key 等敏感信息,正式环境应优先考虑 Docker Secrets 或其他安全的密钥管理方案。

11.6 不要过度依赖 container_name

在没有特殊需求的情况下,让 Compose 自动管理容器名称通常更方便。

服务之间应该优先通过服务名称访问,而不是依赖固定容器名称。

11.7 了解数据备份的重要性

数据卷只能解决持久化问题,不能代替备份。

对于 MySQL 等数据库,仍然需要定期备份,并验证恢复流程。


十二、总结

通过本文,我们系统学习了 Docker Compose 的核心内容,包括:

  1. Docker Compose 的基本概念和使用场景。
  2. Docker、Dockerfile、Docker Compose 的区别。
  3. Service、Container、Network、Volume 等核心概念。
  4. services、image、ports、volumes、environment 等配置。
  5. 使用 Docker Compose 部署 MySQL、Redis、Nginx。
  6. 容器之间通过服务名进行通信的原理。
  7. 常用的 Docker Compose 命令。
  8. depends_on 与 healthcheck 的使用方法。
  9. .env、environment、env_file 的区别。
  10. 常见问题及实际项目中的最佳实践。

最后,用一句话总结:

Docker Compose 的核心价值,就是将多个容器的运行配置统一定义在 YAML 文件中,实现多容器应用的快速部署、统一管理和环境复用。

学习 Docker Compose 时,重点不只是记住命令,而是理解以下几个核心问题:

  • 容器是如何创建和运行的?
  • 容器之间为什么可以通过服务名通信?
  • 宿主机端口和容器内部端口有什么区别?
  • 数据卷为什么能够实现数据持久化?
  • 多个服务之间的依赖关系应该如何管理?

理解这些问题之后,再学习 Spring Boot + MySQL + Redis 的实际部署,就会容易很多。


参考资料


如果这篇文章对你有所帮助,欢迎点赞、收藏,也欢迎在评论区交流 Docker 和后端部署过程中遇到的问题。

相关推荐
kyle~32 分钟前
Linux --- CPU 调度机制
linux·运维·数码相机
晴天的雨.99235 分钟前
【Linux】编译器gcc/g++
linux·运维·服务器
xiaoyunxuexibiji37 分钟前
供应商认证管理怎么做?从资质审核到现场认证、样品认证
运维·服务器·人工智能
JoyCong199840 分钟前
参数测评:ToDesk个人版、团队版、企业版的设备数、并发通道与安全能力对比
运维·服务器·网络·安全·智能手机·远程工作
Tronlong创龙1 小时前
TLT153工控机:Docker 环境部署与容器开发实践(上)
docker·嵌入式开发·硬件开发·工业控制·工业开发板
KIDULT°1 小时前
【K8s 实战】Volume 存储、PV/PVC、ConfigMap 与 Secret 完整实验
云原生·容器·kubernetes
无敌糖果1 小时前
Nginx 后端error.log疯狂刷盘问题分析
运维·nginx
逐流人1 小时前
ELK企业级日志分析系统:从零搭建集中化日志平台
运维·elk·云原生·云计算·日志分析
木雷坞1 小时前
PHP两项9.2分漏洞:Docker容器更新与版本核验教程
开发语言·docker·php