VortMall Docker 部署指南
14
类别: 
生产部署

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. 参考文档

评论 0
/ 1000
0
0
收藏