XXL-Job Docker 部署中“登录无响应”的排查与解决

前言

最近在 Ubuntu 服务器上使用 Docker 部署 XXL-Job 分布式任务调度平台时,遇到了一个典型但容易踩坑的网络问题:调度中心容器与 MySQL 容器无法正常通信,导致登录界面点击后毫无反应。本文将复盘整个部署过程,并重点分享如何通过 Docker 自定义网络彻底解决该问题。

如果你也正准备在 Linux 环境下用 Docker 搭建 XXL-Job,或者遇到类似的容器互联问题,相信这篇文章能帮你少走弯路。


环境说明

  • 操作系统:Ubuntu 20.04 / 22.04(Intel 芯片)
  • Docker 版本:20.10+
  • MySQL:已通过 Docker 运行 amd64/mysql:5.7.36 容器,端口映射 3306:3306,容器名 mysql,root 密码 root
  • XXL-Job 版本:2.4.0
  • 数据挂载路径:/data/docker/xxl-job/logs

第一阶段:初始化数据库

XXL-Job 依赖 MySQL 存储任务元数据,首先需要执行官方提供的初始化脚本。

bash 复制代码
# 下载 2.4.0 版本的 SQL 脚本
wget https://raw.githubusercontent.com/xuxueli/xxl-job/2.4.0/doc/db/tables_xxl_job.sql

# 将脚本导入已运行的 MySQL 容器
docker exec -i mysql mysql -uroot -proot < tables_xxl_job.sql

验证表是否创建成功:

bash 复制代码
docker exec -it mysql mysql -uroot -proot -e "USE xxl_job; SHOW TABLES;"

若看到 xxl_job_infoxxl_job_log 等表,说明数据库初始化完成。


第二阶段:启动调度中心(首次尝试,方案一)

按照常规思路,我将 MySQL 端口映射到了宿主机 3306,于是尝试让 XXL-Job 容器通过 127.0.0.1:3306 连接数据库:

bash 复制代码
docker run -d \
  --name xxl-job-admin \
  --restart=always \
  -p 8080:8080 \
  -v /data/docker/xxl-job/logs:/data/applogs \
  -e PARAMS="--spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai \
  --spring.datasource.username=root \
  --spring.datasource.password=root \
  --xxl.job.accessToken=default_token" \
  xuxueli/xxl-job-admin:2.4.0

容器启动正常,访问 http://<服务器IP>:8080/xxl-job-admin 也能看到登录页。然而输入账号 admin 密码 123456 点击登录后,页面毫无反应,浏览器控制台也没有明显报错。


第三阶段:问题排查

1. 查看容器日志

bash 复制代码
docker logs -f --tail=100 xxl-job-admin

日志中抛出了关键异常:

复制代码
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.

很明显,调度中心根本无法连接到 MySQL 数据库。

2. 分析网络隔离原因

问题的根源在于 Docker 容器的网络隔离机制:

  • XXL-Job 容器内使用的 127.0.0.1 指向的是容器自身,而不是宿主机。
  • MySQL 虽然通过 -p 3306:3306 将端口映射到了宿主机,但容器想要访问宿主机网络,不能直接使用 127.0.0.1

3. 尝试方案一:host.docker.internal

在 Mac/Windows 的 Docker Desktop 中,可以使用特殊域名 host.docker.internal 来访问宿主机。我尝试在 Linux 下也使用该方式,将连接地址改为:

复制代码
jdbc:mysql://host.docker.internal:3306/xxl_job?...

重新启动容器后,问题依旧。查阅文档发现,在 Linux 系统上,Docker 默认并不支持 host.docker.internal (除非在 docker run 时添加 --add-host 参数手动映射)。因此方案一失败。


第四阶段:最终解决方案(方案二)------ 使用 Docker 自定义网络

最标准、最稳定的做法是:将两个容器置于同一个自定义 Docker 网络中,直接通过容器名互相访问

步骤详解

1. 创建自定义桥接网络
bash 复制代码
docker network create xxl-net
2. 将已运行的 MySQL 容器连接到该网络
bash 复制代码
docker network connect xxl-net mysql
3. 启动 XXL-Job 容器并加入同一网络

注意数据库连接地址直接使用 MySQL 容器名 mysql

bash 复制代码
# 如果之前启动过 xxl-job-admin,先停止并删除
docker stop xxl-job-admin
docker rm xxl-job-admin

# 使用新网络启动
docker run -d \
  --name xxl-job-admin \
  --network xxl-net \
  --restart=always \
  -p 8080:8080 \
  -v /data/docker/xxl-job/logs:/data/applogs \
  -e PARAMS="--spring.datasource.url=jdbc:mysql://mysql:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai \
  --spring.datasource.username=root \
  --spring.datasource.password=root \
  --xxl.job.accessToken=default_token" \
  xuxueli/xxl-job-admin:2.4.0

原理说明

  • 同一个自定义网络内的容器,Docker 会提供内置的 DNS 服务。
  • 容器名 mysql 会被解析为 MySQL 容器的内部 IP,无需关心端口映射,直接通过容器的 3306 端口通信。
  • 这种方式避免了宿主机端口暴露带来的安全隐患,也绕过了 127.0.0.1 的歧义问题。
4. 验证结果

再次访问 http://<服务器IP>:8080/xxl-job-admin,输入 admin/123456,登录成功!

如果遇到密码错误,可以进入 MySQL 容器手动将 xxl_job_user 表中 admin 用户的密码改为 MD5 值 e10adc3949ba59abbe56e057f20f883e(对应 123456),因为 2.4.0 版本存在密码加密方式不一致的已知问题。


总结

本次部署的核心卡点在于 Docker 容器间的网络通信 。通过自定义网络 xxl-net,我们实现了:

  • 调度中心与 MySQL 的稳定互联
  • 配置简洁,无需关心宿主机 IP 变化
  • 符合 Docker 最佳实践,易于后续扩展(如增加更多执行器容器)

完整部署架构图(简化版)

一些经验教训

  1. 在 Linux 上不要依赖 host.docker.internal ,除非你手动在 docker run 中添加 --add-host host.docker.internal:host-gateway
  2. 优先使用 Docker 自定义网络来处理容器间通信,这是官方推荐的方式。
  3. 遇到问题时,第一时间查看容器日志 docker logs <容器名>,往往能直接定位错误。

希望这篇记录能帮助你在 Docker 上顺利部署 XXL-Job,也为你处理类似的容器网络问题提供一个清晰的思路。

相关推荐
逻极2 小时前
MySQL 从入门到精通:一个老 DBA 的实战心法
运维·数据库·mysql·从入门到精通·mysql从入门到精通
cui_ruicheng2 小时前
Linux IO入门(三):手写一个简易的 mystdio 库
linux·运维·服务器
telllong2 小时前
MCP协议实战:30分钟给Claude接上你公司的内部API
linux·运维·服务器
正在走向自律2 小时前
KingbaseES 基础 SQL 语法与日常运维实操手册
运维·数据库·sql·kingbasees
实心儿儿2 小时前
Linux —— 进程概念 - 程序地址空间
linux·运维·算法
buhuizhiyuci2 小时前
linux篇-应用商店:“yum / apt“ 的详解
linux·运维·服务器
Tisfy3 小时前
CORS 跨域重定向后 Origin 变 null —— 一次 Nginx 字体加载失败的排查记录
运维·nginx·html·cors
程序猿阿伟3 小时前
《QClaw隐藏的GitHub自动化神级用法》
运维·自动化·github
ulias2123 小时前
进程初识(1)
linux·运维·服务器·网络·c++