新增两步独立 Docker 部署方案(czleilei240 环境): 步骤一 寄卖商城(integral-resell) - step1-integral/docker-compose.yml:redis(Alpine自建) + houtai(webman PHP8) + h5(Nginx) - houtai.Dockerfile:PHP 8.0 + 阿里云镜像源 + webman.bin entrypoint - h5.Dockerfile:Nginx + configs.js 环境变量动态重写 - redis.Dockerfile:Alpine + apk 构建,绕过 DockerHub 镜像源问题 - 宿主机 bind-mount:/www/wwwroot/leileiadmin.czchunfang.com(FTP可直接更新程序) 步骤二 积分商城(single-shop-22) - step2-single-shop/docker-compose.yml:redis + admin-api + front-api + admin-web + h5 - Java Dockerfiles:OpenJDK 17 + --add-opens Spring Boot 2.2.6 兼容 公共配置 - nginx/:四个域名宝塔 Nginx 反代配置(HTTP→HTTPS 301、SSL 终止) - scripts/:sync-to-server.sh / deploy-step1.sh / remote-up.sh - DOCKER_DEPLOY.md:完整部署文档 Co-authored-by: Cursor <cursoragent@cursor.com>
21 KiB
Docker 部署方案(寄卖商城 + 积分商城前后端)
本方案覆盖:
- integral-resell(积分商城):Webman PHP 后端二进制 + H5 静态站
- single-shop-22(寄卖商城):CRMEB Spring Boot 双 jar 后端 + Vue 管理后台 + uni-app H5
- Redis:每个子栈独立容器(两套互不干扰)
不包含:
MER-2.2_2601多商户、Kafka 同步、MySQL(使用 阿里云 RDS for MySQL)。
两步独立部署(推荐)
从 czleilei240 分支开始,两个商城各自独立部署,互不依赖。
| 步骤一 寄卖商城 | 步骤二 积分商城 | |
|---|---|---|
| 项目 | integral-resell |
single-shop-22 |
| 目录 | deploy/docker/step1-integral/ |
deploy/docker/step2-single-shop/ |
| 服务 | redis · integral-houtai · integral-h5 | redis · single-admin-api · single-front-api · single-admin-web · single-h5 |
| 宿主机端口 | 18080 |
18081(管理后台) 18082(H5) |
| compose name | resell-czleilei240 |
jifenmall-czleilei240 |
| 详细说明 | README | README |
步骤一 — 寄卖商城(integral-resell)
cd deploy/docker/step1-integral
cp .env.example .env && cp houtai.env.example houtai.env
# 填写 .env 中的 REDIS_PASSWORD
# 填写 houtai.env 中的 DB_PASSWORD 和 REDIS_PASSWORD(两者须一致)
docker compose --env-file .env up -d --build
步骤二 — 积分商城(single-shop-22)
cd deploy/docker/step2-single-shop
cp .env.example .env
# 填写 RDS_PASSWORD、REDIS_PASSWORD
docker compose --env-file .env up -d --build
# Java 首次构建约 10-20 分钟,可用 logs -f 观察进度
下方章节描述的是历史上合并部署时的
docker-compose.yml(deploy/docker/docker-compose.yml),供参考。两步拆分方案已取代合并方案。
一、架构总览
flowchart LR
user((用户)) -->|H5/管理后台| EdgeLB[(阿里云 SLB / Nginx)]
subgraph Host [Docker 主机]
direction TB
subgraph integralStack [积分商城]
integral_h5[integral-h5\nNginx :80]
integral_houtai[integral-houtai\nwebman.bin :8787]
end
subgraph singleStack [寄卖商城]
single_admin_web[single-admin-web\nNginx :80]
single_h5[single-h5\nNginx :80]
single_admin_api[single-admin-api\nminiao-admin :30032]
single_front_api[single-front-api\nminiao-front :30031]
end
redis[(redis :6379)]
end
EdgeLB -- jf-h5.* --> single_h5
EdgeLB -- jfadmin.* --> single_admin_web
EdgeLB -- admin.* --> integral_h5
integral_h5 -- /api/ --> integral_houtai
single_admin_web -- /api/ --> single_admin_api
single_h5 -- /api/ --> single_front_api
integral_houtai --> redis
single_admin_api --> redis
single_front_api --> redis
integral_houtai --> RDS[(阿里云 RDS MySQL)]
single_admin_api --> RDS
single_front_api --> RDS
服务清单
| 服务 | 镜像构建来源 | 容器内端口 | 默认宿主机端口 | 说明 |
|---|---|---|---|---|
redis |
官方 redis:6.2-alpine |
6379 | 6379 (可不暴露) | 持久化 AOF,挂卷 redis-data |
integral-houtai |
integral-resell/houtai/ |
8787 | (不暴露) | Webman 静态 ELF;同容器写 runtime/ 与 public/upload/ |
integral-h5 |
integral-resell/h5/ |
80 | 18080 | 服务静态站;/api/ 反代到 integral-houtai;启动时根据 env 重写 static/configs.js |
single-admin-api |
single-shop-22/backend/crmeb-admin |
30032 | (不暴露) | 多阶段 Maven 构建出 miao-admin-2.2.jar |
single-front-api |
single-shop-22/backend/crmeb-front |
30031 | (不暴露) | 多阶段 Maven 构建出 miao-front-2.2.jar |
single-admin-web |
single-shop-22/backend-adminend |
80 | 18081 | 多阶段 Node 构建 dist;/api/ 反代到 single-admin-api |
single-h5 |
single-shop-22/single_uniapp22miao |
80 | 18082 | 多阶段 Node 构建 unpackage/dist/build/h5;/api/ 反代到 single-front-api |
域名/端口策略:建议在 docker 主机前再放一层 Nginx 或阿里云 SLB,按域名分发到 18080/18081/18082;下面的 compose 默认把这三个静态站暴露在宿主机不同端口。
共享资源 / 卷
| 卷 / 目录 | 容器内挂载点 | 用途 |
|---|---|---|
redis-data |
/data |
Redis AOF 持久化 |
integral-runtime |
/app/runtime |
Webman 运行时(session、views 缓存等) |
integral-upload |
/app/public/upload |
积分商城上传图片 |
single-images |
/usr/local/crmeb/crmebimage |
寄卖商城 imagePath,admin/front 两个 jar 共享 |
single-logs |
/app/log |
Spring Boot 日志(按需保留) |
与外部资源的关系
| 资源 | 地址来源 | 说明 |
|---|---|---|
| 阿里云 RDS MySQL | .env 中 RDS_* |
RDS 白名单需放通宿主机出口 IP;建议同地域 VPC |
| OSS(可选) | .env 中 OSS_* |
不配置时积分商城走本地 public/upload;寄卖商城用 admin 后台界面里配置 |
| 短信(可选) | .env 中 SMS_* |
仅积分商城 .env 用到 |
二、目录布局
integral-shop/
├── DOCKER_DEPLOY.md ← 本文档
├── deploy/
│ └── docker/
│ ├── docker-compose.yml
│ ├── .env.example
│ ├── README.md ← 一键启动说明(简版)
│ ├── redis/
│ │ └── redis.conf
│ ├── integral-resell/
│ │ ├── houtai.Dockerfile
│ │ ├── h5.Dockerfile
│ │ ├── nginx-h5.conf
│ │ ├── .env.template ← Webman 后端运行时 .env 模板
│ │ └── docker-entrypoint-h5.sh ← 启动时根据 env 改写 configs.js
│ └── single-shop/
│ ├── admin-api.Dockerfile
│ ├── front-api.Dockerfile
│ ├── admin-web.Dockerfile
│ ├── h5.Dockerfile
│ ├── application-docker.yml ← Spring Boot docker profile
│ ├── nginx-admin-web.conf
│ └── nginx-h5.conf
├── integral-resell/ ← 源码(不改动)
└── single-shop-22/ ← 源码(不改动)
所有 Dockerfile / compose 都只读访问源码目录,不会修改它们。
三、配置与环境变量
复制一份 deploy/docker/.env.example 为 deploy/docker/.env 并按下面表格修改。
| 变量 | 用途 | 示例 |
|---|---|---|
TZ |
容器时区 | Asia/Shanghai |
RDS_HOST |
阿里云 RDS 外网/内网地址 | rm-bp1a178eq62lxba9xbo.mysql.rds.aliyuncs.com |
RDS_PORT |
RDS 端口 | 3306 |
RDS_INTEGRAL_DB |
积分商城数据库 | yangtangyoupin |
RDS_INTEGRAL_USER / RDS_INTEGRAL_PASS |
积分商城账号 | 默认 yangtangyoupin / 来自原 sxsy80 |
RDS_SINGLE_DB |
寄卖商城数据库(与积分共库) | yangtangyoupin |
RDS_SINGLE_USER / RDS_SINGLE_PASS |
寄卖商城账号 | 同上 |
REDIS_PASSWORD |
容器 Redis 密码 | 123456 |
REDIS_INTEGRAL_DB |
积分商城使用的 Redis db | 0 |
REDIS_SINGLE_ADMIN_DB |
寄卖 admin Redis db | 25 |
REDIS_SINGLE_FRONT_DB |
寄卖 front Redis db | 26 |
INTEGRAL_API_PUBLIC_URL |
H5 调用后端的对外 URL | https://admin.example.com |
INTEGRAL_IMG_PUBLIC_URL |
H5 引用图片的对外 URL | https://admin.example.com |
INTEGRAL_H5_PUBLIC_URL |
H5 自身对外 URL | https://h5.example.com/ |
INTEGRAL_SN_ID |
configs.js 中 sn_id |
17533260260405 |
INTEGRAL_APP_STR |
configs.js 中 appStr(与寄卖 APP_SECRET 必须一致) |
ZFyTNQTWEkCBczKzyUDJWE9Ecx260405 |
SINGLE_ADMIN_BASE_API |
寄卖管理后台调用 API 的域名/路径 | 留空走同域 /api/ 即可 |
SINGLE_H5_DOMAIN |
uni-app H5 调用 API 的域名 | 留空走同域 /api/ 即可 |
SYNC_SOURCE_ID / SYNC_TARGET_MER_ID |
多商户同步配置(无 MER 时留空) | "" / 0 |
关键一致性:积分商城
configs.js#appStr↔ 积分商城 Webman.env#APP_SECRET↔ 寄卖商城 admin 后台中的appStr必须一致;否则双向调用会鉴权失败。
四、镜像构建策略
0. 基础镜像选型(与主机对齐)
| 服务 | 基础镜像 | libc | 选择理由 |
|---|---|---|---|
redis |
redis:6.2-alpine |
musl | Redis 官方推荐,无 native 依赖 |
integral-houtai |
php:8.0-cli-bullseye (Debian 11) |
glibc | 与宝塔 PHP 8.0.26 版本对齐;已装 pdo_mysql / redis / gd / imagick 等 webman 常用扩展 |
integral-h5 |
nginx:1.25-alpine |
musl | 纯静态文件 + nginx,无字体/native 依赖 |
single-admin-api / single-front-api 构建 |
maven:3.8.8-eclipse-temurin-17 (Debian) |
glibc | 与部署环境 OpenJDK 17.0.x 对齐;pom.xml source/target=1.8,Java 17 编译器向下兼容 |
single-admin-api / single-front-api 运行 |
eclipse-temurin:17-jre-jammy (Ubuntu 22.04) |
glibc | 匹配主机 openjdk 17.0.18;Spring Boot 2.2.6 + Java 17 需额外 --add-opens JVM 参数(已写入 JAVA_OPTS);预装 fonts-dejavu + fonts-wqy-zenhei |
single-admin-web / single-h5 构建 |
node:16-alpine |
musl | 仅打包 JS/CSS,无 native 依赖 |
single-admin-web / single-h5 运行 |
nginx:1.25-alpine |
musl | 同上 |
主机环境:Debian-class(Linux kernel 6.1.164)/ x86_64 / Docker + BuildKit。 所有
--platform=linux/amd64在主机上都是原生执行,无 QEMU 模拟;只有在 Apple Silicon 上本地 build 时才会走 QEMU。 Java 后端最终镜像在 glibc 上运行,与主机 OS 完全同源;这样可避免 Alpine + musl 时验证码 / 中文字体 / POI 个别场景的兼容性问题。
1. integral-houtai(PHP Webman 二进制)
- 基础镜像:
debian:bookworm-slim(webman.bin 为 ELF x86_64,静态链接,glibc 兼容)。 - 直接拷贝
webman.bin、public/、runtime/views模板进镜像。 .env不打进镜像,通过docker-compose把deploy/docker/integral-resell/.env.template渲染后挂进/app/.env。- 启动命令:
./webman.bin start -d(业主指定的守护模式),entrypoint 在后台tail -F runtime/logs/*.log把日志接到容器 stdout,并监听主进程退出。收到SIGTERM时执行./webman.bin stop优雅退出。
2. integral-h5(静态站)
- 基础镜像:
nginx:1.25-alpine。 - 直接拷贝
integral-resell/h5/到/usr/share/nginx/html/。 docker-entrypoint-h5.sh在启动时根据环境变量重写static/configs.js:把BASE_URL/IMG_URL/H5_URL/sn_id/appStr替换为部署值,无需重新构建前端。
3. single-admin-api / single-front-api(Spring Boot)
- 多阶段构建:
- 构建阶段:
maven:3.8.8-eclipse-temurin-17→mvn package -pl crmeb-admin -am -DskipTests(front 同理)。pom.xml 已配置source/target=1.8,Java 17 编译器向下兼容,产物字节码级别不变。 - 运行阶段:
eclipse-temurin:17-jre-jammy(Ubuntu 22.04 / glibc),与部署环境openjdk 17.0.18对齐;预装fontconfig + fonts-dejavu + fonts-wqy-zenhei。
- 构建阶段:
- Java 17 兼容性:Spring Boot 2.2.6 使用 cglib、Druid、Quartz 等大量反射,Java 17 强模块封装会报
InaccessibleObjectException。已在JAVA_OPTS中加入 7 条--add-opens,覆盖已知触发点(java.lang / reflect / util / io / math / sun.net.util / net)。若运行时出现新的InaccessibleObjectException,按报错包名继续追加--add-opens。 - 通过
--spring.profiles.active=docker+--spring.config.additional-location=file:/config/加载application-docker.yml,所有 DB/Redis/端口参数从.env注入。 imagePath指向/usr/local/crmeb/crmebimage/(挂卷single-images,两个 jar 共享)。
4. single-admin-web(Vue 管理后台)
- 多阶段构建:
- 构建阶段:
node:16-alpine→npm ci && npm run build:prod(VUE_APP_BASE_API设为空,走同域/api/)。 - 运行阶段:
nginx:1.25-alpine,/api/反代到single-admin-api:30032。
- 构建阶段:
- 若想直接复用源码里现成的
dist/,可改用「fast」分支(见 Dockerfile 注释)。
5. single-h5(uni-app H5)
- 同样多阶段:
node:16-alpine→npm install && npm run build:h5,再 nginx 服务。 config/app.js里domain硬编码,需在构建前注入:通过 ARGH5_API_DOMAIN做字符串替换,或留空让同域生效(推荐)。
五、Spring Boot 接 RDS / Redis 的细节
寄卖商城原本通过 spring.profiles.active=byjyw149 / miao80 等加载不同 yml。Docker 部署用全新 profile docker:
# deploy/docker/single-shop/application-docker.yml
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT:3306}/${MYSQL_DATABASE}?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
username: ${MYSQL_USERNAME}
password: ${MYSQL_PASSWORD}
redis:
host: ${REDIS_HOST}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASSWORD:}
database: ${REDIS_DATABASE:0}
通过 docker-compose 注入:
MYSQL_HOST=${RDS_HOST}
MYSQL_DATABASE=${RDS_SINGLE_DB}
MYSQL_USERNAME=${RDS_SINGLE_USER}
MYSQL_PASSWORD=${RDS_SINGLE_PASS}
REDIS_HOST=redis
REDIS_PASSWORD=${REDIS_PASSWORD}
REDIS_DATABASE=${REDIS_SINGLE_ADMIN_DB}
数据库初始化:首次部署前请用
db/下的 SQL(推荐db/yangtangyoupin.sql、db/shop22-v2.sql等)在 RDS 中初始化对应库;本方案不在容器中建库,避免误覆盖现网数据。
六、首次部署步骤
# 1. 准备环境变量
cd integral-shop/deploy/docker
cp .env.example .env
vim .env # 填入 RDS / Redis / 域名等
# 2. 准备积分商城 Webman .env(容器运行时挂载)
cp integral-resell/.env.template integral-resell/.env
vim integral-resell/.env # 至少配置 DB_*、APP_SECRET、SMS_*
# 3. 在阿里云 RDS 上提前导入数据
# - 积分商城:db/yangtangyoupin.sql
# - 寄卖商城:db/shop22-v2.sql / db/jjy153-mysql.sql (按实际版本)
# 4. 构建并启动
docker compose --env-file .env build
docker compose --env-file .env up -d
# 5. 健康检查
docker compose ps
docker compose logs -f single-admin-api # 看到 "Started CrmebAdminApplication" 即成功
docker compose logs -f integral-houtai # 看到 "Webman start success" 即成功
curl -I http://localhost:18080 # 积分商城 H5
curl -I http://localhost:18081 # 寄卖管理后台
curl -I http://localhost:18082 # 寄卖用户 H5
七、日常运维
| 场景 | 操作 |
|---|---|
| 拉取最新源码后重建 | docker compose build --no-cache <service> 然后 docker compose up -d <service> |
| 只重启某服务 | docker compose restart single-admin-api |
| 看日志 | docker compose logs -f --tail 200 single-front-api |
| 进入容器 | docker compose exec single-admin-api sh |
| 备份用户上传 | docker run --rm -v integral-upload:/d -v $(pwd):/b alpine tar czf /b/upload.tgz -C /d . |
| 备份寄卖商城图片 | 同上,卷名 single-images |
| 切换到外部 Redis | 在 .env 把 REDIS_HOST 改成外部地址,并在 compose 里把 redis 服务注释 |
| 切换到 Java 17 运行寄卖商城 | 把 eclipse-temurin:8-jre-alpine 改成 17-jre;本工程经验依旧建议 8 |
八、性能与资源建议
| 容器 | CPU | 内存(建议) |
|---|---|---|
redis |
0.2 | 256 MB |
integral-houtai |
0.5–1 | 256–512 MB(webman 多 worker 时 ↑) |
integral-h5 |
0.1 | 64 MB |
single-admin-api |
1 | JVM -Xmx512m,容器 limit 768 MB |
single-front-api |
1 | JVM -Xmx768m,容器 limit 1 GB |
single-admin-web |
0.1 | 64 MB |
single-h5 |
0.1 | 64 MB |
最低配宿主机:2 vCPU / 4 GB(建议 4 vCPU / 8 GB 起)。
九、上线检查清单
- 阿里云 RDS 白名单已放通 Docker 主机出口 IP
- RDS 中已导入对应库的 SQL,账号/密码权限正确
.env中无明文敏感信息提交到 git(已.gitignore)INTEGRAL_APP_STR与寄卖商城 admin 后台 + Webman.env#APP_SECRET三处一致- 域名 / SSL 在外层 Nginx 或阿里云 SLB 完成 443 卸载
- OSS 与 SMS 等第三方密钥若启用,已写入对应位置
- 备份策略:RDS 自动备份 +
integral-upload/single-images卷定期 tar 备份
十、远端 116.62.83.240 一键部署
服务器已具备的环境(来自宝塔软件商店截图):
- Docker(节点管理 → Docker 已部署)
- Nginx 1.28.1(未使用,本方案的 Nginx 在容器内)
- MySQL 5.7.44(未使用,本方案走阿里云 RDS)
- Redis 8.0.5(默认未使用,容器内自带 Redis;想复用宿主 Redis 见下方"复用宿主 Redis")
- PHP 8.0.26(未使用,webman 走静态二进制)
- rsync 已安装、SSH
root / A@123456
1. 本机一次性配置
cd deploy/docker/scripts
cp server.env.example server.env
$EDITOR server.env # 默认已写好 116.62.83.240 / root / A@123456
强烈建议先用 SSH key 替代密码:
ssh-copy-id root@116.62.83.240后把server.env里的SSHPASS=注释掉即可。脚本会自动切回 SSH key 通道。
2. 全量同步并启动
./sync-to-server.sh up
脚本流程:
- SSH 登录 116.62.83.240,确保
/root/integral-shop目录存在; - rsync 增量同步整个工程(自动排除
node_modules / target / .git / runtime/logs / MER-2.2_2601等大目录); - 在远端
cd /root/integral-shop/deploy/docker && docker compose build && docker compose up -d; - 输出
docker compose ps结果。
首次会要求你先在远端把 .env / integral-resell/.env 改成真实值(如未做,运行下面这一步):
./bootstrap-remote-env.sh # 在远端基于模板创建 .env,再 ssh 上去填写
3. 日常运维(无需登录服务器)
./remote-up.sh ps # 服务状态
./remote-up.sh logs single-admin-api # 跟随日志
./remote-up.sh restart single-front-api # 重启某服务
./remote-up.sh build single-admin-web # 只重建某镜像
./remote-up.sh exec single-admin-api sh # 进容器
./remote-up.sh ssh # 直接登录服务器
./sync-to-server.sh up # 改了代码后再同步+重启
4. 端口规划与宝塔放行
宿主机暴露端口(来自 .env.example,可改):
| 端口 | 服务 | 用途 |
|---|---|---|
| 18080 | integral-h5 |
积分商城 H5 |
| 18081 | single-admin-web |
寄卖管理后台 |
| 18082 | single-h5 |
寄卖用户 H5 |
| 6379 | redis |
(生产建议关闭)REDIS_HOST_PORT= 留空即不暴露 |
安全组 / 防火墙:阿里云安全组放通 18080-18082;宝塔面板 → 安全 → 放行同样端口。强烈建议在前面再挂一层域名 + SSL(宝塔自带 Nginx 反代 / 阿里云 SLB / Cloudflare 都行)。
5. 复用宿主已有 Redis 8.0.5(可选)
若想节省一份 Redis,直接用宿主机的 Redis:
# 1) 远端编辑 deploy/docker/.env
REDIS_PASSWORD=宿主-Redis-的密码
# 2) 远端编辑 deploy/docker/docker-compose.yml
# a. 注释掉 redis: 整个服务块(包括 healthcheck)
# b. single-admin-api / single-front-api 把 REDIS_HOST: redis 改成 172.17.0.1
# (docker bridge 网关;宝塔默认端口 6379;先确保 Redis 监听 0.0.0.0 且防火墙放行 6379 to docker subnet)
# c. integral-resell/.env 把 REDIS_HOST=redis 同步改为 172.17.0.1
# 3) 同步重启
./sync-to-server.sh up
6. 阿里云 RDS 白名单
到 RDS 控制台 → 白名单 → 加入 116.62.83.240(如果 RDS 与 ECS 同 VPC 则用内网地址 + 内网白名单更优)。
7. 数据库初始化
# 本地把 SQL 上传到服务器(默认 db/ 已被 rsync 同步过去)
./remote-up.sh ssh
# 远端
mysql -h <RDS_HOST> -u <RDS_USER> -p<RDS_PASS> < /root/integral-shop/db/yangtangyoupin.sql
mysql -h <RDS_HOST> -u <RDS_USER> -p<RDS_PASS> < /root/integral-shop/db/shop22-v2.sql
也可以用宝塔自带的 phpMyAdmin 直接连 RDS 导入。
十一、各文件清单一览
参见 deploy/docker/ 下:
docker-compose.yml← 编排入口.env.example← 环境变量模板redis/redis.confintegral-resell/houtai.Dockerfileintegral-resell/h5.Dockerfileintegral-resell/nginx-h5.confintegral-resell/.env.templateintegral-resell/docker-entrypoint-h5.shsingle-shop/admin-api.Dockerfilesingle-shop/front-api.Dockerfilesingle-shop/admin-web.Dockerfilesingle-shop/h5.Dockerfilesingle-shop/application-docker.ymlsingle-shop/nginx-admin-web.confsingle-shop/nginx-h5.confscripts/server.env.example← 远端 SSH 配置模板scripts/sync-to-server.sh← rsync 增量同步 + 触发远端部署scripts/remote-up.sh← 远端docker compose操作(up/build/restart/logs/ps/exec/ssh)scripts/bootstrap-remote-env.sh← 首次在远端生成 .env 模板
每个文件都已生成可直接使用的版本。