背景
在服务器上已经运行了一个 MySQL 服务(端口 3309),现在需要使用 Docker Compose 启动 Spring Boot 应用,并连接到这个已存在的 MySQL 数据库,而不是在 Docker 容器中再启动一个新的 MySQL。
完整解决方案
一、修改 docker-compose.yml
1. 注释掉 MySQL 容器配置
# mysql:
# image: mysql:8.0
# container_name: springboot-mysql
...
# mem_limit: 256m
2. 修改 app 服务的数据库连接配置
app:
build:
context: .
dockerfile: Dockerfile
container_name: springboot-app
restart: always
ports:
- "8080:8080"
environment:
# 修改数据库连接配置,连接服务器现有 MySQL
SPRING_DATASOURCE_URL: jdbc:mysql://host.docker.internal:3309/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
SPRING_DATASOURCE_USERNAME: newuser
SPRING_DATASOURCE_PASSWORD: 123456
...
mem_limit: 256m
3. 移除 mysql-data 卷定义
volumes:
# 移除 mysql-data 卷
redis-data:
二、MySQL 用户授权
由于 Docker 容器需要从容器网络访问宿主机的 MySQL,需要给数据库用户授予相应的权限。
1. 连接到 MySQL
mysql -u root -p
2. 创建用户并授权(MySQL 8.0+ 语法)
-- 创建用户(如果不存在)
CREATE USER IF NOT EXISTS 'newuser'@'%' IDENTIFIED BY '123456';
-- 授予 demo 数据库的所有权限
GRANT ALL PRIVILEGES ON demo.* TO 'newuser'@'%';
-- 刷新权限
FLUSH PRIVILEGES;
3. 验证权限
-- 查看用户权限
SHOW GRANTS FOR 'newuser'@'%';
-- 查看用户信息
SELECT host, user FROM mysql.user WHERE user = 'newuser';
三、关键修改点说明
1. 数据库连接配置
| 配置项 | 原值 | 新值 | 说明 |
|---|---|---|---|
| 主机地址 | mysql |
host.docker.internal |
指向宿主机 |
| 端口 | 3306 |
3309 |
服务器 MySQL 实际端口 |
| 用户名 | root |
newuser |
使用指定的数据库用户 |
| 密码 | 123456 |
123456 |
保持不变 |
2. host.docker.internal 说明
host.docker.internal 是 Docker 提供的特殊 DNS 名称,用于从容器内部访问宿主机。
平台支持情况:
- ✅ Docker Desktop(Windows/Mac):原生支持
- ❌ Linux:不支持
Linux 替代方案:
如果服务器是 Linux 系统,需要将 host.docker.internal 替换为宿主机的实际 IP 地址。
查看宿主机 IP 的命令:
# 快速查看主网卡 IP
ip route get 1.1.1.1 | awk '{print $7}'
# 查看所有 IP
hostname -I
选择物理网卡(如 eth0、ens33)的 IP,不要选择 127.0.0.1 或 172.17.0.1。
修改后的配置示例:
SPRING_DATASOURCE_URL: jdbc:mysql://192.168.1.100:3309/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
3. 依赖关系调整
移除了 app 服务对 mysql 容器的依赖,因为不再启动 MySQL 容器:
depends_on:
redis:
condition: service_healthy
4. 卷定义清理
移除了不再使用的 mysql-data 卷:
volumes:
redis-data:
四、常见问题解决
问题1:Access denied for user 'newuser'@'172.18.0.1'
原因: 用户没有从 Docker 容器网络访问的权限。
解决: 执行 MySQL 授权命令,使用 @'%' 允许从任意 IP 访问。
问题2:MySQL 8.0+ GRANT 语法错误
错误信息: ERROR 1410 (42000): You are not allowed to create a user with GRANT
原因: MySQL 8.0+ 不允许在 GRANT 语句中使用 IDENTIFIED BY。
解决: 先创建用户,再授予权限。
-- 正确的语法
CREATE USER IF NOT EXISTS 'newuser'@'%' IDENTIFIED BY '123456';
GRANT ALL PRIVILEGES ON demo.* TO 'newuser'@'%';
FLUSH PRIVILEGES;
问题3:Linux 上 host.docker.internal 不工作
解决: 使用宿主机实际 IP 地址替代。
五、启动服务
完成以上配置后,启动 Docker Compose 服务:
# 构建并启动所有服务
docker-compose up -d
# 查看服务状态
docker-compose ps
# 查看应用日志
docker-compose logs -f app
# 重启应用服务
docker-compose restart app
六、总结
通过以上方案,我们实现了 Docker Compose 连接服务器现有 MySQL 的目标,主要步骤包括:
- 注释掉 docker-compose.yml 中的 MySQL 容器配置
- 修改 app 服务的数据库连接配置,指向宿主机 MySQL
- 移除对 MySQL 容器的依赖和卷定义
- 在 MySQL 中为容器用户授予访问权限
- Linux 环境需要使用宿主机实际 IP 替代
host.docker.internal
这样可以避免重复启动 MySQL 服务,节省服务器资源,同时保持应用的正常运行。