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
这份配置主要实现了:
- 使用 MySQL 8.4 镜像创建数据库服务。
- 通过命名数据卷持久化 MySQL 数据。
- 创建 Redis 服务并开启 AOF 持久化。
- 使用 Nginx 提供静态页面。
- 将 Nginx 的 80 端口映射到宿主机 8080。
- 让三个容器加入同一个 Docker 网络。
- 配置容器自动重启策略。
- 通过健康检查观察 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
重点检查:
- 容器是否正常运行。
- 宿主机端口是否正确映射。
- 容器内部程序是否监听对应端口。
- 应用监听地址是否正确。
- 防火墙是否阻止了访问。
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 的核心内容,包括:
- Docker Compose 的基本概念和使用场景。
- Docker、Dockerfile、Docker Compose 的区别。
- Service、Container、Network、Volume 等核心概念。
services、image、ports、volumes、environment等配置。- 使用 Docker Compose 部署 MySQL、Redis、Nginx。
- 容器之间通过服务名进行通信的原理。
- 常用的 Docker Compose 命令。
depends_on与healthcheck的使用方法。.env、environment、env_file的区别。- 常见问题及实际项目中的最佳实践。
最后,用一句话总结:
Docker Compose 的核心价值,就是将多个容器的运行配置统一定义在 YAML 文件中,实现多容器应用的快速部署、统一管理和环境复用。
学习 Docker Compose 时,重点不只是记住命令,而是理解以下几个核心问题:
- 容器是如何创建和运行的?
- 容器之间为什么可以通过服务名通信?
- 宿主机端口和容器内部端口有什么区别?
- 数据卷为什么能够实现数据持久化?
- 多个服务之间的依赖关系应该如何管理?
理解这些问题之后,再学习 Spring Boot + MySQL + Redis 的实际部署,就会容易很多。
参考资料
- Docker Compose 官方文档:https://docs.docker.com/compose/
- Docker Compose 入门教程:https://docs.docker.com/compose/gettingstarted/
- Compose 配置参考:https://docs.docker.com/reference/compose-file/
- Docker Compose CLI 命令参考:https://docs.docker.com/reference/cli/docker/compose/
- Docker Compose 网络文档:https://docs.docker.com/compose/how-tos/networking/
如果这篇文章对你有所帮助,欢迎点赞、收藏,也欢迎在评论区交流 Docker 和后端部署过程中遇到的问题。