Skip to content

部署文档

部署准备

最低服务器配置

2核16G内存服务器一台(推荐使用 CentOS 7.6 64位)(如果基础中间件使用外部服务器的,则可以适量减少内存)

docker-compose环境安装

  • 安装docker-compose环境(已经安装的可以略过)
#安装git
sudo yum install -y git
#安装maven
sudo yum install -y maven
#安装依赖
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
#设置源
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sudo yum makecache fast
#安装docker
sudo yum install -y docker-ce
#启动服务
sudo systemctl start docker
#安装docker-compose
curl -L https://github.com/docker/compose/releases/download/v2.17.1/docker-compose-linux-x86_64 > /usr/local/bin/docker-compose
#授权
sudo chmod +x /usr/local/bin/docker-compose
#检测版本号
docker-compose -v
  • docker脚本下载
git clone https://gitee.com/beijing_hongye_huicheng/docker.git
  • Rocketmq 需要特殊配制一下节点ip

    在 config/broker.conf 文件中,将brokerIP1修改为部署docker的局域网ip

  • 运行脚本

    必须保证es本地挂载目录权限为 777 否则es启动不成功。默认es本地挂载目录为docker项目上一级的volumes/data

docker-compose up -d
  • 校验 (查看进程是否启动,如果反复启动的程序,可以使用docker logs 镜像id 查看日志)
docker ps

API部署

  • 下载源码
cd /home/source
git clone https://gitee.com/beijing_hongye_huicheng/lilishop.git
  • 编辑运行API的脚本
vi pg_start_api1.sh

脚本内容:

#!/bin/bash
# 开启 Fail-Fast 机制:除了交互式选择和特定检查外,关键命令执行失败(返回非 0)会立即退出验证环节
# 由于带有交互逻辑,这里不全局 set -e,而是在关键函数中处理错误

# ==========================================
# 统一变量与配置区 (Configuration Zone)
# ==========================================
version="4.3"
max_wait_seconds=60 
code_path="/home/source/lilishop"
run_path="/home/source/api/"

# 定义所有服务名称数组(用于遍历和菜单选择)
service_names=("buyer" "manager" "im")

# 声明服务配置映射 (服务名对应 -> PID关键词:端口:JAR包名:JVM参数)
# 注意:Bash 3不支持关联数组声明,这里用 case 语句实现配置获取以兼容所有版本
get_service_config() {
    local s_name=$1
    case $s_name in
        "buyer")    echo "buyer 8083 buyer-api-$version.jar -Xmx1g -Xms256m -Xss512k" ;;
        "manager")  echo "manager 8081 manager-api-$version.jar -Xmx1g -Xms128m -Xss256k" ;;
        "im")       echo "im 8086 im-api-$version.jar -Xmx512m -Xms128m -Xss256k" ;;
        *)          echo "" ;;
    esac
}

# 统一追加的生产环境通用 JVM 参数兜底策略
common_jvm_opts="-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=logs/"

# 打印颜色辅助函数
color_echo() {
    local color=$1
    local text=$2
    case $color in
        "red")    echo -e "\033[31m${text}\033[0m" ;;
        "green")  echo -e "\033[32m${text}\033[0m" ;;
        "yellow") echo -e "\033[33m${text}\033[0m" ;;
        "blue")   echo -e "\033[34m${text}\033[0m" ;;
        *)        echo "$text" ;;
    esac
}

# ==========================================
# 核心功能函数区 (Core Functions)
# ==========================================

# 1. 检查目录
check_env() {
    if [ ! -d "$code_path" ]; then
        color_echo "red" "错误: 代码目录 $code_path 不存在!"
        exit 1
    fi
}

# 2. 拉取代码
pull_code() {
    color_echo "blue" "\n==== [1/4] 更新代码 (Git Pull) ===="
    cd "${code_path}" || exit 1
    git checkout master || { color_echo "red" "Git Checkout 失败"; exit 1; }
    git pull || { color_echo "red" "Git Pull 失败"; exit 1; }
    color_echo "green" "代码更新完成。"
}

# 3. 编译构建
build_code() {
    color_echo "blue" "\n==== [2/4] 构建代码 (Maven Build) ===="
    cd "${code_path}" || exit 1
    # 开启 Maven 多线程构建加速
    mvn clean install -DskipTests -T 1C || { color_echo "red" "Maven 构建失败"; exit 1; }
    color_echo "green" "Maven 构建完成。"
}

# 4. 拷贝与归档
prepare_jars() {
    color_echo "blue" "\n==== [3/4] 归档旧文件,准备新 JAR 包 ===="
    mkdir -p "${run_path}/logs"
    
    # 清理所有旧的 jar 包
    rm -f "${run_path}"/*.jar
    
    # 移动刚才编译好的包
    mv "${code_path}"/buyer-api/target/buyer-api-$version.jar "${run_path}"
    mv "${code_path}"/manager-api/target/manager-api-$version.jar "${run_path}"
    mv "${code_path}"/im-api/target/im-api-$version.jar "${run_path}"
    
    color_echo "green" "JAR 包拷贝完成。"
}

# 5. 停止指定服务 (传all停全部)
stop_services() {
    local target_service=$1
    color_echo "blue" "\n==== [X] 停止服务 (Stop Services) [$target_service] ===="
    
    local s_list=("${service_names[@]}")
    if [ "$target_service" != "all" ]; then
        s_list=("$target_service")
    fi

    for name in "${s_list[@]}"; do
        # 获取对应进程的 PID
        pids=$(ps -ef | grep java | grep "jar" | grep "$name" | grep -v 'grep' | awk '{print $2}')
        if [ -n "$pids" ]; then
            color_echo "yellow" "尝试优雅停机 $name (PID: $pids)..."
            kill -15 $pids
            
            # 等待进程退出,最多等 10 秒
            wait_time=0
            while ps -p $pids > /dev/null 2>&1; do
                sleep 1
                ((wait_time++))
                if [ $wait_time -ge 10 ]; then
                    color_echo "red" "进程未主动退出,执行强制清理 (kill -9)..."
                    kill -9 $pids
                    break
                fi
            done
            color_echo "green" "$name 进程已完全终止。"
        else
            echo "服务 $name 目前未运行。"
        fi
    done
}

# 6. 启动指定服务 (传all起全部)
start_services() {
    local target_service=$1
    color_echo "blue" "\n==== [4/4] 启动服务 (Start Services) [$target_service] ===="
    
    cd "${run_path}" || { color_echo "red" "进入运行目录失败"; exit 1; }
    mkdir -p logs
    
    local s_list=("${service_names[@]}")
    if [ "$target_service" != "all" ]; then
        s_list=("$target_service")
    fi

    for name in "${s_list[@]}"; do
        config_str=$(get_service_config "$name")
        if [ -z "$config_str" ]; then
            color_echo "red" "未找到服务 $name 的配置,跳过。"
            continue
        fi
        
        IFS=' ' read -r app_name port jar_file jvm_opts <<< "$config_str"
        
        # 检查包是否存在
        if [ ! -f "$jar_file" ]; then
             color_echo "red" "错误:运行目录下找不到对应的包 ${jar_file},无法启动该服务!"
             if [ "$target_service" = "all" ]; then continue; else exit 1; fi
        fi
        
        # 归档旧日志 (使用替换时间命名)
        if [ -f "logs/${app_name}.out" ]; then
            # 创建归档目录
            mkdir -p logs/archive
            # 获取当前时间格式: YYYYMMDD_HHMMSS
            local current_time=$(date "+%Y%m%d_%H%M%S")
            # 移动并重命名文件
            mv "logs/${app_name}.out" "logs/archive/${app_name}_${current_time}.out"
        fi
        
        # 启动进程
        nohup java $jvm_opts $common_jvm_opts -jar "$jar_file" --spring.profiles.active=prod > "logs/${app_name}.out" 2>&1 &
        
        echo -n "启动 $app_name 中 (目标端口 $port)..."
        
        # 智能检查:轮询检查端口是否处于 LISTEN 状态
        port_ready=false
        for ((i=1; i<=max_wait_seconds; i++)); do
            if lsof -i :$port -sTCP:LISTEN >/dev/null 2>&1; then
                 port_ready=true
                 break
            fi
            echo -n "."
            sleep 1
        done
        
        if [ "$port_ready" = true ]; then
            color_echo "green" " 启动成功!"
        else
            color_echo "red" "\n[错误] $app_name 在 $max_wait_seconds 秒内未能成功启动端口 $port 开发!终端拦截。"
            color_echo "yellow" "请查看尾部日志以便排查:"
            tail -n 20 "logs/${app_name}.out"
            # 启动单一服务失败退出,如果是all则继续尝试别的
            if [ "$target_service" != "all" ]; then exit 1; fi
        fi
    done
}


# ==========================================
# 交互与调度逻辑 (Interactive & Dispatch Menu)
# ==========================================

show_menu() {
    clear
    color_echo "green" "=============================================="
    color_echo "green" "     LiliShop 一站式服务管理脚本 版本: $version"
    color_echo "green" "=============================================="
    echo "请选择你要执行的操作:"
    echo "1. [一键发版] 全量拉取代码、构建并启动所有服务 (Default)"
    echo "2. [离线一键] 不拉取代码,仅重新构建并启动所有服务"
    echo "3. [仅起服务] 不构建,直接使用现有的 JAR 包启动所有服务"
    echo "4. [选择重启] 重启单独的服务 (例如仅重启 buyer-api, 无构建)"
    echo "5. [选择构建] 构建并重启单独的服务 (拉取最新代码 -> 编译 -> 仅重启此项)"
    echo "6. [一键关停] 停止所有正在运行的服务"
    echo "0. [退出] 取消并安全退出"
    color_echo "green" "=============================================="
    read -rp "请输入序号 [1-6,0] " choice
}

select_single_service() {
    local action_type=$1 # start_only 或 build_and_start
    echo ""
    color_echo "yellow" "请选择要操作的服务名字 (输入数字):"
    
    select srv in "${service_names[@]}"; do
        if [ -n "$srv" ]; then
            color_echo "blue" "你选择了: $srv"
            if [ "$action_type" = "start_only" ]; then
                stop_services "$srv"
                start_services "$srv"
            elif [ "$action_type" = "build_and_start" ]; then
                pull_code
                build_code
                
                # 为单个服务更新 JAR 这里我们简单只拷贝他需要的
                config_str=$(get_service_config "$srv")
                IFS=' ' read -r app_name port jar_file jvm_opts <<< "$config_str"
                # 由于模块目录命名跟 jar 不一定一样,简单的做法依然是全量拷贝,覆盖掉旧的。
                prepare_jars 
                
                stop_services "$srv"
                start_services "$srv"
            fi
            break
        else
            color_echo "red" "无效的选择,请重新输入"
        fi
    done
}


main() {
    check_env
    
    # 支持命令行静默参数调用 (方便配合 Jenkins/GitLab CI)
    case "$1" in
        --build-all)
            pull_code; build_code; stop_services "all"; prepare_jars; start_services "all"
            exit 0;;
        --start-all)
            stop_services "all"; start_services "all"
            exit 0;;
        --stop-all)
            stop_services "all"
            exit 0;;
        *)
            # 无参数,进入交互菜单
            show_menu
            case $choice in
                1)
                    # 全量
                    pull_code; build_code; stop_services "all"; prepare_jars; start_services "all"
                    ;;
                2)
                    # 不拉取,构建+启动全部
                    build_code; stop_services "all"; prepare_jars; start_services "all"
                    ;;
                3)
                    # 不构建,仅启动全部旧包
                    stop_services "all"; start_services "all"
                    ;;
                4)
                    # 仅重启单独的服务(不构建)
                    select_single_service "start_only"
                    ;;
                5)
                    # 构建并重启单独的服务
                    select_single_service "build_and_start"
                    ;;
                6)
                    stop_services "all"
                    ;;
                0)
                    color_echo "yellow" "退出脚本。"
                    exit 0
                    ;;
                *)
                    color_echo "red" "无效的选择!"
                    exit 1
                    ;;
            esac
            ;;
    esac
    
    color_echo "green" "\n🎉 操作执行完毕。"
}

# 脚本入口
main "$@"
  • 执行脚本
sh pg_start_api1.sh

可以指定不同的环境有不同的启动参数(上方为正式环境)

测试环境:

nohup java -Xmx256m -Xms128m -Xss256k -jar manager-api-$version.jar --spring.profiles.active=test > logs/manager.out 2>&1 &
nohup java -Xmx256m -Xms128m -Xss256k -jar common-api-$version.jar  --spring.profiles.active=test > logs/common.out  2>&1 &
nohup java -Xmx256m -Xms128m -Xss256k -jar buyer-api-$version.jar   --spring.profiles.active=test > logs/buyer.out   2>&1 &
nohup java -Xmx256m -Xms128m -Xss256k -jar consumer-$version.jar    --spring.profiles.active=test > logs/consumer.out 2>&1 &
nohup java -Xmx256m -Xms128m -Xss256k -jar im-api-$version.jar      --spring.profiles.active=test > logs/im.out      2>&1 &
nohup java -Xmx256m -Xms128m -Xss256k -jar seller-api-$version.jar  --spring.profiles.active=test > logs/seller.out  2>&1 &

开发环境:

nohup java -Xmx256m -Xms128m -Xss256k -jar manager-api-$version.jar --spring.profiles.active=dev > logs/manager.out 2>&1 &
nohup java -Xmx256m -Xms128m -Xss256k -jar common-api-$version.jar  --spring.profiles.active=dev > logs/common.out  2>&1 &
nohup java -Xmx256m -Xms128m -Xss256k -jar buyer-api-$version.jar   --spring.profiles.active=dev > logs/buyer.out   2>&1 &
nohup java -Xmx256m -Xms128m -Xss256k -jar consumer-$version.jar    --spring.profiles.active=dev > logs/consumer.out 2>&1 &
nohup java -Xmx256m -Xms128m -Xss256k -jar im-api-$version.jar      --spring.profiles.active=dev > logs/im.out      2>&1 &
nohup java -Xmx256m -Xms128m -Xss256k -jar seller-api-$version.jar  --spring.profiles.active=dev > logs/seller.out  2>&1 &

UI部署

  • 下载源码
cd /home/source
git clone https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
  • 安装node yarn
yum update
yum install -y nodejs
yum install -y npm
npm install -g yarn
#   #设置镜像
#   yarn config set registry https://registry.npmmirror.com --global
#   yarn config set disturl https://registry.npmmirror.com/dist --global

# 升级node
npm install -g n
n install v14.16.0
  • 编辑脚本
vi start-ui.sh
  • 脚本内容:
#代码目录
code_path=/home/source/lilishop-ui

cd ${code_path}
git checkout master
git pull

cd ${code_path}/manager
yarn install
yarn build

cd ${code_path}/seller
yarn install
yarn build

cd ${code_path}/buyer
yarn install
yarn build

# 新增:IM客服聊天模块
cd ${code_path}/im
yarn install
yarn build
  • 执行脚本
sh start-ui.sh

Nginx

  • 安装nginx
sudo yum install -y nginx
  • Nginx 示例配置文件
# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;
    proxy_hide_header X-Powered-By;
    proxy_hide_header Server;
    # 开启gzip
    gzip on;

    # 启用gzip压缩的最小文件;小于设置值的文件将不会被压缩
    gzip_min_length 1k;

    # gzip 压缩级别 1-10 
    gzip_comp_level 2;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

  #http强制跳转 https
    server {
         listen 80;
         server_name pickmall.cn;
         rewrite ^(.*)$  https://$host$1 permanent;
         location ~ / {
            index index.html index.php index.htm;
         }
 }

    #管理端
    server {
        listen       443 ssl;
        ssl_certificate "/etc/nginx/ssl/pickmall.cn.pem";
        ssl_certificate_key "/etc/nginx/ssl/pickmall.cn.key";
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;
        include /etc/nginx/default.d/*.conf;

        server_name  admin-b2b2c.pickmall.cn;
        try_files $uri $uri/ /index.html;

        root    /home/source/lilishop-ui/manager/dist;
    }

    #商家端
    server {
        listen       443 ssl;
        ssl_certificate "/etc/nginx/ssl/pickmall.cn.pem";
        ssl_certificate_key "/etc/nginx/ssl/pickmall.cn.key";
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;
        include /etc/nginx/default.d/*.conf;

        server_name  store-b2b2c.pickmall.cn;
        try_files $uri $uri/ /index.html;
        root    /home/source/lilishop-ui/seller/dist;
    }

    #h5端
    server {
        listen       443 ssl;
        ssl_certificate "/etc/nginx/ssl/pickmall.cn.pem";
        ssl_certificate_key "/etc/nginx/ssl/pickmall.cn.key";
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;
        include /etc/nginx/default.d/*.conf;

        server_name  m-b2b2c.pickmall.cn;
        try_files $uri $uri/ /index.html;
        root    /home/source/h5;
    }

    #PC端
    server {
        listen       443 ssl;
        ssl_certificate "/etc/nginx/ssl/pickmall.cn.pem";
        ssl_certificate_key "/etc/nginx/ssl/pickmall.cn.key";
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;
        include /etc/nginx/default.d/*.conf;

        server_name  pc-b2b2c.pickmall.cn;
        try_files $uri $uri/ /index.html;
        root         /home/source/lilishop-ui/buyer/dist;
    }
    #IM
     server {
         listen       443 ssl;
         ssl_certificate "/etc/nginx/ssl/pickmall.cn.pem";
         ssl_certificate_key "/etc/nginx/ssl/pickmall.cn.key";
         ssl_session_cache shared:SSL:1m;
         ssl_session_timeout  10m;
         ssl_ciphers HIGH:!aNULL:!MD5;
         ssl_prefer_server_ciphers on;
      include /etc/nginx/default.d/*.conf;

         proxy_set_header Host $host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header REMOTE-HOST $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

         server_name  im.pickmall.cn;
         try_files $uri $uri/ /index.html;
         root         /home/source/lili-shop-ui/im/dist;
     }

    #admin-api
    server {
        listen       443 ssl;
        ssl_certificate "/etc/nginx/ssl/pickmall.cn.pem";
        ssl_certificate_key "/etc/nginx/ssl/pickmall.cn.key";
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;
        include /etc/nginx/default.d/*.conf;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header REMOTE-HOST $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        server_name  admin-api.pickmall.cn;
        location / {
            proxy_pass http://127.0.0.1:8887;
        }
    }
    #buyer-api
    server {
        listen       443 ssl;
        ssl_certificate "/etc/nginx/ssl/pickmall.cn.pem";
        ssl_certificate_key "/etc/nginx/ssl/pickmall.cn.key";
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;
        include /etc/nginx/default.d/*.conf;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header REMOTE-HOST $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        server_name  buyer-api.pickmall.cn;
        location / {
            proxy_pass http://127.0.0.1:8888;
        }
    }

     #im-api
     server {
         listen       443 ssl;
         ssl_certificate "/etc/nginx/ssl/pickmall.cn.pem";
         ssl_certificate_key "/etc/nginx/ssl/pickmall.cn.key";
         ssl_session_cache shared:SSL:1m;
         ssl_session_timeout  10m;
         ssl_ciphers HIGH:!aNULL:!MD5;
         ssl_prefer_server_ciphers on;
         include /etc/nginx/default.d/*.conf;
         server_name  im-api.pickmall.cn;

         location / {
             proxy_http_version 1.1;    
             proxy_set_header Upgrade $http_upgrade;    
             proxy_set_header Connection "Upgrade";    
             proxy_set_header X-real-ip $remote_addr;
             proxy_set_header X-Forwarded-For $remote_addr;
             proxy_pass http://127.0.0.1:8885;
         }
     }

}
  • nginx 启动
service nginx restart

代码更新部署

cd /home/source
sh pg_start_api1.sh
sh start-ui.sh