在Swarm中部署Nacos并配置外部MySQL

在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集群,需要:

  1. 修改 .env 文件:
env 复制代码
NACOS_MODE=cluster
NACOS_REPLICAS=3
  1. 确保每个节点都有标签:
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
  1. 创建集群配置文件并挂载到每个Nacos实例。

这个配置实现了:

  • Nacos使用外部MySQL存储配置
  • 所有配置文件持久化到本地
  • Spring Boot应用从Nacos获取配置
  • 完整的健康检查和服务依赖
  • 日志和数据持久化

请根据您的实际需求调整配置。

相关推荐
颜酱7 分钟前
# 02 | 搭骨架:用 LangGraph 编排 12 步工作流(思路)
前端·人工智能·后端
颜酱8 分钟前
02 | 搭骨架:用 LangGraph 编排 12 步工作流
前端·人工智能·后端
嘉伟桑1 小时前
Python调用电价API返回JSON示例:分时电价、现货电价和字段解析
后端
武子康1 小时前
Shippy:确定性工具、会话级 Sandbox 与 Live-Data Eval(4 类收敛 + 7 步实现方案 + 6 类评测指标)
前端·人工智能·后端
我叫黑大帅2 小时前
我为什么单一消费者的场景下,要用 Redis List 当消息队列?
redis·后端·面试
AskHarries2 小时前
文件上传系统
后端
止语Lab3 小时前
好的 DX 不等于少写代码——三种语言的摩擦力设计课
后端
吃饱了得干活3 小时前
别再手动解析 LLM 输出了!LangChain 四种结构化输出方案对比
后端·python·langchain
程序员天天困3 小时前
Arthas trace 命令怎么用?一行定位最慢那行代码
jvm·后端
Huiturn3 小时前
GPT 5.6 连续编码 10 小时,纯 Python 啃下 Word 二进制格式——doc2docx 实现拆解
后端