在Swarm中部署Nacos并配置外部MySQL
1. 项目结构调整
csharp
project/
├── docker-stack.yml # Swarm主配置文件
├── .env # 环境变量文件
├── config/
│ ├── mysql-init/
│ │ ├── init.sql # MySQL初始化脚本
│ │ └── nacos-schema.sql # Nacos数据库脚本
│ ├── nacos/
│ │ ├── cluster.conf # Nacos集群配置(可选)
│ │ └── application.properties # Nacos自定义配置
│ └── nginx/
│ └── nginx.conf # 如果需要nginx代理
├── logs/
│ ├── app/
│ ├── nacos/
│ └── nginx/
└── data/
├── mysql/
├── redis/
├── app-data/
└── nacos/
├── conf/ # Nacos配置文件
├── data/ # Nacos数据
└── logs/ # Nacos日志
2. Nacos数据库初始化脚本
config/mysql-init/nacos-schema.sql
sql
-- 创建Nacos数据库
CREATE DATABASE IF NOT EXISTS nacos CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 使用Nacos数据库
USE nacos;
-- 创建Nacos配置表
-- 注意:这里使用Nacos官方提供的SQL脚本,您需要从以下地址下载:
-- https://github.com/alibaba/nacos/blob/master/distribution/conf/mysql-schema.sql
-- 这里是一个简化的示例,实际使用时请使用官方完整脚本
CREATE TABLE IF NOT EXISTS `config_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) DEFAULT NULL,
`content` longtext NOT NULL COMMENT 'content',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
`app_name` varchar(128) DEFAULT NULL,
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
`c_desc` varchar(256) DEFAULT NULL,
`c_use` varchar(64) DEFAULT NULL,
`effect` varchar(64) DEFAULT NULL,
`type` varchar(64) DEFAULT NULL,
`c_schema` text,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';
-- 其他表结构请从官方GitHub获取完整SQL
config/mysql-init/init.sql
sql
-- 创建应用数据库
CREATE DATABASE IF NOT EXISTS appdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 创建应用用户
CREATE USER IF NOT EXISTS 'appuser'@'%' IDENTIFIED BY '${MYSQL_PASSWORD}';
GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'%';
-- 创建Nacos用户
CREATE USER IF NOT EXISTS 'nacos'@'%' IDENTIFIED BY '${NACOS_DB_PASSWORD}';
GRANT ALL PRIVILEGES ON nacos.* TO 'nacos'@'%';
FLUSH PRIVILEGES;
3. Nacos自定义配置
config/nacos/application.properties
properties
# 数据库配置
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://mysql:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user=nacos
db.password=${NACOS_DB_PASSWORD}
# 集群配置(单机模式)
nacos.standalone=true
# 鉴权配置(可选)
nacos.core.auth.enabled=false
nacos.core.auth.server.identity.key=serverIdentity
nacos.core.auth.server.identity.value=security
# 服务发现配置
nacos.naming.empty-service.auto-clean=true
nacos.naming.empty-service.clean.initial-delay-ms=50000
nacos.naming.empty-service.clean.period-time-ms=30000
# 日志配置
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D
logging.file.path=/home/nacos/logs
logging.level.com.alibaba.nacos=info
config/nacos/cluster.conf(集群模式可选)
conf
# Nacos集群节点配置
nacos1:8848
nacos2:8848
nacos3:8848
4. docker-stack.yml
yaml
version: '3.8'
# 定义网络
networks:
backend:
driver: overlay
attachable: true
# 定义配置
configs:
# Nacos配置
nacos-config:
file: ./config/nacos/application.properties
# 应用配置(可选)
app-config:
file: ./config/application.yml
# 定义卷
volumes:
mysql-data:
driver: local
driver_opts:
type: none
o: bind
device: ./data/mysql
redis-data:
driver: local
driver_opts:
type: none
o: bind
device: ./data/redis
nacos-conf:
driver: local
driver_opts:
type: none
o: bind
device: ./data/nacos/conf
nacos-data:
driver: local
driver_opts:
type: none
o: bind
device: ./data/nacos/data
nacos-logs:
driver: local
driver_opts:
type: none
o: bind
device: ./data/nacos/logs
app-logs:
driver: local
driver_opts:
type: none
o: bind
device: ./logs/app
app-data:
driver: local
driver_opts:
type: none
o: bind
device: ./data/app-data
# 定义服务
services:
# MySQL服务
mysql:
image: mysql:8.0
container_name: mysql
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
TZ: Asia/Shanghai
volumes:
- mysql-data:/var/lib/mysql
- ./config/mysql-init:/docker-entrypoint-initdb.d # 初始化脚本
ports:
- "3306:3306"
networks:
- backend
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD"]
interval: 10s
timeout: 5s
retries: 3
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.role == manager
# Redis服务
redis:
image: redis:7-alpine
container_name: redis
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
volumes:
- redis-data:/data
ports:
- "6379:6379"
networks:
- backend
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
interval: 10s
timeout: 3s
retries: 3
deploy:
mode: replicated
replicas: 1
# Nacos服务
nacos:
image: nacos/nacos-server:${NACOS_VERSION:-2.2.0}
container_name: nacos
environment:
MODE: ${NACOS_MODE:-standalone} # standalone 或 cluster
SPRING_DATASOURCE_PLATFORM: mysql
MYSQL_SERVICE_HOST: mysql
MYSQL_SERVICE_PORT: 3306
MYSQL_SERVICE_DB_NAME: nacos
MYSQL_SERVICE_USER: nacos
MYSQL_SERVICE_PASSWORD: ${NACOS_DB_PASSWORD}
NACOS_AUTH_ENABLE: ${NACOS_AUTH_ENABLE:-false}
NACOS_AUTH_TOKEN: ${NACOS_AUTH_TOKEN:-SecretKey012345678901234567890123456789012345678901234567890123456789}
NACOS_AUTH_IDENTITY_KEY: ${NACOS_AUTH_IDENTITY_KEY:-serverIdentity}
NACOS_AUTH_IDENTITY_VALUE: ${NACOS_AUTH_IDENTITY_VALUE:-security}
JVM_XMS: ${NACOS_JVM_XMS:-512m}
JVM_XMX: ${NACOS_JVM_XMX:-512m}
JVM_XMN: ${NACOS_JVM_XMN:-256m}
TZ: Asia/Shanghai
volumes:
- nacos-conf:/home/nacos/conf
- nacos-data:/home/nacos/data
- nacos-logs:/home/nacos/logs
ports:
- "${NACOS_PORT:-8848}:8848" # 主端口
- "${NACOS_PORT_GRPC:-9848}:9848" # gRPC端口,用于服务发现
- "${NACOS_PORT_GRPC_PLUS:-9849}:9849" # gRPC端口+1000
networks:
- backend
depends_on:
mysql:
condition: service_healthy
configs:
- source: nacos-config
target: /home/nacos/conf/application.properties
deploy:
mode: replicated
replicas: ${NACOS_REPLICAS:-1}
update_config:
parallelism: 1
delay: 10s
order: start-first
restart_policy:
condition: on-failure
delay: 10s
max_attempts: 3
resources:
limits:
memory: 1G
reservations:
memory: 512M
placement:
constraints:
- node.labels.nacos == true # 可以给节点打标签
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8848/nacos/v1/ns/operator/metrics"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
# Spring Boot应用
app:
image: ${APP_IMAGE}
container_name: app
environment:
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILE:-prod}
SPRING_CLOUD_NACOS_DISCOVERY_SERVER-ADDR: nacos:8848
SPRING_CLOUD_NACOS_CONFIG_SERVER-ADDR: nacos:8848
SPRING_CLOUD_NACOS_USERNAME: ${NACOS_USERNAME:-nacos}
SPRING_CLOUD_NACOS_PASSWORD: ${NACOS_PASSWORD:-nacos}
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/${MYSQL_DATABASE}?useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
SPRING_DATASOURCE_USERNAME: ${MYSQL_USER}
SPRING_DATASOURCE_PASSWORD: ${MYSQL_PASSWORD}
SPRING_REDIS_HOST: redis
SPRING_REDIS_PORT: 6379
SPRING_REDIS_PASSWORD: ${REDIS_PASSWORD}
JAVA_OPTS: "-Xmx512m -Xms256m -Duser.timezone=Asia/Shanghai"
TZ: Asia/Shanghai
volumes:
- app-logs:/app/logs
- app-data:/app/data
ports:
- "${APP_PORT:-8080}:8080"
networks:
- backend
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
nacos:
condition: service_healthy
deploy:
mode: replicated
replicas: ${REPLICAS:-2}
update_config:
parallelism: 1
delay: 10s
order: start-first
restart_policy:
condition: on-failure
delay: 10s
max_attempts: 3
resources:
limits:
memory: 1G
reservations:
memory: 512M
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# Nginx反向代理(可选)
nginx:
image: nginx:alpine
container_name: nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./config/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./logs/nginx:/var/log/nginx
- ./ssl:/etc/nginx/ssl:ro
networks:
- backend
depends_on:
- app
- nacos
deploy:
mode: replicated
replicas: 1
5. .env 文件
env
# MySQL配置
MYSQL_ROOT_PASSWORD=YourStrongRootPassword
MYSQL_DATABASE=appdb
MYSQL_USER=appuser
MYSQL_PASSWORD=YourStrongAppPassword
# Redis配置
REDIS_PASSWORD=YourStrongRedisPassword
# Nacos配置
NACOS_VERSION=2.2.0
NACOS_MODE=standalone
NACOS_DB_PASSWORD=YourStrongNacosDbPassword
NACOS_AUTH_ENABLE=false
NACOS_AUTH_TOKEN=SecretKey012345678901234567890123456789012345678901234567890123456789
NACOS_USERNAME=nacos
NACOS_PASSWORD=nacos
NACOS_PORT=8848
NACOS_PORT_GRPC=9848
NACOS_REPLICAS=1
# 应用配置
APP_IMAGE=your-registry/springboot-app:1.0.0
APP_PORT=8080
SPRING_PROFILE=prod
REPLICAS=2
# Swarm配置
STACK_NAME=springboot-nacos-stack
6. Nginx配置(代理Nacos和App)
config/nginx/nginx.conf
nginx
worker_processes auto;
events {
worker_connections 1024;
}
http {
upstream app_servers {
least_conn;
server app:8080;
}
upstream nacos_servers {
least_conn;
server nacos:8848;
}
# Nacos服务代理
server {
listen 8848;
server_name nacos.your-domain.com;
location / {
proxy_pass http://nacos_servers;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# 允许跨域(Nacos控制台需要)
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
}
access_log /var/log/nginx/nacos-access.log;
error_log /var/log/nginx/nacos-error.log;
}
# 应用服务代理
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://app_servers;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
access_log /var/log/nginx/app-access.log;
error_log /var/log/nginx/app-error.log;
}
}
7. Spring Boot应用配置示例
bootstrap.yml(应用配置文件)
yaml
spring:
application:
name: your-app-name
cloud:
nacos:
discovery:
server-addr: ${SPRING_CLOUD_NACOS_DISCOVERY_SERVER_ADDR:nacos:8848}
namespace: ${NACOS_NAMESPACE:}
group: ${NACOS_GROUP:DEFAULT_GROUP}
username: ${SPRING_CLOUD_NACOS_USERNAME:nacos}
password: ${SPRING_CLOUD_NACOS_PASSWORD:nacos}
config:
server-addr: ${SPRING_CLOUD_NACOS_CONFIG_SERVER_ADDR:nacos:8848}
file-extension: yaml
namespace: ${NACOS_NAMESPACE:}
group: ${NACOS_GROUP:DEFAULT_GROUP}
username: ${SPRING_CLOUD_NACOS_USERNAME:nacos}
password: ${SPRING_CLOUD_NACOS_PASSWORD:nacos}
refresh-enabled: true
datasource:
url: ${SPRING_DATASOURCE_URL}
username: ${SPRING_DATASOURCE_USERNAME}
password: ${SPRING_DATASOURCE_PASSWORD}
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
maximum-pool-size: 10
minimum-idle: 5
redis:
host: ${SPRING_REDIS_HOST}
port: ${SPRING_REDIS_PORT}
password: ${SPRING_REDIS_PASSWORD}
database: 0
timeout: 5000ms
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
8. 部署脚本
deploy.sh
bash
#!/bin/bash
# 设置颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo -e "${GREEN}开始部署Spring Boot + Nacos项目...${NC}"
# 检查Docker Swarm是否已初始化
if ! docker node ls &> /dev/null; then
echo -e "${YELLOW}Docker Swarm未初始化,正在初始化...${NC}"
docker swarm init
fi
# 创建必要的目录
echo -e "${GREEN}创建必要的目录...${NC}"
mkdir -p logs/{app,nacos,nginx}
mkdir -p data/{mysql,redis,app-data,nacos/{conf,data,logs}}
mkdir -p config/{mysql-init,nacos,nginx}
# 检查Nacos数据库脚本是否存在
if [ ! -f "config/mysql-init/nacos-schema.sql" ]; then
echo -e "${YELLOW}下载Nacos数据库脚本...${NC}"
curl -o config/mysql-init/nacos-schema.sql \
https://raw.githubusercontent.com/alibaba/nacos/master/distribution/conf/mysql-schema.sql
fi
# 加载环境变量
if [ -f ".env" ]; then
echo -e "${GREEN}加载环境变量...${NC}"
export $(cat .env | grep -v '^#' | xargs)
else
echo -e "${RED}错误: .env文件不存在${NC}"
exit 1
fi
# 构建应用镜像(如果需要)
if [ "$1" == "build" ]; then
echo -e "${GREEN}构建应用镜像...${NC}"
docker build -t ${APP_IMAGE} .
fi
# 部署服务
echo -e "${GREEN}部署服务...${NC}"
docker stack deploy -c docker-stack.yml ${STACK_NAME}
# 等待服务启动
echo -e "${GREEN}等待服务启动...${NC}"
sleep 30
# 检查服务状态
echo -e "${GREEN}检查服务状态...${NC}"
docker stack services ${STACK_NAME}
echo -e "${GREEN}部署完成!${NC}"
echo -e "访问地址:"
echo -e " Nacos控制台: http://localhost:${NACOS_PORT:-8848}/nacos"
echo -e " 应用服务: http://localhost:${APP_PORT:-8080}"
echo -e " 数据库: localhost:3306"
echo -e " Redis: localhost:6379"
9. 管理命令
bash
# 给节点打标签(用于部署Nacos)
docker node update --label-add nacos=true <node-name>
# 查看Nacos日志
docker service logs ${STACK_NAME}_nacos -f
# 查看所有服务
docker stack ps ${STACK_NAME}
# 扩展Nacos实例(集群模式)
docker service scale ${STACK_NAME}_nacos=3
# 备份Nacos配置
tar -czf nacos-backup-$(date +%Y%m%d).tar.gz data/nacos/conf/
# 访问Nacos控制台
# 用户名: nacos
# 密码: nacos(默认)
10. Nacos集群模式部署(可选)
如果需要部署Nacos集群,需要:
- 修改
.env文件:
env
NACOS_MODE=cluster
NACOS_REPLICAS=3
- 确保每个节点都有标签:
bash
docker node update --label-add nacos=true node1
docker node update --label-add nacos=true node2
docker node update --label-add nacos=true node3
- 创建集群配置文件并挂载到每个Nacos实例。
这个配置实现了:
- Nacos使用外部MySQL存储配置
- 所有配置文件持久化到本地
- Spring Boot应用从Nacos获取配置
- 完整的健康检查和服务依赖
- 日志和数据持久化
请根据您的实际需求调整配置。