Deploy a 3-Node Seata 1.8.0 Cluster with Docker Compose, Nacos & MySQL
This tutorial details deploying a three-node Seata 1.8.0 cluster using Docker Compose, Nacos for service registration and configuration, and MySQL for persistent transaction storage, covering directory layout, node-specific configs, database schema, and verification steps.
Preparation
Seata is an open-source distributed transaction solution from Ant Group and Alibaba, offering four modes: XA (strong consistency, no business intrusion), TCC (eventual consistency, business intrusion), AT (eventual consistency, no intrusion, default), and SAGA (long transactions, business intrusion). This guide focuses on the first three modes and demonstrates a production-style cluster deployment.
Environment
OS: CentOS 7
Host IP: 192.168.136.128
Nacos: already deployed, no authentication
MySQL: already deployed
Docker & Docker Compose installed
Seata version: 1.8.0
Required Downloads
seata-server-1.8.0.zip– server package for direct Windows startup seata-1.8.0.zip – source package containing configuration files and SQL scripts
From the source package, the following files are needed: server/src/main/resources/application.yml and application.example.yml (server config) script/server/db/mysql.sql (server-side table creation) script/client/at/db/mysql.sql (AT-mode client tables, not used here)
Cluster Setup
1. Directory Structure
Create /app/seata with subdirectories server1, server2, server3. Place a copy of application.yml in each, modifying the port per node.
2. Node Configuration (application.yml)
Example for server1 (port 7091, transaction port 8091):
server:
port: 7091
spring:
application:
name: seata-server
logging:
config: classpath:logback-spring.xml
file:
path: ${log.home:${user.home}/logs/seata}
console:
user:
username: seata
password: seata
seata:
config:
type: nacos
nacos:
server-addr: 192.168.136.128:8848
group: SEATA_GROUP
data-id: seataServer.properties
registry:
type: nacos
nacos:
application: seata-server
server-addr: 192.168.136.128:8848
group: SEATA_GROUP
cluster: jobs
security:
secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
tokenValidityInMilliseconds: 1800000
ignore:
urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.jpeg,/**/*.ico,/api/v1/auth/loginserver2 uses port 7092 (transaction port 8092); server3 uses port 7093 (transaction port 8093).
3. Nacos Configuration (seataServer.properties)
Create a config in Nacos with data-id=seataServer.properties, group=SEATA_GROUP:
store.mode=db
#-----db-----
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://192.168.136.128:3306/seata?useUnicode=true&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false
store.db.user=root
store.db.password=root
store.db.minConn=1
store.db.maxConn=20
store.db.maxWait=5000
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.lockTable=lock_table
store.db.queryLimit=100
# undo log retention 7 days
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000
# Two-phase retry timeout, -1 = infinite retry
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
# Retry thread intervals (ms)
server.recovery.committingRetryPeriod=1000
server.recovery.asynCommittingRetryPeriod=1000
server.recovery.rollbackingRetryPeriod=1000
server.recovery.timeoutRetryPeriod=10004. MySQL Schema Creation
Create database seata and execute the following SQL (from script/server/db/mysql.sql):
-- global_table
CREATE TABLE IF NOT EXISTS `global_table` (
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`status` TINYINT NOT NULL,
`application_id` VARCHAR(32),
`transaction_service_group` VARCHAR(32),
`transaction_name` VARCHAR(128),
`timeout` INT,
`begin_time` BIGINT,
`application_data` VARCHAR(2000),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`xid`),
KEY `idx_status_gmt_modified` (`status`, `gmt_modified`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- branch_table
CREATE TABLE IF NOT EXISTS `branch_table` (
`branch_id` BIGINT NOT NULL,
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`resource_group_id` VARCHAR(32),
`resource_id` VARCHAR(256),
`branch_type` VARCHAR(8),
`status` TINYINT,
`client_id` VARCHAR(64),
`application_data` VARCHAR(2000),
`gmt_create` DATETIME(6),
`gmt_modified` DATETIME(6),
PRIMARY KEY (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- lock_table
CREATE TABLE IF NOT EXISTS `lock_table` (
`row_key` VARCHAR(128) NOT NULL,
`xid` VARCHAR(128),
`transaction_id` BIGINT,
`branch_id` BIGINT NOT NULL,
`resource_id` VARCHAR(256),
`table_name` VARCHAR(32),
`pk` VARCHAR(36),
`status` TINYINT NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`row_key`),
KEY `idx_status` (`status`),
KEY `idx_branch_id` (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- distributed_lock
CREATE TABLE IF NOT EXISTS `distributed_lock` (
`lock_key` CHAR(20) NOT NULL,
`lock_value` VARCHAR(20) NOT NULL,
`expire` BIGINT,
PRIMARY KEY (`lock_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);5. Docker Compose File
Create /app/seata/docker-compose.yml:
version: "3.2"
services:
seata1:
image: seataio/seata-server:1.8.0
container_name: seata1
restart: always
ports:
- 7091:7091
- 8091:8091
environment:
- SEATA_IP=192.168.136.128
- SEATA_PORT=8091
- SERVER_NODE=1
volumes:
- /app/seata/server1/application.yml:/seata-server/resources/application.yml
networks:
- seata_net
seata2:
image: seataio/seata-server:1.8.0
container_name: seata2
restart: always
ports:
- 7092:7092
- 8092:8092
environment:
- SEATA_IP=192.168.136.128
- SEATA_PORT=8092
- SERVER_NODE=2
volumes:
- /app/seata/server2/application.yml:/seata-server/resources/application.yml
networks:
- seata_net
seata3:
image: seataio/seata-server:1.8.0
container_name: seata3
restart: always
ports:
- 7093:7093
- 8093:8093
environment:
- SEATA_IP=192.168.136.128
- SEATA_PORT=8093
- SERVER_NODE=3
volumes:
- /app/seata/server3/application.yml:/seata-server/resources/application.yml
networks:
- seata_net
networks:
seata_net:
driver: bridgeCritical: SEATA_IP and SEATA_PORT must be set to the host VM IP and the transaction port (8091/8092/8093). Without them, Seata registers its container-internal IP in Nacos, making it unreachable from external microservices.
6. Start the Cluster
cd /app/seata
docker-compose up -dVerification
Container logs – run docker logs -f seata1, seata2, seata3; confirm no errors.
Web console – access each node at:
http://192.168.136.128:7091
http://192.168.136.128:7092
http://192.168.136.128:7093
Credentials: seata / seata.
Nacos service list – open Nacos console, find service seata-server under cluster jobs; three instances should appear.
Single-node deployment: remove two service definitions from docker-compose.yml .
Future posts will use this environment to demonstrate AT, TCC, and XA transaction modes.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
