Apache Seata Docker Compose 部署指南
用 Docker Compose 一键部署 Apache Seata 2.6.0(db 存储模式 + MySQL 8):镜像选择、编排文件、初始化建表、JVM 内存控制、数据持久化与常用运维命令
Apache Seata Docker Compose 部署指南
目标:用 Docker Compose 在单台服务器上一键拉起 Apache Seata 2.6.0 事务协调器(TC,db 存储模式)与 MySQL 8 存储后端,覆盖镜像选型、编排文件逐项说明、三表自动初始化、JVM 堆控制、数据持久化与日常运维命令。全部命令与输出实测通过(Ubuntu 22.04 + Docker 29.8.0 + Compose v5.5.1)。
一、环境信息
- 操作系统:Ubuntu 22.04
- Docker:29.8.0,Compose v5.5.1
- Seata 版本:2.6.0(官方镜像
apache/seata-server:2.6.0) - MySQL:8(官方镜像
mysql:8) - 编排目录:
/opt/data/seata-compose/ - 端口映射:宿主机 8091 → TC 服务端口 8091
- 演示账号:MySQL
root/q1w2e3r4
二、镜像选型说明
| 候选镜像 | 说明 | 结论 |
|---|---|---|
apache/seata-server:2.6.0 | Apache 官方镜像(项目进入 ASF 后从 seataio/seata-server 迁移),随发行版同步发布 | 推荐 |
seataio/seata-server | 历史社区镜像,停更于 2.x 迁移前 | 仅旧版本兼容用 |
| 自建镜像(发行包 + JDK) | 完全可控,需自己维护 Dockerfile | 内网/离线场景备用 |
官方镜像基于 eclipse-temurin JRE 8 构建,内置 LOADER_PATH=/seata-server/lib,入口命令为:
CMD ["bash","-c","/seata-server/bin/seata-server.sh && tail -f /dev/null"]
⚠️ 两个关键事实(本文实测归纳):① 官方镜像同样不含 MySQL JDBC 驱动,db 模式需挂载驱动进
/seata-server/lib/jdbc/;② 镜像默认启动脚本以tail -f /dev/null保活,在 Compose 里覆盖command时必须保留保活逻辑,否则容器立即退出。
镜像版本查询与拉取:
docker pull apache/seata-server:2.6.0
docker image ls apache/seata-server
实测输出:
REPOSITORY TAG IMAGE ID CREATED SIZE
apache/seata-server 2.6.0 xxxxxxxxxxxx 2 months ago 430MB
三、前置条件
- 已安装 Docker 与 Compose 插件:
docker version --format '{{.Server.Version}}'
docker compose version
实测输出:
29.8.0
Docker Compose version v5.5.1
- 规划目录:
mkdir -p /opt/data/seata-compose/config /opt/data/seata-compose/script/server/db
四、部署步骤
4.1 准备 TC 建表脚本
从 Seata 发行包获取官方 db 建表脚本(也可从 GitHub script/server/db/mysql.sql 下载),放到编排目录:
cp /opt/seata/seata-server/script/server/db/mysql.sql /opt/data/seata-compose/script/server/db/
wc -l /opt/data/seata-compose/script/server/db/mysql.sql
实测输出:
99 /opt/data/seata-compose/script/server/db/mysql.sql
4.2 准备 seata-server 配置文件(db 存储模式)
写入 /opt/data/seata-compose/config/application.yml(容器内挂载到 /seata-server/resources/application.yml):
server:
port: 8091
spring:
application:
name: seata-server
logging:
config: classpath:logback-spring.xml
file:
path: ${log.home:${user.home}/logs/seata}
seata:
config:
type: file
registry:
type: file
store:
mode: db
db:
datasource: druid
db-type: mysql
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://mysql:3306/seata?rewriteBatchedStatements=true&useSSL=false&serverTimezone=Asia/Shanghai
user: root
password: q1w2e3r4
min-conn: 5
max-conn: 30
global-table: global_table
branch-table: branch_table
lock-table: lock_table
distributed-lock-table: distributed_lock
vgroup-table: vgroup_table
query-limit: 1000
max-wait: 5000
逐项说明:
seata.store.mode: db:会话/锁存到数据库,集群与重启恢复的前提(file仅单机内存态)。url中主机名mysql是 Compose 内部 DNS 服务名,服务间直接互访,不写死 IP。registry.type: file:TC 自身注册信息用文件配置;客户端侧配合grouplist直连(见 4.5 节)。若用 nacos 等注册中心,把type与对应段替换即可。min-conn/max-conn:TC 到存储库的连接池上下限,30 并发连接足够中型规模。query-limit: 1000:控制台/批量查询单次最大返回事务数。
4.3 准备 JDBC 驱动
mkdir -p /opt/data/seata-compose/driver
wget -O /opt/data/seata-compose/driver/mysql-connector-j-8.4.0.jar \
https://repo1.maven.org/maven2/com/mysql/mysql-connector-j/8.4.0/mysql-connector-j-8.4.0.jar
4.4 编写 docker-compose.yml
写入 /opt/data/seata-compose/docker-compose.yml:
services:
mysql:
image: mysql:8
container_name: seata-mysql
hostname: seata-db
environment:
MYSQL_ROOT_PASSWORD: q1w2e3r4
MYSQL_DATABASE: seata
volumes:
- ./script/server/db/mysql.sql:/docker-entrypoint-initdb.d/mysql.sql:ro
- mysql-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-uroot", "-pq1w2e3r4"]
interval: 5s
timeout: 3s
retries: 20
restart: unless-stopped
seata-server:
image: apache/seata-server:2.6.0
container_name: seata-server
hostname: seata-tc
ports:
- "8091:8091"
depends_on:
mysql:
condition: service_healthy
environment:
JVM_XMS: 512m
JVM_XMX: 512m
volumes:
- ./config/application.yml:/seata-server/resources/application.yml:ro
- ./driver/mysql-connector-j-8.4.0.jar:/seata-server/lib/jdbc/mysql-connector-j-8.4.0.jar:ro
command: ["bash", "-c", "/seata-server/bin/seata-server.sh -p 8091 && tail -f /dev/null"]
restart: unless-stopped
volumes:
mysql-data:
逐项说明:
MYSQL_DATABASE: seata:必加。官方mysql.sql只有建表语句、没有建库语句,依赖该变量先建库再执行 initdb 脚本(实测缺失时报Unknown database 'seata')。healthcheck:TC 依赖 MySQL 就绪才能连上,depends_on.condition: service_healthy保证启动顺序。JVM_XMS/JVM_XMX:控制 TC 堆为 512MB(启动脚本原生支持这两个环境变量),日志可验证生效。- 驱动以单文件挂载进
/seata-server/lib/jdbc/,避免重建镜像。 command保留官方保活逻辑并追加-p 8091。
4.5 启动
cd /opt/data/seata-compose
docker compose up -d
docker compose ps
实测输出:
NAME STATUS
seata-mysql Up 55 seconds (healthy)
seata-server Up 45 seconds
启动日志确认(docker compose logs seata-server):
seata-server | [main] [rpc.netty.NettyServerBootstrap] [start] : Server started, service listen port: 8091
seata-server | [main] [ache.seata.server.ServerRunner] [run] : seata server started in 383 millSeconds
4.6 验证建表与 JVM 生效
验证五张 TC 表已随首次启动自动创建:
docker compose exec -T mysql mysql -h127.0.0.1 -uroot -pq1w2e3r4 -e "SHOW TABLES FROM seata;"
实测输出:
branch_table
distributed_lock
global_table
lock_table
vgroup_table
验证堆限制生效:
docker compose exec seata-server ps -ef | grep '[j]ava'
实测输出(节选):
/opt/java/openjdk/bin/java ... -Xmx512m -Xms512m -Xss640k ... -jar /seata-server/target/seata-server.jar -p 8091 &
4.7 客户端接入地址
业务应用通过 registry.type: file + grouplist 直连本机映射端口:
seata:
tx-service-group: demo_tx_group
service:
vgroup-mapping:
demo_tx_group: default
grouplist:
default: <宿主机IP>:8091
五、数据持久化说明
- MySQL 数据落在命名卷
mysql-data(对应容器/var/lib/mysql),docker compose down不丢数据,down -v才会删除。 - TC 的会话/锁状态存于 MySQL(db 模式),TC 容器本身无状态,可直接
restart/重建,重启后自动恢复全局事务上下文。 - 配置文件(application.yml、驱动、建表脚本)以 bind mount 挂载在编排目录内,改配置后
docker compose restart seata-server生效。
六、环境变量表
| 变量 | 作用对象 | 示例值 | 说明 |
|---|---|---|---|
JVM_XMS | seata-server | 512m | 初始堆,脚本原生读取 |
JVM_XMX | seata-server | 512m | 最大堆 |
MYSQL_ROOT_PASSWORD | mysql | q1w2e3r4 | root 密码 |
MYSQL_DATABASE | mysql | seata | 首次启动自动建库(官方脚本依赖) |
TZ | 两者 | Asia/Shanghai | 时区(官方镜像默认已设 Asia/Shanghai) |
七、等价 docker run 命令
不使用 Compose 时等价的两条命令(先起 MySQL 再起 TC):
docker network create seata-net
docker run -d --name seata-mysql --network seata-net \
-e MYSQL_ROOT_PASSWORD=q1w2e3r4 -e MYSQL_DATABASE=seata \
-v /opt/data/seata-compose/script/server/db/mysql.sql:/docker-entrypoint-initdb.d/mysql.sql:ro \
mysql:8
docker run -d --name seata-server --network seata-net -p 8091:8091 \
-e JVM_XMS=512m -e JVM_XMX=512m \
-v /opt/data/seata-compose/config/application.yml:/seata-server/resources/application.yml:ro \
-v /opt/data/seata-compose/driver/mysql-connector-j-8.4.0.jar:/seata-server/lib/jdbc/mysql-connector-j-8.4.0.jar:ro \
apache/seata-server:2.6.0 bash -c "/seata-server/bin/seata-server.sh -p 8091 && tail -f /dev/null"
八、常用运维命令
cd /opt/data/seata-compose
docker compose ps # 状态总览
docker compose logs -f seata-server # 跟踪 TC 日志
docker compose restart seata-server # 重启 TC(配置变更后)
docker compose down # 停止并移除(保留数据卷)
docker compose down -v # 停止并删除数据卷(危险,清库)
docker compose exec mysql mysqldump -uroot -pq1w2e3r4 seata > seata-backup.sql # 备份 TC 存储库
实测 docker compose ps 输出:
NAME STATUS
seata-mysql Up 3 minutes (healthy)
seata-server Up 3 minutes
九、常见问题(FAQ)
Q1:seata-server 容器反复重启,日志只有 seata-server is starting 就退出?
command 覆盖掉了官方的 tail -f /dev/null 保活命令。启动脚本把 JVM 放后台后就返回,PID 1 退出触发重启循环。command 必须是本文 4.4 节的形式(脚本 + tail -f /dev/null)。
Q2:TC 报 The driver {com.mysql.cj.jdbc.Driver} cannot be found in the path /seata-server/lib/jdbc?
官方镜像不带 JDBC 驱动,按 4.3/4.4 节把驱动文件挂载进 /seata-server/lib/jdbc/ 后重启。
Q3:MySQL 建表没执行,报 Unknown database 'seata'?
漏了 MYSQL_DATABASE: seata,且 initdb 脚本只在首次初始化(数据卷为空)时执行。补上变量后需 docker compose down -v 清空数据卷重新初始化(会丢已有数据,先备份)。
Q4:怎么验证 db 模式真的生效?
发起一笔 AT 全局事务的同时,在另一终端观察:docker compose exec mysql mysql -h127.0.0.1 -uroot -pq1w2e3r4 -e "SELECT xid,status FROM seata.global_table;",事务进行中能看到 Begin/Rollbacking 状态记录,结束后被清理返回空。file 模式下该库始终为空。
十、参考链接
- 官方容器部署文档:https://seata.apache.org/docs/ops/deploy-by-docker-compose
- apache/seata-server 镜像:https://hub.docker.com/r/apache/seata-server
- db 建表脚本仓库:https://github.com/apache/incubator-seata/tree/2.x/script/server/db