VortMall Docker 部署指南

VortMall Docker 部署指南

本文档详细介绍如何使用 Docker 和 Docker Compose 部署 VortMall 微服务商城系统。

目录


1. 环境准备

1.1 系统要求

项目最低要求推荐配置
操作系统CentOS 7+ / Ubuntu 20.04+ / Debian 11+Ubuntu 22.04 LTS
CPU4核8核+
内存16GB32GB
磁盘100GB SSD200GB SSD
Docker20.10+24.0+
Docker Compose2.0+2.20+

1.2 安装 Docker

CentOS / RHEL / Alibaba Cloud Linux

# 卸载旧版本
sudo yum remove docker docker-client docker-client-latest docker-common \
    docker-latest docker-latest-logrotate docker-logrotate docker-engine

# 安装依赖
sudo yum install -y yum-utils device-mapper-persistent-data lvm2

# 添加 Docker 仓库
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# 安装 Docker
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# 启动 Docker
sudo systemctl start docker
sudo systemctl enable docker

# 验证安装
docker --version
docker compose version

Ubuntu / Debian

# 卸载旧版本
sudo apt-get remove docker docker-engine docker.io containerd runc

# 安装依赖
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg lsb-release

# 添加 Docker GPG 密钥
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# 添加仓库
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 安装 Docker
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# 验证安装
docker --version
docker compose version

1.3 Docker 配置优化

# 创建配置目录
sudo mkdir -p /etc/docker

# 配置 Docker daemon
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": [
    "https://mirror.ccs.tencentyun.com",
    "https://docker.mirrors.ustc.edu.cn",
    "https://hub-mirror.c.163.com"
  ],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  },
  "storage-driver": "overlay2",
  "live-restore": true,
  "default-ulimits": {
    "nofile": {
      "Name": "nofile",
      "Hard": 65536,
      "Soft": 65536
    }
  }
}
EOF

# 重启 Docker
sudo systemctl daemon-reload
sudo systemctl restart docker

# 添加当前用户到 docker 组(免 sudo)
sudo usermod -aG docker $USER
newgrp docker

1.4 系统参数优化

# 优化内核参数
sudo tee -a /etc/sysctl.conf <<-'EOF'
# 网络优化
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_max_tw_buckets = 5000

# 文件句柄
fs.file-max = 2097152
fs.nr_open = 2097152

# 内存优化
vm.swappiness = 10
vm.max_map_count = 262144
EOF

# 应用配置
sudo sysctl -p

# 设置文件句柄限制
sudo tee -a /etc/security/limits.conf <<-'EOF'
* soft nofile 65536
* hard nofile 65536
* soft nproc 65536
* hard nproc 65536
EOF

2. 目录结构规划

2.1 创建部署目录

# 创建主目录
sudo mkdir -p /opt/vortmall
sudo chown -R $USER:$USER /opt/vortmall
cd /opt/vortmall

# 创建子目录
mkdir -p {apps,middleware,data,logs,config,scripts,backup}

# 目录结构
/opt/vortmall/
├── apps/                    # 业务服务
│   ├── docker-compose.yml   # 业务服务编排
│   ├── .env                 # 环境变量
│   └── jars/                # JAR 包目录
├── middleware/              # 中间件
│   ├── docker-compose.yml   # 中间件编排
│   ├── mysql/               # MySQL 配置
│   ├── redis/               # Redis 配置
│   ├── nacos/               # Nacos 配置
│   ├── rocketmq/            # RocketMQ 配置
│   └── ...
├── data/                    # 数据持久化
│   ├── mysql/
│   ├── redis/
│   ├── nacos/
│   ├── minio/
│   └── ...
├── logs/                    # 日志目录
│   ├── gateway/
│   ├── auth/
│   ├── biz-user/
│   └── ...
├── config/                  # 配置文件
│   └── nacos/               # Nacos 配置导出
├── scripts/                 # 运维脚本
│   ├── start.sh
│   ├── stop.sh
│   ├── backup.sh
│   └── health-check.sh
└── backup/                  # 备份目录

2.2 复制项目部署文件

# 从项目中复制部署配置
cp -r /path/to/vortmall-api/deployment/DockerCompose/* /opt/vortmall/middleware/

3. 中间件部署

3.1 中间件清单

中间件版本端口必需说明
MySQL8.4.13306数据库
Redislatest6379缓存
Nacos2.5.18848, 9848注册/配置中心
RocketMQ5.2.09876, 10911消息队列
XXL-JOB2.4.18082任务调度
MinIOlatest9000, 9001文件存储
Seata2.0.07091, 8091分布式事务
EMQX5.8.31883, 18083MQTT 消息
Elasticsearch8.12.09200搜索引擎
Kibana8.12.05601ES 可视化
SkyWalking10.0.111800, 12800链路追踪

3.2 中间件 docker-compose.yml

创建 /opt/vortmall/middleware/docker-compose.yml

version: '3.8'

services:
  # ==================== 核心中间件 ====================
  
  mysql:
    image: mysql:8.4.1
    container_name: vortmall-mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-vortmall666}
      MYSQL_CHARACTER_SET_SERVER: utf8mb4
      MYSQL_COLLATION_SERVER: utf8mb4_unicode_ci
      TZ: Asia/Shanghai
    ports:
      - "3306:3306"
    volumes:
      - ${DATA_PATH}/mysql/data:/var/lib/mysql
      - ${DATA_PATH}/mysql/conf:/etc/mysql/conf.d
      - ${DATA_PATH}/mysql/init:/docker-entrypoint-initdb.d
      - /etc/localtime:/etc/localtime:ro
    command:
      - --default-authentication-plugin=caching_sha2_password
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
      - --max_connections=1000
      - --innodb_buffer_pool_size=512M
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD:-vortmall666}"]
      interval: 10s
      timeout: 5s
      retries: 10
      start_period: 30s
    networks:
      - vortmall-network

  redis:
    image: redis:7-alpine
    container_name: vortmall-redis
    restart: always
    ports:
      - "6379:6379"
    volumes:
      - ${DATA_PATH}/redis/data:/data
      - ${DATA_PATH}/redis/conf/redis.conf:/usr/local/etc/redis/redis.conf
    command: redis-server /usr/local/etc/redis/redis.conf
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - vortmall-network

  nacos:
    image: nacos/nacos-server:v2.5.1
    container_name: vortmall-nacos
    restart: always
    environment:
      MODE: standalone
      SPRING_DATASOURCE_PLATFORM: mysql
      MYSQL_SERVICE_HOST: mysql
      MYSQL_SERVICE_PORT: 3306
      MYSQL_SERVICE_USER: root
      MYSQL_SERVICE_PASSWORD: ${MYSQL_ROOT_PASSWORD:-vortmall666}
      MYSQL_SERVICE_DB_NAME: nacos_config
      MYSQL_SERVICE_DB_PARAM: characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
      JVM_XMS: 512m
      JVM_XMX: 512m
      JVM_XMN: 256m
      NACOS_AUTH_ENABLE: "true"
      NACOS_AUTH_TOKEN: "VG9rZW5TZWNyZXRLZXlGb3JOYWNvc0F1dGhUb2tlbjIwMjQ="
      NACOS_AUTH_IDENTITY_KEY: serverIdentity
      NACOS_AUTH_IDENTITY_VALUE: vortmall
    ports:
      - "8848:8848"
      - "9848:9848"
      - "9849:9849"
    volumes:
      - ${DATA_PATH}/nacos/logs:/home/nacos/logs
    depends_on:
      mysql:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8848/nacos/v1/console/health/readiness"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 60s
    networks:
      - vortmall-network

  # ==================== 消息队列 ====================

  rocketmq-namesrv:
    image: apache/rocketmq:5.2.0
    container_name: vortmall-rocketmq-namesrv
    restart: always
    environment:
      JAVA_OPT_EXT: "-Xms512m -Xmx512m -Xmn256m"
    ports:
      - "9876:9876"
    volumes:
      - ${DATA_PATH}/rocketmq/namesrv/logs:/home/rocketmq/logs
    command: sh mqnamesrv
    networks:
      - vortmall-network

  rocketmq-broker:
    image: apache/rocketmq:5.2.0
    container_name: vortmall-rocketmq-broker
    restart: always
    environment:
      JAVA_OPT_EXT: "-Xms512m -Xmx1g -Xmn256m"
      NAMESRV_ADDR: rocketmq-namesrv:9876
    ports:
      - "10909:10909"
      - "10911:10911"
      - "10912:10912"
    volumes:
      - ${DATA_PATH}/rocketmq/broker/logs:/home/rocketmq/logs
      - ${DATA_PATH}/rocketmq/broker/store:/home/rocketmq/store
      - ./rocketmq/broker.conf:/home/rocketmq/conf/broker.conf
    command: sh mqbroker -c /home/rocketmq/conf/broker.conf
    depends_on:
      - rocketmq-namesrv
    networks:
      - vortmall-network

  rocketmq-dashboard:
    image: apacherocketmq/rocketmq-dashboard:2.0.0
    container_name: vortmall-rocketmq-dashboard
    restart: always
    environment:
      JAVA_OPTS: "-Drocketmq.namesrv.addr=rocketmq-namesrv:9876"
    ports:
      - "8080:8080"
    depends_on:
      - rocketmq-namesrv
      - rocketmq-broker
    networks:
      - vortmall-network

  # ==================== 任务调度 ====================

  xxl-job-admin:
    image: xuxueli/xxl-job-admin:2.4.1
    container_name: vortmall-xxl-job
    restart: always
    environment:
      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=${MYSQL_ROOT_PASSWORD:-vortmall666}
        --xxl.job.accessToken=vortmall-xxl-job-token
    ports:
      - "8082:8080"
    volumes:
      - ${DATA_PATH}/xxl-job/logs:/data/applogs
    depends_on:
      mysql:
        condition: service_healthy
    networks:
      - vortmall-network

  # ==================== 文件存储 ====================

  minio:
    image: minio/minio:latest
    container_name: vortmall-minio
    restart: always
    environment:
      MINIO_ROOT_USER: ${MINIO_USER:-vortmall}
      MINIO_ROOT_PASSWORD: ${MINIO_PASSWORD:-vortmall666}
    ports:
      - "9000:9000"
      - "9001:9001"
    volumes:
      - ${DATA_PATH}/minio/data:/data
    command: server /data --console-address ":9001"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 30s
      timeout: 10s
      retries: 3
    networks:
      - vortmall-network

  # ==================== 分布式事务 ====================

  seata-server:
    image: seataio/seata-server:2.0.0
    container_name: vortmall-seata
    restart: always
    environment:
      STORE_MODE: db
      SEATA_IP: ${HOST_IP}
      SEATA_PORT: 8091
    ports:
      - "7091:7091"
      - "8091:8091"
    volumes:
      - ./seata/application.yml:/seata-server/resources/application.yml
      - ${DATA_PATH}/seata/logs:/seata-server/logs
    depends_on:
      mysql:
        condition: service_healthy
      nacos:
        condition: service_healthy
    networks:
      - vortmall-network

  # ==================== MQTT 消息服务 ====================

  emqx:
    image: emqx/emqx:5.8.3
    container_name: vortmall-emqx
    restart: always
    environment:
      EMQX_NAME: emqx
      EMQX_HOST: ${HOST_IP}
      EMQX_DASHBOARD__DEFAULT_USERNAME: admin
      EMQX_DASHBOARD__DEFAULT_PASSWORD: ${EMQX_PASSWORD:-vortmall666}
    ports:
      - "1883:1883"
      - "8083:8083"
      - "8084:8084"
      - "8883:8883"
      - "18083:18083"
    volumes:
      - ${DATA_PATH}/emqx/data:/opt/emqx/data
      - ${DATA_PATH}/emqx/log:/opt/emqx/log
    healthcheck:
      test: ["CMD", "emqx", "ctl", "status"]
      interval: 30s
      timeout: 10s
      retries: 5
    networks:
      - vortmall-network

  # ==================== 搜索引擎 ====================

  elasticsearch:
    image: elasticsearch:8.12.0
    container_name: vortmall-es
    restart: always
    environment:
      - discovery.type=single-node
      - ES_JAVA_OPTS=-Xms512m -Xmx1g
      - ELASTIC_PASSWORD=${ES_PASSWORD:-vortmall666}
      - xpack.security.enabled=true
      - xpack.security.http.ssl.enabled=false
      - TZ=Asia/Shanghai
    ports:
      - "9200:9200"
      - "9300:9300"
    volumes:
      - ${DATA_PATH}/elasticsearch/data:/usr/share/elasticsearch/data
      - ${DATA_PATH}/elasticsearch/plugins:/usr/share/elasticsearch/plugins
      - ${DATA_PATH}/elasticsearch/logs:/usr/share/elasticsearch/logs
    healthcheck:
      test: ["CMD-SHELL", "curl -u elastic:${ES_PASSWORD:-vortmall666} -s http://localhost:9200/_cluster/health | grep -q 'green\\|yellow'"]
      interval: 30s
      timeout: 10s
      retries: 10
      start_period: 60s
    networks:
      - vortmall-network

  kibana:
    image: kibana:8.12.0
    container_name: vortmall-kibana
    restart: always
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
      - ELASTICSEARCH_USERNAME=kibana_system
      - ELASTICSEARCH_PASSWORD=${ES_PASSWORD:-vortmall666}
      - I18N_LOCALE=zh-CN
      - TZ=Asia/Shanghai
    ports:
      - "5601:5601"
    depends_on:
      elasticsearch:
        condition: service_healthy
    networks:
      - vortmall-network

  # ==================== 链路追踪 ====================

  skywalking-oap:
    image: apache/skywalking-oap-server:10.0.1
    container_name: vortmall-skywalking-oap
    restart: always
    environment:
      SW_STORAGE: elasticsearch
      SW_STORAGE_ES_CLUSTER_NODES: elasticsearch:9200
      SW_ES_USER: elastic
      SW_ES_PASSWORD: ${ES_PASSWORD:-vortmall666}
      TZ: Asia/Shanghai
      SW_CORE_RECORD_DATA_TTL: 3
      SW_CORE_METRICS_DATA_TTL: 7
    ports:
      - "11800:11800"
      - "12800:12800"
    depends_on:
      elasticsearch:
        condition: service_healthy
    healthcheck:
      test: ["CMD-SHELL", "curl -sf http://localhost:12800/healthcheck || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 60s
    networks:
      - vortmall-network

  skywalking-ui:
    image: apache/skywalking-ui:10.0.1
    container_name: vortmall-skywalking-ui
    restart: always
    environment:
      SW_OAP_ADDRESS: http://skywalking-oap:12800
      TZ: Asia/Shanghai
    ports:
      - "18080:8080"
    depends_on:
      skywalking-oap:
        condition: service_healthy
    networks:
      - vortmall-network

networks:
  vortmall-network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16

3.3 环境变量配置

创建 /opt/vortmall/middleware/.env

# 主机 IP(请修改为实际 IP)
HOST_IP=192.168.1.100

# 数据目录
DATA_PATH=/opt/vortmall/data

# MySQL
MYSQL_ROOT_PASSWORD=vortmall666

# MinIO
MINIO_USER=vortmall
MINIO_PASSWORD=vortmall666

# Elasticsearch
ES_PASSWORD=vortmall666

# EMQX
EMQX_PASSWORD=vortmall666

3.4 配置文件准备

MySQL 配置

创建 /opt/vortmall/data/mysql/conf/my.cnf

[mysqld]
# 基础配置
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
default-time-zone='+08:00'

# 连接配置
max_connections=1000
max_connect_errors=100

# InnoDB 配置
innodb_buffer_pool_size=512M
innodb_log_file_size=256M
innodb_flush_log_at_trx_commit=2
innodb_lock_wait_timeout=50

# 日志配置
slow_query_log=1
slow_query_log_file=/var/log/mysql/slow.log
long_query_time=2
log_queries_not_using_indexes=1

# Binlog 配置
server-id=1
log-bin=mysql-bin
binlog_format=ROW
expire_logs_days=7

[mysql]
default-character-set=utf8mb4

[client]
default-character-set=utf8mb4

Redis 配置

创建 /opt/vortmall/data/redis/conf/redis.conf

# 绑定地址
bind 0.0.0.0

# 端口
port 6379

# 密码(生产环境建议设置)
# requirepass vortmall666

# 持久化
appendonly yes
appendfsync everysec

# 内存配置
maxmemory 1gb
maxmemory-policy allkeys-lru

# 日志
loglevel notice

# 连接
tcp-keepalive 300
timeout 0

RocketMQ Broker 配置

创建 /opt/vortmall/middleware/rocketmq/broker.conf

brokerClusterName=DefaultCluster
brokerName=broker-a
brokerId=0
deleteWhen=04
fileReservedTime=48
brokerRole=ASYNC_MASTER
flushDiskType=ASYNC_FLUSH

# 需要修改为实际 IP
namesrvAddr=rocketmq-namesrv:9876
brokerIP1=192.168.1.100

# 自动创建 Topic
autoCreateTopicEnable=true
autoCreateSubscriptionGroup=true

3.5 初始化数据库脚本

创建 /opt/vortmall/data/mysql/init/01-init-databases.sql

-- 创建 Nacos 数据库
CREATE DATABASE IF NOT EXISTS `nacos_config` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 创建 XXL-JOB 数据库
CREATE DATABASE IF NOT EXISTS `xxl_job` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 创建 Seata 数据库
CREATE DATABASE IF NOT EXISTS `seata` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 创建业务数据库
CREATE DATABASE IF NOT EXISTS `vortmall-user` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE IF NOT EXISTS `vortmall-product` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE IF NOT EXISTS `vortmall-order` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE IF NOT EXISTS `vortmall-payment` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE IF NOT EXISTS `vortmall-system` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE IF NOT EXISTS `vortmall-marketing` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE IF NOT EXISTS `vortmall-content` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE IF NOT EXISTS `vortmall-organize` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE IF NOT EXISTS `vortmall-logistics` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE IF NOT EXISTS `vortmall-aftersales` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE IF NOT EXISTS `vortmall-distribution` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE IF NOT EXISTS `vortmall-decoration` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE IF NOT EXISTS `vortmall-message` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE IF NOT EXISTS `vortmall-file` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE IF NOT EXISTS `vortmall-pos` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 创建应用账号
CREATE USER IF NOT EXISTS 'vortmall'@'%' IDENTIFIED BY 'vortmall666';
GRANT ALL PRIVILEGES ON `vortmall-%`.* TO 'vortmall'@'%';
GRANT ALL PRIVILEGES ON `nacos_config`.* TO 'vortmall'@'%';
GRANT ALL PRIVILEGES ON `xxl_job`.* TO 'vortmall'@'%';
GRANT ALL PRIVILEGES ON `seata`.* TO 'vortmall'@'%';
FLUSH PRIVILEGES;

3.6 启动中间件

cd /opt/vortmall/middleware

# 第一步:启动核心中间件
docker compose up -d mysql redis

# 等待 MySQL 完全启动(查看日志)
docker compose logs -f mysql
# 看到 "ready for connections" 后 Ctrl+C 退出

# 第二步:启动 Nacos
docker compose up -d nacos

# 等待 Nacos 启动完成
docker compose logs -f nacos
# 看到 "Nacos started successfully" 后 Ctrl+C 退出

# 第三步:启动消息队列和其他服务
docker compose up -d rocketmq-namesrv rocketmq-broker rocketmq-dashboard
docker compose up -d xxl-job-admin minio

# 第四步(可选):启动扩展服务
docker compose up -d seata-server emqx
docker compose up -d elasticsearch kibana
docker compose up -d skywalking-oap skywalking-ui

# 查看所有容器状态
docker compose ps

4. 镜像构建

4.1 基础 Dockerfile

创建 /opt/vortmall/apps/Dockerfile.base(通用基础镜像):

FROM eclipse-temurin:21-jre-alpine

LABEL maintainer="VortMall Team <admin@vortmall.com>"

# 设置时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# 安装常用工具
RUN apk add --no-cache curl tzdata

# 创建应用用户
RUN addgroup -g 1000 vortmall && \
    adduser -u 1000 -G vortmall -s /bin/sh -D vortmall

# 创建目录
RUN mkdir -p /app/logs && chown -R vortmall:vortmall /app

# 设置工作目录
WORKDIR /app

# 切换用户
USER vortmall

# 健康检查(子镜像覆盖)
HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=60s \
    CMD curl -sf http://localhost:8080/actuator/health || exit 1

4.2 服务 Dockerfile 模板

创建各服务的 Dockerfile,以 Gateway 为例 /opt/vortmall/apps/gateway/Dockerfile

FROM vortmall/base:latest

LABEL service="vortmall-gateway"

# 设置 JVM 参数
ENV JAVA_OPTS="-Xms512m -Xmx512m -XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/logs/heapdump.hprof"

# 复制 JAR 包
COPY --chown=vortmall:vortmall vortmall-gateway-*.jar app.jar

# 暴露端口
EXPOSE 8000

# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=60s \
    CMD curl -sf http://localhost:8000/actuator/health || exit 1

# 启动命令
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar app.jar"]

4.3 批量构建脚本

创建 /opt/vortmall/scripts/build-images.sh

#!/bin/bash

set -e

# 配置
REGISTRY="registry.cn-hangzhou.aliyuncs.com/vortmall"
VERSION="${1:-latest}"
PROJECT_PATH="${2:-/path/to/vortmall-api}"

echo "========================================"
echo "VortMall Docker 镜像构建"
echo "版本: $VERSION"
echo "========================================"

# 编译项目
echo ">>> 编译项目..."
cd $PROJECT_PATH
mvn clean package -DskipTests -T 4

# 构建基础镜像
echo ">>> 构建基础镜像..."
docker build -t vortmall/base:latest -f /opt/vortmall/apps/Dockerfile.base .

# 服务列表
declare -A SERVICES=(
    ["gateway"]="vortmall-gateway/target"
    ["auth"]="vortmall-auth/target"
    ["biz-user"]="vortmall-biz/vortmall-biz-user/target"
    ["biz-product"]="vortmall-biz/vortmall-biz-product/target"
    ["biz-order"]="vortmall-biz/vortmall-biz-order/target"
    ["biz-payment"]="vortmall-biz/vortmall-biz-payment/target"
    ["biz-system"]="vortmall-biz/vortmall-biz-system/target"
    ["biz-marketing"]="vortmall-biz/vortmall-biz-marketing/target"
    ["biz-content"]="vortmall-biz/vortmall-biz-content/target"
    ["biz-organize"]="vortmall-biz/vortmall-biz-organize/target"
    ["biz-logistics"]="vortmall-biz/vortmall-biz-logistics/target"
    ["biz-aftersales"]="vortmall-biz/vortmall-biz-aftersales/target"
    ["biz-distribution"]="vortmall-biz/vortmall-biz-distribution/target"
    ["biz-decoration"]="vortmall-biz/vortmall-biz-decoration/target"
    ["biz-message"]="vortmall-biz/vortmall-biz-message/target"
    ["biz-file"]="vortmall-biz/vortmall-biz-file/target"
    ["biz-pos"]="vortmall-biz/vortmall-biz-pos/target"
)

# 构建服务镜像
for SERVICE in "${!SERVICES[@]}"; do
    JAR_PATH="${SERVICES[$SERVICE]}"
    IMAGE_NAME="vortmall/$SERVICE:$VERSION"
    
    echo ">>> 构建镜像: $IMAGE_NAME"
    
    # 创建临时构建目录
    BUILD_DIR="/tmp/vortmall-build-$SERVICE"
    mkdir -p $BUILD_DIR
    
    # 复制 JAR 和 Dockerfile
    cp $PROJECT_PATH/$JAR_PATH/*.jar $BUILD_DIR/
    
    # 生成 Dockerfile
    cat > $BUILD_DIR/Dockerfile <<EOF
FROM vortmall/base:latest
LABEL service="vortmall-$SERVICE"
ENV JAVA_OPTS="-Xms256m -Xmx256m -XX:+UseG1GC"
COPY --chown=vortmall:vortmall *.jar app.jar
EXPOSE 8080
ENTRYPOINT ["sh", "-c", "java \$JAVA_OPTS -jar app.jar"]
EOF
    
    # 构建镜像
    docker build -t $IMAGE_NAME $BUILD_DIR
    
    # 清理
    rm -rf $BUILD_DIR
    
    echo ">>> 完成: $IMAGE_NAME"
done

echo "========================================"
echo "所有镜像构建完成!"
echo "========================================"

# 列出构建的镜像
docker images | grep vortmall

4.4 推送到镜像仓库

# 登录阿里云镜像仓库
docker login --username=your-username registry.cn-hangzhou.aliyuncs.com

# 标记镜像
docker tag vortmall/gateway:latest registry.cn-hangzhou.aliyuncs.com/vortmall/gateway:latest

# 推送镜像
docker push registry.cn-hangzhou.aliyuncs.com/vortmall/gateway:latest

# 批量推送脚本
for image in $(docker images --format "{{.Repository}}:{{.Tag}}" | grep "^vortmall/"); do
    remote_image="registry.cn-hangzhou.aliyuncs.com/$image"
    docker tag $image $remote_image
    docker push $remote_image
done

5. 业务服务部署

5.1 业务服务 docker-compose.yml

创建 /opt/vortmall/apps/docker-compose.yml

version: '3.8'

services:
  # ==================== 核心服务 ====================

  gateway:
    image: vortmall/gateway:${VERSION:-latest}
    container_name: vortmall-gateway
    restart: always
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - VORTMALL_HOST=${MIDDLEWARE_HOST}
      - JAVA_OPTS=-Xms512m -Xmx512m
      - TZ=Asia/Shanghai
    ports:
      - "8000:8000"
    volumes:
      - ${LOG_PATH}/gateway:/app/logs
    healthcheck:
      test: ["CMD", "curl", "-sf", "http://localhost:8000/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    networks:
      - vortmall-network
    depends_on:
      - auth

  auth:
    image: vortmall/auth:${VERSION:-latest}
    container_name: vortmall-auth
    restart: always
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - VORTMALL_HOST=${MIDDLEWARE_HOST}
      - JAVA_OPTS=-Xms256m -Xmx256m
      - TZ=Asia/Shanghai
    ports:
      - "8001:8001"
    volumes:
      - ${LOG_PATH}/auth:/app/logs
    healthcheck:
      test: ["CMD", "curl", "-sf", "http://localhost:8001/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    networks:
      - vortmall-network

  # ==================== 业务服务 ====================

  biz-user:
    image: vortmall/biz-user:${VERSION:-latest}
    container_name: vortmall-biz-user
    restart: always
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - VORTMALL_HOST=${MIDDLEWARE_HOST}
      - JAVA_OPTS=-Xms512m -Xmx512m
      - TZ=Asia/Shanghai
    ports:
      - "19913:19913"
    volumes:
      - ${LOG_PATH}/biz-user:/app/logs
    healthcheck:
      test: ["CMD", "curl", "-sf", "http://localhost:19913/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    networks:
      - vortmall-network

  biz-product:
    image: vortmall/biz-product:${VERSION:-latest}
    container_name: vortmall-biz-product
    restart: always
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - VORTMALL_HOST=${MIDDLEWARE_HOST}
      - JAVA_OPTS=-Xms512m -Xmx512m
      - TZ=Asia/Shanghai
    ports:
      - "19901:19901"
    volumes:
      - ${LOG_PATH}/biz-product:/app/logs
    healthcheck:
      test: ["CMD", "curl", "-sf", "http://localhost:19901/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    networks:
      - vortmall-network

  biz-order:
    image: vortmall/biz-order:${VERSION:-latest}
    container_name: vortmall-biz-order
    restart: always
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - VORTMALL_HOST=${MIDDLEWARE_HOST}
      - JAVA_OPTS=-Xms512m -Xmx512m
      - TZ=Asia/Shanghai
    ports:
      - "19905:19905"
    volumes:
      - ${LOG_PATH}/biz-order:/app/logs
    healthcheck:
      test: ["CMD", "curl", "-sf", "http://localhost:19905/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    networks:
      - vortmall-network

  biz-payment:
    image: vortmall/biz-payment:${VERSION:-latest}
    container_name: vortmall-biz-payment
    restart: always
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - VORTMALL_HOST=${MIDDLEWARE_HOST}
      - JAVA_OPTS=-Xms256m -Xmx256m
      - TZ=Asia/Shanghai
    ports:
      - "19902:19902"
    volumes:
      - ${LOG_PATH}/biz-payment:/app/logs
    networks:
      - vortmall-network

  biz-system:
    image: vortmall/biz-system:${VERSION:-latest}
    container_name: vortmall-biz-system
    restart: always
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - VORTMALL_HOST=${MIDDLEWARE_HOST}
      - JAVA_OPTS=-Xms256m -Xmx256m
      - TZ=Asia/Shanghai
    ports:
      - "19903:19903"
    volumes:
      - ${LOG_PATH}/biz-system:/app/logs
    networks:
      - vortmall-network

  biz-marketing:
    image: vortmall/biz-marketing:${VERSION:-latest}
    container_name: vortmall-biz-marketing
    restart: always
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - VORTMALL_HOST=${MIDDLEWARE_HOST}
      - JAVA_OPTS=-Xms256m -Xmx256m
      - TZ=Asia/Shanghai
    ports:
      - "19904:19904"
    volumes:
      - ${LOG_PATH}/biz-marketing:/app/logs
    networks:
      - vortmall-network

  biz-content:
    image: vortmall/biz-content:${VERSION:-latest}
    container_name: vortmall-biz-content
    restart: always
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - VORTMALL_HOST=${MIDDLEWARE_HOST}
      - JAVA_OPTS=-Xms256m -Xmx256m
      - TZ=Asia/Shanghai
    ports:
      - "19906:19906"
    volumes:
      - ${LOG_PATH}/biz-content:/app/logs
    networks:
      - vortmall-network

  biz-organize:
    image: vortmall/biz-organize:${VERSION:-latest}
    container_name: vortmall-biz-organize
    restart: always
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - VORTMALL_HOST=${MIDDLEWARE_HOST}
      - JAVA_OPTS=-Xms256m -Xmx256m
      - TZ=Asia/Shanghai
    ports:
      - "19907:19907"
    volumes:
      - ${LOG_PATH}/biz-organize:/app/logs
    networks:
      - vortmall-network

  biz-logistics:
    image: vortmall/biz-logistics:${VERSION:-latest}
    container_name: vortmall-biz-logistics
    restart: always
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - VORTMALL_HOST=${MIDDLEWARE_HOST}
      - JAVA_OPTS=-Xms256m -Xmx256m
      - TZ=Asia/Shanghai
    ports:
      - "19908:19908"
    volumes:
      - ${LOG_PATH}/biz-logistics:/app/logs
    networks:
      - vortmall-network

  biz-aftersales:
    image: vortmall/biz-aftersales:${VERSION:-latest}
    container_name: vortmall-biz-aftersales
    restart: always
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - VORTMALL_HOST=${MIDDLEWARE_HOST}
      - JAVA_OPTS=-Xms256m -Xmx256m
      - TZ=Asia/Shanghai
    ports:
      - "19909:19909"
    volumes:
      - ${LOG_PATH}/biz-aftersales:/app/logs
    networks:
      - vortmall-network

  biz-distribution:
    image: vortmall/biz-distribution:${VERSION:-latest}
    container_name: vortmall-biz-distribution
    restart: always
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - VORTMALL_HOST=${MIDDLEWARE_HOST}
      - JAVA_OPTS=-Xms256m -Xmx256m
      - TZ=Asia/Shanghai
    ports:
      - "19910:19910"
    volumes:
      - ${LOG_PATH}/biz-distribution:/app/logs
    networks:
      - vortmall-network

  biz-decoration:
    image: vortmall/biz-decoration:${VERSION:-latest}
    container_name: vortmall-biz-decoration
    restart: always
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - VORTMALL_HOST=${MIDDLEWARE_HOST}
      - JAVA_OPTS=-Xms256m -Xmx256m
      - TZ=Asia/Shanghai
    ports:
      - "19911:19911"
    volumes:
      - ${LOG_PATH}/biz-decoration:/app/logs
    networks:
      - vortmall-network

  biz-message:
    image: vortmall/biz-message:${VERSION:-latest}
    container_name: vortmall-biz-message
    restart: always
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - VORTMALL_HOST=${MIDDLEWARE_HOST}
      - JAVA_OPTS=-Xms256m -Xmx256m
      - TZ=Asia/Shanghai
    ports:
      - "19912:19912"
    volumes:
      - ${LOG_PATH}/biz-message:/app/logs
    networks:
      - vortmall-network

  biz-file:
    image: vortmall/biz-file:${VERSION:-latest}
    container_name: vortmall-biz-file
    restart: always
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - VORTMALL_HOST=${MIDDLEWARE_HOST}
      - JAVA_OPTS=-Xms256m -Xmx256m
      - TZ=Asia/Shanghai
    ports:
      - "19914:19914"
    volumes:
      - ${LOG_PATH}/biz-file:/app/logs
    networks:
      - vortmall-network

  biz-pos:
    image: vortmall/biz-pos:${VERSION:-latest}
    container_name: vortmall-biz-pos
    restart: always
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - VORTMALL_HOST=${MIDDLEWARE_HOST}
      - JAVA_OPTS=-Xms256m -Xmx256m
      - TZ=Asia/Shanghai
    ports:
      - "19915:19915"
    volumes:
      - ${LOG_PATH}/biz-pos:/app/logs
    networks:
      - vortmall-network

networks:
  vortmall-network:
    external: true
    name: middleware_vortmall-network

5.2 业务服务环境变量

创建 /opt/vortmall/apps/.env

# 版本号
VERSION=latest

# 中间件服务器地址
MIDDLEWARE_HOST=192.168.1.100

# 日志目录
LOG_PATH=/opt/vortmall/logs

5.3 启动业务服务

cd /opt/vortmall/apps

# 启动所有服务
docker compose up -d

# 查看服务状态
docker compose ps

# 查看日志
docker compose logs -f gateway

6. 网络配置

6.1 Docker 网络架构

┌─────────────────────────────────────────────────────────────────────────┐
│                         Docker Network: vortmall-network                │
│                              (172.20.0.0/16)                            │
│                                                                         │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │                         中间件服务                               │   │
│  │                                                                   │   │
│  │  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐   │   │
│  │  │  MySQL  │ │  Redis  │ │  Nacos  │ │RocketMQ │ │  MinIO  │   │   │
│  │  │ :3306   │ │ :6379   │ │ :8848   │ │ :9876   │ │ :9000   │   │   │
│  │  └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘   │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                   │                                     │
│                                   │ 内网通信                            │
│                                   ▼                                     │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │                         业务服务                                 │   │
│  │                                                                   │   │
│  │  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐   │   │
│  │  │ Gateway │ │  Auth   │ │  User   │ │ Product │ │  Order  │   │   │
│  │  │ :8000   │ │ :8001   │ │ :19913  │ │ :19901  │ │ :19905  │   │   │
│  │  └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘   │   │
│  │                                                                   │   │
│  │  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐   │   │
│  │  │ Payment │ │ System  │ │Marketing│ │ Content │ │   ...   │   │   │
│  │  │ :19902  │ │ :19903  │ │ :19904  │ │ :19906  │ │         │   │   │
│  │  └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘   │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                   │                                     │
└───────────────────────────────────│─────────────────────────────────────┘
                                    │ 端口映射
                                    ▼
                    ┌───────────────────────────────┐
                    │          宿主机端口            │
                    │   8000, 8848, 3306, 6379...   │
                    └───────────────────────────────┘

6.2 创建 Docker 网络

# 创建自定义网络
docker network create --driver bridge --subnet 172.20.0.0/16 vortmall-network

# 查看网络
docker network ls

# 查看网络详情
docker network inspect vortmall-network

6.3 服务间通信

容器间通过服务名称直接访问:

# 应用配置示例
spring:
  datasource:
    url: jdbc:mysql://vortmall-mysql:3306/vortmall-user
  redis:
    host: vortmall-redis
  cloud:
    nacos:
      discovery:
        server-addr: vortmall-nacos:8848

7. 数据持久化

7.1 数据目录结构

/opt/vortmall/data/
├── mysql/
│   ├── data/           # MySQL 数据文件
│   ├── conf/           # MySQL 配置
│   └── init/           # 初始化脚本
├── redis/
│   ├── data/           # Redis 数据
│   └── conf/           # Redis 配置
├── nacos/
│   └── logs/           # Nacos 日志
├── rocketmq/
│   ├── namesrv/logs/   # NameServer 日志
│   └── broker/
│       ├── logs/       # Broker 日志
│       └── store/      # 消息存储
├── minio/
│   └── data/           # MinIO 数据
├── elasticsearch/
│   ├── data/           # ES 数据
│   ├── plugins/        # ES 插件
│   └── logs/           # ES 日志
├── seata/
│   └── logs/           # Seata 日志
└── emqx/
    ├── data/           # EMQX 数据
    └── log/            # EMQX 日志

7.2 备份策略

创建 /opt/vortmall/scripts/backup.sh

#!/bin/bash

set -e

# 配置
BACKUP_DIR="/opt/vortmall/backup"
DATE=$(date +%Y%m%d_%H%M%S)
MYSQL_CONTAINER="vortmall-mysql"
MYSQL_PASSWORD="vortmall666"

# 创建备份目录
mkdir -p $BACKUP_DIR/$DATE

echo "=========================================="
echo "VortMall 数据备份 - $DATE"
echo "=========================================="

# 1. 备份 MySQL
echo ">>> 备份 MySQL..."
docker exec $MYSQL_CONTAINER mysqldump -uroot -p$MYSQL_PASSWORD \
    --all-databases \
    --single-transaction \
    --quick \
    --lock-tables=false \
    > $BACKUP_DIR/$DATE/mysql_all_databases.sql

# 压缩 SQL 文件
gzip $BACKUP_DIR/$DATE/mysql_all_databases.sql
echo "MySQL 备份完成: mysql_all_databases.sql.gz"

# 2. 备份 Redis
echo ">>> 备份 Redis..."
docker exec vortmall-redis redis-cli BGSAVE
sleep 5
docker cp vortmall-redis:/data/dump.rdb $BACKUP_DIR/$DATE/redis_dump.rdb
echo "Redis 备份完成: redis_dump.rdb"

# 3. 备份 Nacos 配置
echo ">>> 备份 Nacos 配置..."
curl -X GET "http://localhost:8848/nacos/v1/cs/configs?dataId=&group=&appName=&config_tags=&pageNo=1&pageSize=100&tenant=&search=blur" \
    -u nacos:nacos \
    -o $BACKUP_DIR/$DATE/nacos_config.json 2>/dev/null || echo "Nacos 备份需要手动导出"

# 4. 备份 MinIO 数据
echo ">>> 备份 MinIO..."
tar -czf $BACKUP_DIR/$DATE/minio_data.tar.gz -C /opt/vortmall/data minio/

# 5. 计算备份大小
BACKUP_SIZE=$(du -sh $BACKUP_DIR/$DATE | cut -f1)
echo "备份大小: $BACKUP_SIZE"

# 6. 清理旧备份(保留 7 天)
echo ">>> 清理旧备份..."
find $BACKUP_DIR -type d -mtime +7 -exec rm -rf {} + 2>/dev/null || true

echo "=========================================="
echo "备份完成!"
echo "备份目录: $BACKUP_DIR/$DATE"
echo "=========================================="

7.3 定时备份

# 设置执行权限
chmod +x /opt/vortmall/scripts/backup.sh

# 添加定时任务(每天凌晨 3 点)
crontab -e
0 3 * * * /opt/vortmall/scripts/backup.sh >> /opt/vortmall/logs/backup.log 2>&1

8. 日志管理

8.1 日志目录结构

/opt/vortmall/logs/
├── gateway/
│   ├── app.log              # 应用日志
│   ├── error.log            # 错误日志
│   └── gc.log               # GC 日志
├── auth/
├── biz-user/
├── biz-product/
├── biz-order/
└── ...

8.2 日志轮转配置

创建 /etc/logrotate.d/vortmall

/opt/vortmall/logs/*/*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 0644 vortmall vortmall
    sharedscripts
    postrotate
        # 如果需要通知应用
    endscript
}

8.3 日志查看命令

# 查看容器日志
docker logs -f vortmall-gateway

# 查看最近 100 行
docker logs --tail 100 vortmall-gateway

# 查看指定时间段
docker logs --since="2024-01-01T00:00:00" --until="2024-01-01T01:00:00" vortmall-gateway

# 实时查看多个服务日志
docker compose logs -f gateway auth biz-user

# 查看应用日志文件
tail -f /opt/vortmall/logs/gateway/app.log

# 搜索错误日志
grep -r "ERROR" /opt/vortmall/logs/*/error.log

9. 健康检查与监控

9.1 健康检查脚本

创建 /opt/vortmall/scripts/health-check.sh

#!/bin/bash

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

echo "=========================================="
echo "VortMall 健康检查 - $(date '+%Y-%m-%d %H:%M:%S')"
echo "=========================================="

# 中间件检查
echo -e "\n${YELLOW}>>> 中间件状态${NC}"

check_service() {
    local name=$1
    local url=$2
    local response=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 "$url" 2>/dev/null)
    
    if [ "$response" == "200" ] || [ "$response" == "301" ] || [ "$response" == "302" ]; then
        echo -e "${GREEN}[OK]${NC} $name"
        return 0
    else
        echo -e "${RED}[FAIL]${NC} $name (HTTP $response)"
        return 1
    fi
}

check_tcp() {
    local name=$1
    local host=$2
    local port=$3
    
    if nc -z -w 5 $host $port 2>/dev/null; then
        echo -e "${GREEN}[OK]${NC} $name ($host:$port)"
        return 0
    else
        echo -e "${RED}[FAIL]${NC} $name ($host:$port)"
        return 1
    fi
}

# 中间件
check_tcp "MySQL" "localhost" 3306
check_tcp "Redis" "localhost" 6379
check_service "Nacos" "http://localhost:8848/nacos/v1/console/health/readiness"
check_tcp "RocketMQ NameServer" "localhost" 9876
check_service "XXL-JOB" "http://localhost:8082/xxl-job-admin"
check_service "MinIO" "http://localhost:9000/minio/health/live"

# 业务服务检查
echo -e "\n${YELLOW}>>> 业务服务状态${NC}"

declare -A SERVICES=(
    ["Gateway"]="http://localhost:8000/actuator/health"
    ["Auth"]="http://localhost:8001/actuator/health"
    ["User"]="http://localhost:19913/actuator/health"
    ["Product"]="http://localhost:19901/actuator/health"
    ["Order"]="http://localhost:19905/actuator/health"
    ["Payment"]="http://localhost:19902/actuator/health"
    ["System"]="http://localhost:19903/actuator/health"
    ["Marketing"]="http://localhost:19904/actuator/health"
)

FAILED=0
for SERVICE in "${!SERVICES[@]}"; do
    if ! check_service "$SERVICE" "${SERVICES[$SERVICE]}"; then
        FAILED=$((FAILED + 1))
    fi
done

# Docker 容器状态
echo -e "\n${YELLOW}>>> Docker 容器状态${NC}"
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep vortmall

# 资源使用情况
echo -e "\n${YELLOW}>>> 资源使用情况${NC}"
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}" | grep vortmall

# 磁盘使用
echo -e "\n${YELLOW}>>> 磁盘使用${NC}"
df -h /opt/vortmall

# 总结
echo -e "\n=========================================="
if [ $FAILED -eq 0 ]; then
    echo -e "${GREEN}所有服务正常运行!${NC}"
else
    echo -e "${RED}$FAILED 个服务异常,请检查!${NC}"
fi
echo "=========================================="

9.2 Prometheus + Grafana 监控(可选)

创建 /opt/vortmall/middleware/monitoring/docker-compose.yml

version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: vortmall-prometheus
    restart: always
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/usr/share/prometheus/console_libraries'
      - '--web.console.templates=/usr/share/prometheus/consoles'
    networks:
      - vortmall-network

  grafana:
    image: grafana/grafana:latest
    container_name: vortmall-grafana
    restart: always
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=vortmall666
    volumes:
      - grafana_data:/var/lib/grafana
    networks:
      - vortmall-network

volumes:
  prometheus_data:
  grafana_data:

networks:
  vortmall-network:
    external: true
    name: middleware_vortmall-network

10. 运维操作

10.1 一键启动脚本

创建 /opt/vortmall/scripts/start.sh

#!/bin/bash

set -e

echo "=========================================="
echo "VortMall 一键启动"
echo "=========================================="

cd /opt/vortmall

# 启动中间件
echo ">>> 启动中间件..."
cd middleware
docker compose up -d mysql redis
sleep 30

docker compose up -d nacos
sleep 30

docker compose up -d rocketmq-namesrv rocketmq-broker xxl-job-admin minio
sleep 10

# 启动业务服务
echo ">>> 启动业务服务..."
cd ../apps
docker compose up -d

# 等待服务启动
echo ">>> 等待服务启动(60秒)..."
sleep 60

# 健康检查
echo ">>> 执行健康检查..."
/opt/vortmall/scripts/health-check.sh

echo "=========================================="
echo "启动完成!"
echo "=========================================="

10.2 一键停止脚本

创建 /opt/vortmall/scripts/stop.sh

#!/bin/bash

echo "=========================================="
echo "VortMall 一键停止"
echo "=========================================="

cd /opt/vortmall

# 停止业务服务
echo ">>> 停止业务服务..."
cd apps
docker compose down

# 停止中间件
echo ">>> 停止中间件..."
cd ../middleware
docker compose down

echo "=========================================="
echo "停止完成!"
echo "=========================================="

10.3 服务更新脚本

创建 /opt/vortmall/scripts/update.sh

#!/bin/bash

SERVICE=$1
VERSION=${2:-latest}

if [ -z "$SERVICE" ]; then
    echo "用法: $0 <服务名> [版本号]"
    echo "示例: $0 gateway 1.0.1"
    exit 1
fi

echo "=========================================="
echo "更新服务: $SERVICE"
echo "版本: $VERSION"
echo "=========================================="

cd /opt/vortmall/apps

# 拉取新镜像
echo ">>> 拉取镜像..."
docker compose pull $SERVICE

# 重启服务
echo ">>> 重启服务..."
docker compose up -d --no-deps $SERVICE

# 等待启动
sleep 30

# 检查状态
echo ">>> 检查状态..."
docker compose ps $SERVICE

echo "=========================================="
echo "更新完成!"
echo "=========================================="

10.4 常用运维命令

# 查看所有容器
docker ps -a | grep vortmall

# 重启单个服务
docker compose -f /opt/vortmall/apps/docker-compose.yml restart gateway

# 查看服务日志
docker logs -f vortmall-gateway --tail 100

# 进入容器
docker exec -it vortmall-gateway sh

# 查看资源使用
docker stats --no-stream | grep vortmall

# 清理无用镜像
docker image prune -a

# 清理无用卷
docker volume prune

# 查看网络
docker network inspect middleware_vortmall-network

11. 常见问题

Q1: 容器启动后立即退出

排查步骤

# 查看容器日志
docker logs vortmall-gateway

# 查看容器详情
docker inspect vortmall-gateway

# 检查退出代码
docker ps -a | grep vortmall-gateway

常见原因

  • 内存不足:增加 JVM 堆内存或服务器内存
  • 配置错误:检查环境变量和配置文件
  • 依赖服务未启动:确保 Nacos、MySQL 等已启动

Q2: 服务注册不到 Nacos

排查

# 检查 Nacos 状态
curl http://localhost:8848/nacos/v1/console/health/readiness

# 检查网络连通性
docker exec vortmall-gateway ping vortmall-nacos

# 检查服务列表
curl "http://localhost:8848/nacos/v1/ns/service/list?pageNo=1&pageSize=10"

Q3: MySQL 连接失败

排查

# 检查 MySQL 容器
docker logs vortmall-mysql

# 测试连接
docker exec vortmall-mysql mysql -uroot -pvortmall666 -e "show databases;"

# 检查网络
docker exec vortmall-gateway nc -zv vortmall-mysql 3306

Q4: 端口被占用

# 查看端口占用
netstat -tlnp | grep 8000

# 或者
ss -tlnp | grep 8000

# 停止占用进程
kill -9 <PID>

Q5: 磁盘空间不足

# 查看磁盘使用
df -h

# 清理 Docker
docker system prune -a --volumes

# 清理日志
truncate -s 0 /opt/vortmall/logs/*/*.log

Q6: 内存不足

# 查看内存使用
free -h

# 查看容器内存
docker stats --no-stream

# 调整 JVM 参数(在 docker-compose.yml 中)
environment:
  - JAVA_OPTS=-Xms256m -Xmx256m

Q7: 时区问题

确保所有容器设置正确时区:

environment:
  - TZ=Asia/Shanghai
volumes:
  - /etc/localtime:/etc/localtime:ro

附录

A. 端口清单

服务端口说明
Gateway8000API 网关
Auth8001认证服务
MySQL3306数据库
Redis6379缓存
Nacos8848, 9848注册中心
RocketMQ9876, 10911消息队列
XXL-JOB8082任务调度
MinIO9000, 9001文件存储
Elasticsearch9200搜索引擎
Kibana5601ES 可视化
SkyWalking11800, 12800, 18080链路追踪

B. 默认账号密码

服务账号密码
MySQLrootvortmall666
Nacosnacosnacos
MinIOvortmallvortmall666
XXL-JOBadmin123456
Elasticsearchelasticvortmall666
Grafanaadminvortmall666

C. 参考文档

VortMall Docker 部署指南
请输入搜索内容
大纲
VortMall Docker 部署指南
目录
1. 环境准备
1.1 系统要求
1.2 安装 Docker
CentOS / RHEL / Alibaba Cloud Linux
Ubuntu / Debian
1.3 Docker 配置优化
1.4 系统参数优化
2. 目录结构规划
2.1 创建部署目录
2.2 复制项目部署文件
3. 中间件部署
3.1 中间件清单
3.2 中间件 docker-compose.yml
3.3 环境变量配置
3.4 配置文件准备
MySQL 配置
Redis 配置
RocketMQ Broker 配置
3.5 初始化数据库脚本
3.6 启动中间件
4. 镜像构建
4.1 基础 Dockerfile
4.2 服务 Dockerfile 模板
4.3 批量构建脚本
4.4 推送到镜像仓库
5. 业务服务部署
5.1 业务服务 docker-compose.yml
5.2 业务服务环境变量
5.3 启动业务服务
6. 网络配置
6.1 Docker 网络架构
6.2 创建 Docker 网络
6.3 服务间通信
7. 数据持久化
7.1 数据目录结构
7.2 备份策略
7.3 定时备份
8. 日志管理
8.1 日志目录结构
8.2 日志轮转配置
8.3 日志查看命令
9. 健康检查与监控
9.1 健康检查脚本
9.2 Prometheus + Grafana 监控(可选)
10. 运维操作
10.1 一键启动脚本
10.2 一键停止脚本
10.3 服务更新脚本
10.4 常用运维命令
11. 常见问题
Q1: 容器启动后立即退出
Q2: 服务注册不到 Nacos
Q3: MySQL 连接失败
Q4: 端口被占用
Q5: 磁盘空间不足
Q6: 内存不足
Q7: 时区问题
附录
A. 端口清单
B. 默认账号密码
C. 参考文档