From fb76270882dcdf04a3e740b0c17b54bcb5130a11 Mon Sep 17 00:00:00 2001 From: danaisuiyuan Date: Sun, 17 May 2026 17:24:08 +0800 Subject: [PATCH] =?UTF-8?q?feat(deploy):=20=E5=AE=8C=E6=95=B4=20Docker=20?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E6=96=B9=E6=A1=88=20=E2=80=94=20=E5=AF=84?= =?UTF-8?q?=E5=8D=96=E5=95=86=E5=9F=8E=20+=20=E7=A7=AF=E5=88=86=E5=95=86?= =?UTF-8?q?=E5=9F=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增两步独立 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 --- .gitignore | 12 + DOCKER_DEPLOY.md | 469 ++++++++++++++++++ deploy/docker/.env.example | 79 +++ deploy/docker/.gitignore | 3 + deploy/docker/README.md | 113 +++++ deploy/docker/docker-compose.yml | 187 +++++++ .../nginx/leilei-jf.czchunfang.com.conf | 83 ++++ .../nginx/leilei-jfadmin.czchunfang.com.conf | 83 ++++ .../docker/nginx/leilei.czchunfang.com.conf | 82 +++ .../nginx/leileiadmin.czchunfang.com.conf | 82 +++ deploy/docker/redis/redis.conf | 39 ++ deploy/docker/scripts/.gitignore | 1 + deploy/docker/scripts/bootstrap-remote-env.sh | 39 ++ deploy/docker/scripts/deploy-step1.sh | 204 ++++++++ deploy/docker/scripts/remote-up.sh | 92 ++++ deploy/docker/scripts/server.env.example | 21 + deploy/docker/scripts/sync-to-server.sh | 123 +++++ .../docker/single-shop/admin-api.Dockerfile | 62 +++ .../docker/single-shop/admin-web.Dockerfile | 88 ++++ .../docker/single-shop/application-docker.yml | 68 +++ .../docker/single-shop/front-api.Dockerfile | 62 +++ deploy/docker/single-shop/h5.Dockerfile | 96 ++++ .../docker/single-shop/nginx-admin-web.conf | 37 ++ deploy/docker/single-shop/nginx-h5.conf | 30 ++ deploy/docker/ssl-cert/.gitignore | 7 + deploy/docker/step1-integral/.env.example | 31 ++ deploy/docker/step1-integral/.gitignore | 2 + deploy/docker/step1-integral/README.md | 126 +++++ .../docker/step1-integral/docker-compose.yml | 95 ++++ .../docker/step1-integral/houtai.env.example | 37 ++ deploy/docker/step1-integral/redis.Dockerfile | 13 + deploy/docker/step2-single-shop/.env.example | 37 ++ deploy/docker/step2-single-shop/.gitignore | 1 + deploy/docker/step2-single-shop/README.md | 130 +++++ .../step2-single-shop/docker-compose.yml | 163 ++++++ deploy/ssl/leilei-jf.czchunfang.com_cert.zip | Bin 0 -> 35713 bytes .../leilei-jfadmin.czchunfang.com_cert.zip | Bin 0 -> 35804 bytes deploy/ssl/leilei.czchunfang.com_cert.zip | Bin 0 -> 35655 bytes .../ssl/leileiadmin.czchunfang.com_cert.zip | Bin 0 -> 35765 bytes integralResell&singleShop.code-workspace | 11 + 40 files changed, 2808 insertions(+) create mode 100644 DOCKER_DEPLOY.md create mode 100644 deploy/docker/.env.example create mode 100644 deploy/docker/.gitignore create mode 100644 deploy/docker/README.md create mode 100644 deploy/docker/docker-compose.yml create mode 100644 deploy/docker/nginx/leilei-jf.czchunfang.com.conf create mode 100644 deploy/docker/nginx/leilei-jfadmin.czchunfang.com.conf create mode 100644 deploy/docker/nginx/leilei.czchunfang.com.conf create mode 100644 deploy/docker/nginx/leileiadmin.czchunfang.com.conf create mode 100644 deploy/docker/redis/redis.conf create mode 100644 deploy/docker/scripts/.gitignore create mode 100755 deploy/docker/scripts/bootstrap-remote-env.sh create mode 100755 deploy/docker/scripts/deploy-step1.sh create mode 100755 deploy/docker/scripts/remote-up.sh create mode 100644 deploy/docker/scripts/server.env.example create mode 100755 deploy/docker/scripts/sync-to-server.sh create mode 100644 deploy/docker/single-shop/admin-api.Dockerfile create mode 100644 deploy/docker/single-shop/admin-web.Dockerfile create mode 100644 deploy/docker/single-shop/application-docker.yml create mode 100644 deploy/docker/single-shop/front-api.Dockerfile create mode 100644 deploy/docker/single-shop/h5.Dockerfile create mode 100644 deploy/docker/single-shop/nginx-admin-web.conf create mode 100644 deploy/docker/single-shop/nginx-h5.conf create mode 100644 deploy/docker/ssl-cert/.gitignore create mode 100644 deploy/docker/step1-integral/.env.example create mode 100644 deploy/docker/step1-integral/.gitignore create mode 100644 deploy/docker/step1-integral/README.md create mode 100644 deploy/docker/step1-integral/docker-compose.yml create mode 100644 deploy/docker/step1-integral/houtai.env.example create mode 100644 deploy/docker/step1-integral/redis.Dockerfile create mode 100644 deploy/docker/step2-single-shop/.env.example create mode 100644 deploy/docker/step2-single-shop/.gitignore create mode 100644 deploy/docker/step2-single-shop/README.md create mode 100644 deploy/docker/step2-single-shop/docker-compose.yml create mode 100644 deploy/ssl/leilei-jf.czchunfang.com_cert.zip create mode 100644 deploy/ssl/leilei-jfadmin.czchunfang.com_cert.zip create mode 100644 deploy/ssl/leilei.czchunfang.com_cert.zip create mode 100644 deploy/ssl/leileiadmin.czchunfang.com_cert.zip create mode 100644 integralResell&singleShop.code-workspace diff --git a/.gitignore b/.gitignore index 4779d45..2c3a653 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,15 @@ backend/**/logs/ backend/**/*.log backend/.idea/ backend/crmebimage/ + +# 独立子仓库(各自有独立 git,不纳入根 repo) +integral-resell/ +single-shop-22/ +MER-2.2_2601/ +db/ + +# 敏感运行时配置(不入库) +deploy/docker/scripts/server.env +deploy/docker/step1-integral/.env +deploy/docker/step1-integral/houtai.env +deploy/docker/step2-single-shop/.env diff --git a/DOCKER_DEPLOY.md b/DOCKER_DEPLOY.md new file mode 100644 index 0000000..2f2fa94 --- /dev/null +++ b/DOCKER_DEPLOY.md @@ -0,0 +1,469 @@ +# 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](deploy/docker/step1-integral/README.md) | [README](deploy/docker/step2-single-shop/README.md) | + +### 步骤一 — 寄卖商城(integral-resell) + +```bash +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) + +```bash +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`),供参考。两步拆分方案已取代合并方案。 + +--- + +## 一、架构总览 + +```mermaid +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` 硬编码,需在构建前注入:通过 ARG `H5_API_DOMAIN` 做字符串替换,或留空让同域生效(推荐)。 + +--- + +## 五、Spring Boot 接 RDS / Redis 的细节 + +寄卖商城原本通过 `spring.profiles.active=byjyw149` / `miao80` 等加载不同 yml。**Docker 部署用全新 profile `docker`**: + +```yaml +# 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 中初始化对应库;本方案不在容器中建库,**避免误覆盖现网数据**。 + +--- + +## 六、首次部署步骤 + +```bash +# 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 ` 然后 `docker compose up -d ` | +| 只重启某服务 | `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. 本机一次性配置 + +```bash +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. 全量同步并启动 + +```bash +./sync-to-server.sh up +``` + +脚本流程: +1. SSH 登录 116.62.83.240,确保 `/root/integral-shop` 目录存在; +2. rsync 增量同步整个工程(自动排除 `node_modules / target / .git / runtime/logs / MER-2.2_2601` 等大目录); +3. 在远端 `cd /root/integral-shop/deploy/docker && docker compose build && docker compose up -d`; +4. 输出 `docker compose ps` 结果。 + +首次会要求你先在远端把 `.env / integral-resell/.env` 改成真实值(如未做,运行下面这一步): + +```bash +./bootstrap-remote-env.sh # 在远端基于模板创建 .env,再 ssh 上去填写 +``` + +### 3. 日常运维(无需登录服务器) + +```bash +./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: + +```bash +# 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. 数据库初始化 + +```bash +# 本地把 SQL 上传到服务器(默认 db/ 已被 rsync 同步过去) +./remote-up.sh ssh +# 远端 +mysql -h -u -p < /root/integral-shop/db/yangtangyoupin.sql +mysql -h -u -p < /root/integral-shop/db/shop22-v2.sql +``` + +也可以用宝塔自带的 phpMyAdmin 直接连 RDS 导入。 + +--- + +## 十一、各文件清单一览 + +参见 `deploy/docker/` 下: + +- `docker-compose.yml` ← 编排入口 +- `.env.example` ← 环境变量模板 +- `redis/redis.conf` +- `integral-resell/houtai.Dockerfile` +- `integral-resell/h5.Dockerfile` +- `integral-resell/nginx-h5.conf` +- `integral-resell/.env.template` +- `integral-resell/docker-entrypoint-h5.sh` +- `single-shop/admin-api.Dockerfile` +- `single-shop/front-api.Dockerfile` +- `single-shop/admin-web.Dockerfile` +- `single-shop/h5.Dockerfile` +- `single-shop/application-docker.yml` +- `single-shop/nginx-admin-web.conf` +- `single-shop/nginx-h5.conf` +- `scripts/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 模板 + +每个文件都已生成可直接使用的版本。 diff --git a/deploy/docker/.env.example b/deploy/docker/.env.example new file mode 100644 index 0000000..0d24059 --- /dev/null +++ b/deploy/docker/.env.example @@ -0,0 +1,79 @@ +# ============================================================ +# Docker 部署环境变量模板 +# 使用方法: cp .env.example .env 然后按实际填写 +# 注意: .env 切勿提交到 git +# ============================================================ + +# ---------- 基础 ---------- +TZ=Asia/Shanghai +COMPOSE_PROJECT_NAME=integral-shop + +# ---------- 阿里云 RDS for MySQL ---------- +# 外网地址(与 240 同地域 VPC 时建议改为内网地址,更快更安全) +RDS_HOST=rm-bp1a178eq62lxba9xbo.mysql.rds.aliyuncs.com +RDS_PORT=3306 + +# 积分商城(Webman PHP 后端) +RDS_INTEGRAL_DB=yangtangyoupin +RDS_INTEGRAL_USER=yangtangyoupin +RDS_INTEGRAL_PASS=change-me + +# 寄卖商城(Spring Boot 后端) — 与积分商城共库共账号 +RDS_SINGLE_DB=yangtangyoupin +RDS_SINGLE_USER=yangtangyoupin +RDS_SINGLE_PASS=change-me + +# ---------- 容器内 Redis ---------- +REDIS_PASSWORD=change-me-redis +# 三个业务各自的 db 序号,建议互不冲突 +REDIS_INTEGRAL_DB=0 +REDIS_SINGLE_ADMIN_DB=25 +REDIS_SINGLE_FRONT_DB=26 + +# 是否把 Redis 端口暴露到宿主机(生产建议不暴露,留空字符串即可关闭) +REDIS_HOST_PORT=6379 + +# ---------- 积分商城 H5 configs.js 注入 ---------- +# 用户浏览器访问到的 API/图片/H5 域名(必须为外网可达 URL) +INTEGRAL_API_PUBLIC_URL=https://admin.example.com +INTEGRAL_IMG_PUBLIC_URL=https://admin.example.com +INTEGRAL_H5_PUBLIC_URL=https://h5.example.com/ +# 业务标识:sn_id(数字)、appStr(与寄卖商城 APP_SECRET 必须一致) +INTEGRAL_SN_ID=17533260260405 +INTEGRAL_APP_STR=ZFyTNQTWEkCBczKzyUDJWE9Ecx260405 +INTEGRAL_TITLE=晨召春商贸 +INTEGRAL_CONTRACT_PAGE=10012 + +# ---------- 积分商城 Webman 后端短信 / OSS ---------- +# 不用就保持空值;启用时填写真实凭证(也可直接编辑 integral-resell/.env 文件) +SMS_CHANNEL=alibaba +SMS_SIGNNAME= +SMS_TEMPLATE= +SMS_KEYID= +SMS_KEYSECRET= + +# OSS_TYPE=public 表示用本地 public/upload;oss 表示走阿里云 OSS +FILE_STORAGE=public +OSS_ACCESS_ID= +OSS_ACCESS_SECRET= +OSS_BUCKET= +OSS_ENDPOINT= +OSS_URL= + +# ---------- 寄卖商城前端构建参数 ---------- +# 留空即走与 Nginx 同域 /api/,最佳实践;如要直连后端写完整 URL +SINGLE_ADMIN_BASE_API= +SINGLE_H5_DOMAIN= + +# ---------- 寄卖商城后端 JVM ---------- +SINGLE_ADMIN_JAVA_OPTS=-Xms256m -Xmx512m +SINGLE_FRONT_JAVA_OPTS=-Xms256m -Xmx768m + +# ---------- 寄卖商城订单同步(无 MER 时填默认) ---------- +SYNC_SOURCE_ID= +SYNC_TARGET_MER_ID=0 + +# ---------- 宿主机暴露端口(可按需修改) ---------- +INTEGRAL_H5_PORT=18080 +SINGLE_ADMIN_WEB_PORT=18081 +SINGLE_H5_PORT=18082 diff --git a/deploy/docker/.gitignore b/deploy/docker/.gitignore new file mode 100644 index 0000000..f7d19fa --- /dev/null +++ b/deploy/docker/.gitignore @@ -0,0 +1,3 @@ +# 部署敏感文件不入库 +.env +integral-resell/.env diff --git a/deploy/docker/README.md b/deploy/docker/README.md new file mode 100644 index 0000000..e2a39da --- /dev/null +++ b/deploy/docker/README.md @@ -0,0 +1,113 @@ +# Docker 部署 — 快速上手 + +> 详细方案见仓库根目录的 `DOCKER_DEPLOY.md`。本文件只列必要操作。 + +## 1. 准备环境变量 + +```bash +cd deploy/docker +cp .env.example .env +$EDITOR .env # 填入 RDS / Redis / 域名 等 + +cp integral-resell/.env.template integral-resell/.env +$EDITOR integral-resell/.env # 积分商城 Webman 后端配置 +``` + +## 2. 阿里云 RDS 初始化 + +在 RDS 控制台新建: +- 积分商城库(默认名 `yangtangyoupin`)→ 导入 `db/yangtangyoupin.sql` +- 寄卖商城库(默认同上)→ 导入 `db/shop22-v2.sql`(或与生产对齐的 `db/jjy153-mysql.sql`) + +把 Docker 主机出口 IP 加入 RDS 白名单。 + +## 3. 构建并启动 + +```bash +# 一次性构建所有镜像(首次 5-15 分钟,含 Maven & Node 拉依赖) +docker compose build + +# 后台启动全部服务 +docker compose up -d + +# 查看状态 +docker compose ps +docker compose logs -f single-admin-api +docker compose logs -f single-front-api +docker compose logs -f integral-houtai +``` + +## 4. 验证 + +| URL | 期望 | +|-----|------| +| `http://:18080/` | 积分商城 H5 首页 | +| `http://:18080/api/...` | 转发到 integral-houtai | +| `http://:18081/` | 寄卖管理后台登录页 | +| `http://:18082/` | 寄卖用户端 H5 | + +## 5. 常用运维 + +```bash +docker compose restart single-admin-api +docker compose build --no-cache single-front-api && docker compose up -d single-front-api +docker compose exec single-admin-api sh +docker compose down # 不删卷 +docker compose down -v # 连卷一并删除(**慎用**) +``` + +## 6. 备份卷 + +```bash +# 在 docker host 上运行 +for v in integral-upload single-images redis-data; do + docker run --rm -v $v:/d -v $(pwd):/b alpine \ + tar czf /b/${v}-$(date +%F).tgz -C /d . +done +``` + +## 7. "fast" 模式(跳过前端构建,使用源码已有 dist) + +如果源码目录里 `backend-adminend/dist` 和 `single_uniapp22miao/unpackage/dist/build/` 已经是最新构建产物,可加速: + +```bash +docker compose build --build-arg=BUILDKIT_INLINE_CACHE=1 \ + --target fast single-admin-web single-h5 +``` + +## 8. 切换为外部 Redis + +把 `.env` 中 `REDIS_HOST` 改为外部地址、注释 `docker-compose.yml` 中的 `redis:` 服务即可。Spring Boot 与 Webman 都通过环境变量读取 Redis 地址。 + +## 9. 远端一键部署(116.62.83.240) + +```bash +cd scripts +cp server.env.example server.env # 已预填 116.62.83.240 / root / A@123456 + +# 首次(推荐):把密码登录换成 SSH key +ssh-copy-id root@116.62.83.240 +# 然后把 server.env 里的 SSHPASS 行注释掉 + +# 同步代码并启动 +./sync-to-server.sh up + +# 同步完成后,若是首次部署还需要先在远端填写 .env: +./bootstrap-remote-env.sh +./remote-up.sh ssh +# 远端:cd /root/integral-shop/deploy/docker +# vim .env +# vim integral-resell/.env +# 编辑完退出后: +./remote-up.sh up + +# 日常运维(本机执行,不用登录服务器) +./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 +``` + +> 用密码模式需要先 `brew install hudochenkov/sshpass/sshpass`(macOS)。 +> 用 SSH key 模式则任何依赖都不需要。 + diff --git a/deploy/docker/docker-compose.yml b/deploy/docker/docker-compose.yml new file mode 100644 index 0000000..5ecff7d --- /dev/null +++ b/deploy/docker/docker-compose.yml @@ -0,0 +1,187 @@ +# ============================================================= +# 寄卖商城 + 积分商城 前后端 Docker 编排 +# - 不含 MER-2.2 多商户 +# - 不含 MySQL(使用阿里云 RDS) +# - 包含独立 Redis(如需用外部 Redis,注释掉 redis 服务并修改 REDIS_HOST) +# ============================================================= + +name: integral-shop + +x-common: &common + restart: unless-stopped + environment: + TZ: ${TZ:-Asia/Shanghai} + logging: + driver: json-file + options: + max-size: "20m" + max-file: "5" + +networks: + inner: + driver: bridge + +volumes: + redis-data: + integral-runtime: + integral-upload: + single-images: + single-logs: + +services: + # ---------------- Redis ---------------- + redis: + <<: *common + image: redis:6.2-alpine + container_name: integral-shop-redis + command: ["redis-server", "/etc/redis/redis.conf", "--requirepass", "${REDIS_PASSWORD}"] + volumes: + - ./redis/redis.conf:/etc/redis/redis.conf:ro + - redis-data:/data + networks: [inner] + # 仅当 REDIS_HOST_PORT 非空时暴露 + ports: + - "${REDIS_HOST_PORT:-}:6379" + healthcheck: + test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"] + interval: 10s + timeout: 3s + retries: 5 + + # ---------------- 积分商城:Webman 后端 ---------------- + integral-houtai: + <<: *common + build: + context: ../../integral-resell/houtai + dockerfile: ../../deploy/docker/integral-resell/houtai.Dockerfile + image: integral-shop/integral-houtai:latest + container_name: integral-houtai + networks: [inner] + volumes: + # .env 由宿主机模板渲染挂入容器;编辑此文件即可改 DB / OSS / 短信 + - ./integral-resell/.env:/app/.env:ro + - integral-runtime:/app/runtime + - integral-upload:/app/public/upload + depends_on: + redis: + condition: service_healthy + + # ---------------- 积分商城:H5 静态站 ---------------- + integral-h5: + <<: *common + build: + context: ../../integral-resell/h5 + dockerfile: ../../deploy/docker/integral-resell/h5.Dockerfile + image: integral-shop/integral-h5:latest + container_name: integral-h5 + networks: [inner] + environment: + TZ: ${TZ:-Asia/Shanghai} + # 这些会在 entrypoint 中被注入到 static/configs.js + INTEGRAL_TITLE: ${INTEGRAL_TITLE} + INTEGRAL_API_PUBLIC_URL: ${INTEGRAL_API_PUBLIC_URL} + INTEGRAL_IMG_PUBLIC_URL: ${INTEGRAL_IMG_PUBLIC_URL} + INTEGRAL_H5_PUBLIC_URL: ${INTEGRAL_H5_PUBLIC_URL} + INTEGRAL_SN_ID: ${INTEGRAL_SN_ID} + INTEGRAL_APP_STR: ${INTEGRAL_APP_STR} + INTEGRAL_CONTRACT_PAGE: ${INTEGRAL_CONTRACT_PAGE} + ports: + - "${INTEGRAL_H5_PORT:-18080}:80" + depends_on: + - integral-houtai + + # ---------------- 寄卖商城:管理后台 API ---------------- + single-admin-api: + <<: *common + build: + context: ../../single-shop-22/backend + dockerfile: ../../deploy/docker/single-shop/admin-api.Dockerfile + image: integral-shop/single-admin-api:latest + container_name: single-admin-api + networks: [inner] + environment: + TZ: ${TZ:-Asia/Shanghai} + JAVA_HEAP_OPTS: ${SINGLE_ADMIN_JAVA_OPTS:--Xms128m -Xmx256m} + SPRING_PROFILES_ACTIVE: docker + SERVER_PORT: "30032" + MYSQL_HOST: ${RDS_HOST} + MYSQL_PORT: ${RDS_PORT:-3306} + MYSQL_DATABASE: ${RDS_SINGLE_DB} + MYSQL_USERNAME: ${RDS_SINGLE_USER} + MYSQL_PASSWORD: ${RDS_SINGLE_PASS} + REDIS_HOST: redis + REDIS_PORT: "6379" + REDIS_PASSWORD: ${REDIS_PASSWORD} + REDIS_DATABASE: ${REDIS_SINGLE_ADMIN_DB:-25} + SYNC_SOURCE_ID: ${SYNC_SOURCE_ID:-} + SYNC_TARGET_MER_ID: ${SYNC_TARGET_MER_ID:-0} + volumes: + - ./single-shop/application-docker.yml:/config/application-docker.yml:ro + - single-images:/usr/local/crmeb/crmebimage + - single-logs:/app/log + depends_on: + redis: + condition: service_healthy + + # ---------------- 寄卖商城:用户端 API ---------------- + single-front-api: + <<: *common + build: + context: ../../single-shop-22/backend + dockerfile: ../../deploy/docker/single-shop/front-api.Dockerfile + image: integral-shop/single-front-api:latest + container_name: single-front-api + networks: [inner] + environment: + TZ: ${TZ:-Asia/Shanghai} + JAVA_OPTS: ${SINGLE_FRONT_JAVA_OPTS:--Xms256m -Xmx768m} + SPRING_PROFILES_ACTIVE: docker + SERVER_PORT: "30031" + MYSQL_HOST: ${RDS_HOST} + MYSQL_PORT: ${RDS_PORT:-3306} + MYSQL_DATABASE: ${RDS_SINGLE_DB} + MYSQL_USERNAME: ${RDS_SINGLE_USER} + MYSQL_PASSWORD: ${RDS_SINGLE_PASS} + REDIS_HOST: redis + REDIS_PORT: "6379" + REDIS_PASSWORD: ${REDIS_PASSWORD} + REDIS_DATABASE: ${REDIS_SINGLE_FRONT_DB:-26} + volumes: + - ./single-shop/application-docker.yml:/config/application-docker.yml:ro + - single-images:/usr/local/crmeb/crmebimage + - single-logs:/app/log + depends_on: + redis: + condition: service_healthy + + # ---------------- 寄卖商城:管理后台 Web ---------------- + single-admin-web: + <<: *common + build: + context: ../../single-shop-22/backend-adminend + dockerfile: ../../deploy/docker/single-shop/admin-web.Dockerfile + args: + VUE_APP_BASE_API: ${SINGLE_ADMIN_BASE_API:-} + image: integral-shop/single-admin-web:latest + container_name: single-admin-web + networks: [inner] + ports: + - "${SINGLE_ADMIN_WEB_PORT:-18081}:80" + depends_on: + - single-admin-api + + # ---------------- 寄卖商城:用户端 H5 ---------------- + single-h5: + <<: *common + build: + context: ../../single-shop-22/single_uniapp22miao + dockerfile: ../../deploy/docker/single-shop/h5.Dockerfile + args: + H5_API_DOMAIN: ${SINGLE_H5_DOMAIN:-} + image: integral-shop/single-h5:latest + container_name: single-h5 + networks: [inner] + ports: + - "${SINGLE_H5_PORT:-18082}:80" + depends_on: + - single-front-api diff --git a/deploy/docker/nginx/leilei-jf.czchunfang.com.conf b/deploy/docker/nginx/leilei-jf.czchunfang.com.conf new file mode 100644 index 0000000..9524b91 --- /dev/null +++ b/deploy/docker/nginx/leilei-jf.czchunfang.com.conf @@ -0,0 +1,83 @@ +upstream jifenmall_h5 { + server 127.0.0.1:18082; + keepalive 10240; +} + +server +{ + listen 80; + listen 443 ssl; + http2 on; + server_name leilei-jf.czchunfang.com; + index index.html index.htm default.htm default.html; + root /www/wwwroot/leilei-jf.czchunfang.com; + include /www/server/panel/vhost/nginx/extension/leilei-jf.czchunfang.com/*.conf; + #CERT-APPLY-CHECK--START + include /www/server/panel/vhost/nginx/well-known/leilei-jf.czchunfang.com.conf; + #CERT-APPLY-CHECK--END + + #SSL-START + #error_page 404/404.html; + #HTTP_TO_HTTPS_START + set $isRedcert 1; + if ($server_port != 443) { + set $isRedcert 2; + } + if ( $uri ~ /\.well-known/ ) { + set $isRedcert 1; + } + if ($isRedcert != 1) { + rewrite ^(/.*)$ https://$host$1 permanent; + } + #HTTP_TO_HTTPS_END + ssl_certificate /www/wwwroot/integral-shop/deploy/docker/ssl-cert/leilei-jf.czchunfang.com_cert/nginx/leilei-jf.czchunfang.com.pem; + ssl_certificate_key /www/wwwroot/integral-shop/deploy/docker/ssl-cert/leilei-jf.czchunfang.com_cert/nginx/leilei-jf.czchunfang.com.key; + ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; + ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; + ssl_prefer_server_ciphers on; + ssl_session_tickets on; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + add_header Strict-Transport-Security "max-age=31536000"; + error_page 497 https://$host$request_uri; + #SSL-END + + #REWRITE-START + include /www/server/panel/vhost/rewrite/html_leilei-jf.czchunfang.com.conf; + #REWRITE-END + + # 积分商城 H5 → Docker single-h5 容器(uni-app SPA) + location ^~ / { + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Real-IP $remote_addr; + proxy_http_version 1.1; + proxy_set_header Connection ""; + if (!-f $request_filename) { + proxy_pass http://jifenmall_h5; + } + } + + location ~* (\.user.ini|\.htaccess|\.htpasswd|\.env.*|\.project|\.bashrc|\.bash_profile|\.bash_logout|\.DS_Store|\.gitignore|\.gitattributes|LICENSE|README\.md|CLAUDE\.md|CHANGELOG\.md|CHANGELOG|CONTRIBUTING\.md|TODO\.md|FAQ\.md|composer\.json|composer\.lock|package(-lock)?\.json|yarn\.lock|pnpm-lock\.yaml|\.\w+~|\.swp|\.swo|\.bak(up)?|\.old|\.tmp|\.temp|\.log|\.sql(\.gz)?|docker-compose\.yml|docker\.env|Dockerfile|\.csproj|\.sln|Cargo\.toml|Cargo\.lock|go\.mod|go\.sum|phpunit\.xml|phpunit\.xml|pom\.xml|build\.gradl|pyproject\.toml|requirements\.txt|application(-\w+)?\.(ya?ml|properties))$ + { return 404; } + + location ~* /(\.git|\.svn|\.bzr|\.vscode|\.claude|\.idea|\.ssh|\.github|\.npm|\.yarn|\.pnpm|\.cache|\.husky|\.turbo|\.next|\.nuxt|node_modules|runtime)/ + { return 404; } + + location ~ \.well-known { allow all; } + + if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) { + return 403; + } + + location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { + expires 30d; error_log /dev/null; access_log /dev/null; + } + location ~ .*\.(js|css)?$ { + expires 12h; error_log /dev/null; access_log /dev/null; + } + + access_log /www/wwwlogs/leilei-jf.czchunfang.com.log; + error_log /www/wwwlogs/leilei-jf.czchunfang.com.error.log; +} diff --git a/deploy/docker/nginx/leilei-jfadmin.czchunfang.com.conf b/deploy/docker/nginx/leilei-jfadmin.czchunfang.com.conf new file mode 100644 index 0000000..248388a --- /dev/null +++ b/deploy/docker/nginx/leilei-jfadmin.czchunfang.com.conf @@ -0,0 +1,83 @@ +upstream jifenmall_admin { + server 127.0.0.1:18081; + keepalive 10240; +} + +server +{ + listen 80; + listen 443 ssl; + http2 on; + server_name leilei-jfadmin.czchunfang.com; + index index.html index.htm default.htm default.html; + root /www/wwwroot/leilei-jfadmin.czchunfang.com; + include /www/server/panel/vhost/nginx/extension/leilei-jfadmin.czchunfang.com/*.conf; + #CERT-APPLY-CHECK--START + include /www/server/panel/vhost/nginx/well-known/leilei-jfadmin.czchunfang.com.conf; + #CERT-APPLY-CHECK--END + + #SSL-START + #error_page 404/404.html; + #HTTP_TO_HTTPS_START + set $isRedcert 1; + if ($server_port != 443) { + set $isRedcert 2; + } + if ( $uri ~ /\.well-known/ ) { + set $isRedcert 1; + } + if ($isRedcert != 1) { + rewrite ^(/.*)$ https://$host$1 permanent; + } + #HTTP_TO_HTTPS_END + ssl_certificate /www/wwwroot/integral-shop/deploy/docker/ssl-cert/leilei-jfadmin.czchunfang.com_cert/nginx/leilei-jfadmin.czchunfang.com.pem; + ssl_certificate_key /www/wwwroot/integral-shop/deploy/docker/ssl-cert/leilei-jfadmin.czchunfang.com_cert/nginx/leilei-jfadmin.czchunfang.com.key; + ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; + ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; + ssl_prefer_server_ciphers on; + ssl_session_tickets on; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + add_header Strict-Transport-Security "max-age=31536000"; + error_page 497 https://$host$request_uri; + #SSL-END + + #REWRITE-START + include /www/server/panel/vhost/rewrite/html_leilei-jfadmin.czchunfang.com.conf; + #REWRITE-END + + # 积分商城管理后台 → Docker single-admin-web 容器(Vue SPA) + location ^~ / { + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Real-IP $remote_addr; + proxy_http_version 1.1; + proxy_set_header Connection ""; + if (!-f $request_filename) { + proxy_pass http://jifenmall_admin; + } + } + + location ~* (\.user.ini|\.htaccess|\.htpasswd|\.env.*|\.project|\.bashrc|\.bash_profile|\.bash_logout|\.DS_Store|\.gitignore|\.gitattributes|LICENSE|README\.md|CLAUDE\.md|CHANGELOG\.md|CHANGELOG|CONTRIBUTING\.md|TODO\.md|FAQ\.md|composer\.json|composer\.lock|package(-lock)?\.json|yarn\.lock|pnpm-lock\.yaml|\.\w+~|\.swp|\.swo|\.bak(up)?|\.old|\.tmp|\.temp|\.log|\.sql(\.gz)?|docker-compose\.yml|docker\.env|Dockerfile|\.csproj|\.sln|Cargo\.toml|Cargo\.lock|go\.mod|go\.sum|phpunit\.xml|phpunit\.xml|pom\.xml|build\.gradl|pyproject\.toml|requirements\.txt|application(-\w+)?\.(ya?ml|properties))$ + { return 404; } + + location ~* /(\.git|\.svn|\.bzr|\.vscode|\.claude|\.idea|\.ssh|\.github|\.npm|\.yarn|\.pnpm|\.cache|\.husky|\.turbo|\.next|\.nuxt|node_modules|runtime)/ + { return 404; } + + location ~ \.well-known { allow all; } + + if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) { + return 403; + } + + location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { + expires 30d; error_log /dev/null; access_log /dev/null; + } + location ~ .*\.(js|css)?$ { + expires 12h; error_log /dev/null; access_log /dev/null; + } + + access_log /www/wwwlogs/leilei-jfadmin.czchunfang.com.log; + error_log /www/wwwlogs/leilei-jfadmin.czchunfang.com.error.log; +} diff --git a/deploy/docker/nginx/leilei.czchunfang.com.conf b/deploy/docker/nginx/leilei.czchunfang.com.conf new file mode 100644 index 0000000..5edb8a2 --- /dev/null +++ b/deploy/docker/nginx/leilei.czchunfang.com.conf @@ -0,0 +1,82 @@ +upstream resell_h5 { + server 127.0.0.1:18080; + keepalive 10240; +} + +server +{ + listen 80; + listen 443 ssl http2; + server_name leilei.czchunfang.com; + index index.html index.htm default.htm default.html; + root /www/wwwroot/leilei.czchunfang.com; + include /www/server/panel/vhost/nginx/extension/leilei.czchunfang.com/*.conf; + #CERT-APPLY-CHECK--START + include /www/server/panel/vhost/nginx/well-known/leilei.czchunfang.com.conf; + #CERT-APPLY-CHECK--END + + #SSL-START + #error_page 404/404.html; + #HTTP_TO_HTTPS_START + set $isRedcert 1; + if ($server_port != 443) { + set $isRedcert 2; + } + if ( $uri ~ /\.well-known/ ) { + set $isRedcert 1; + } + if ($isRedcert != 1) { + rewrite ^(/.*)$ https://$host$1 permanent; + } + #HTTP_TO_HTTPS_END + ssl_certificate /www/wwwroot/integral-shop/deploy/docker/ssl-cert/leilei.czchunfang.com_cert/nginx/leilei.czchunfang.com.pem; + ssl_certificate_key /www/wwwroot/integral-shop/deploy/docker/ssl-cert/leilei.czchunfang.com_cert/nginx/leilei.czchunfang.com.key; + ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; + ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; + ssl_prefer_server_ciphers on; + ssl_session_tickets on; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + add_header Strict-Transport-Security "max-age=31536000"; + error_page 497 https://$host$request_uri; + #SSL-END + + #REWRITE-START + include /www/server/panel/vhost/rewrite/html_leilei.czchunfang.com.conf; + #REWRITE-END + + # 寄卖商城 H5 → Docker integral-h5 容器(内部已含 /api/ /upload/ 反代到 webman:8785) + location ^~ / { + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Real-IP $remote_addr; + proxy_http_version 1.1; + proxy_set_header Connection ""; + if (!-f $request_filename) { + proxy_pass http://resell_h5; + } + } + + location ~* (\.user.ini|\.htaccess|\.htpasswd|\.env.*|\.project|\.bashrc|\.bash_profile|\.bash_logout|\.DS_Store|\.gitignore|\.gitattributes|LICENSE|README\.md|CLAUDE\.md|CHANGELOG\.md|CHANGELOG|CONTRIBUTING\.md|TODO\.md|FAQ\.md|composer\.json|composer\.lock|package(-lock)?\.json|yarn\.lock|pnpm-lock\.yaml|\.\w+~|\.swp|\.swo|\.bak(up)?|\.old|\.tmp|\.temp|\.log|\.sql(\.gz)?|docker-compose\.yml|docker\.env|Dockerfile|\.csproj|\.sln|Cargo\.toml|Cargo\.lock|go\.mod|go\.sum|phpunit\.xml|phpunit\.xml|pom\.xml|build\.gradl|pyproject\.toml|requirements\.txt|application(-\w+)?\.(ya?ml|properties))$ + { return 404; } + + location ~* /(\.git|\.svn|\.bzr|\.vscode|\.claude|\.idea|\.ssh|\.github|\.npm|\.yarn|\.pnpm|\.cache|\.husky|\.turbo|\.next|\.nuxt|node_modules|runtime)/ + { return 404; } + + location ~ \.well-known { allow all; } + + if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) { + return 403; + } + + location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { + expires 30d; error_log /dev/null; access_log /dev/null; + } + location ~ .*\.(js|css)?$ { + expires 12h; error_log /dev/null; access_log /dev/null; + } + + access_log /www/wwwlogs/leilei.czchunfang.com.log; + error_log /www/wwwlogs/leilei.czchunfang.com.error.log; +} diff --git a/deploy/docker/nginx/leileiadmin.czchunfang.com.conf b/deploy/docker/nginx/leileiadmin.czchunfang.com.conf new file mode 100644 index 0000000..9d51029 --- /dev/null +++ b/deploy/docker/nginx/leileiadmin.czchunfang.com.conf @@ -0,0 +1,82 @@ +upstream resell_api { + server 127.0.0.1:18085; + keepalive 10240; +} + +server +{ + listen 80; + listen 443 ssl http2; + server_name leileiadmin.czchunfang.com; + index index.html index.htm default.htm default.html; + root /www/wwwroot/leileiadmin.czchunfang.com; + include /www/server/panel/vhost/nginx/extension/leileiadmin.czchunfang.com/*.conf; + #CERT-APPLY-CHECK--START + include /www/server/panel/vhost/nginx/well-known/leileiadmin.czchunfang.com.conf; + #CERT-APPLY-CHECK--END + + #SSL-START + #error_page 404/404.html; + #HTTP_TO_HTTPS_START + set $isRedcert 1; + if ($server_port != 443) { + set $isRedcert 2; + } + if ( $uri ~ /\.well-known/ ) { + set $isRedcert 1; + } + if ($isRedcert != 1) { + rewrite ^(/.*)$ https://$host$1 permanent; + } + #HTTP_TO_HTTPS_END + ssl_certificate /www/wwwroot/integral-shop/deploy/docker/ssl-cert/leileiadmin.czchunfang.com_cert/nginx/leileiadmin.czchunfang.com.pem; + ssl_certificate_key /www/wwwroot/integral-shop/deploy/docker/ssl-cert/leileiadmin.czchunfang.com_cert/nginx/leileiadmin.czchunfang.com.key; + ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; + ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; + ssl_prefer_server_ciphers on; + ssl_session_tickets on; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + add_header Strict-Transport-Security "max-age=31536000"; + error_page 497 https://$host$request_uri; + #SSL-END + + #REWRITE-START + include /www/server/panel/vhost/rewrite/html_leileiadmin.czchunfang.com.conf; + #REWRITE-END + + # 寄卖商城后台 API → Docker integral-houtai 容器(webman.bin 写死端口 8785) + location ^~ / { + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Real-IP $remote_addr; + proxy_http_version 1.1; + proxy_set_header Connection ""; + if (!-f $request_filename) { + proxy_pass http://resell_api; + } + } + + location ~* (\.user.ini|\.htaccess|\.htpasswd|\.env.*|\.project|\.bashrc|\.bash_profile|\.bash_logout|\.DS_Store|\.gitignore|\.gitattributes|LICENSE|README\.md|CLAUDE\.md|CHANGELOG\.md|CHANGELOG|CONTRIBUTING\.md|TODO\.md|FAQ\.md|composer\.json|composer\.lock|package(-lock)?\.json|yarn\.lock|pnpm-lock\.yaml|\.\w+~|\.swp|\.swo|\.bak(up)?|\.old|\.tmp|\.temp|\.log|\.sql(\.gz)?|docker-compose\.yml|docker\.env|Dockerfile|\.csproj|\.sln|Cargo\.toml|Cargo\.lock|go\.mod|go\.sum|phpunit\.xml|phpunit\.xml|pom\.xml|build\.gradl|pyproject\.toml|requirements\.txt|application(-\w+)?\.(ya?ml|properties))$ + { return 404; } + + location ~* /(\.git|\.svn|\.bzr|\.vscode|\.claude|\.idea|\.ssh|\.github|\.npm|\.yarn|\.pnpm|\.cache|\.husky|\.turbo|\.next|\.nuxt|node_modules|runtime)/ + { return 404; } + + location ~ \.well-known { allow all; } + + if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) { + return 403; + } + + location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { + expires 30d; error_log /dev/null; access_log /dev/null; + } + location ~ .*\.(js|css)?$ { + expires 12h; error_log /dev/null; access_log /dev/null; + } + + access_log /www/wwwlogs/leileiadmin.czchunfang.com.log; + error_log /www/wwwlogs/leileiadmin.czchunfang.com.error.log; +} diff --git a/deploy/docker/redis/redis.conf b/deploy/docker/redis/redis.conf new file mode 100644 index 0000000..62afd8c --- /dev/null +++ b/deploy/docker/redis/redis.conf @@ -0,0 +1,39 @@ +# ============================================================= +# Redis 6.2 — 容器内最小化生产配置 +# 密码由 docker-compose 通过 --requirepass 参数注入 +# ============================================================= + +bind 0.0.0.0 +protected-mode yes +port 6379 +tcp-backlog 511 +timeout 0 +tcp-keepalive 300 + +# 数据持久化: AOF + 一份 RDB 兜底 +appendonly yes +appendfsync everysec +save 900 1 +save 300 10 +save 60 10000 + +dir /data +dbfilename dump.rdb +appendfilename "appendonly.aof" +auto-aof-rewrite-percentage 100 +auto-aof-rewrite-min-size 64mb + +# 内存策略 +maxmemory 512mb +maxmemory-policy allkeys-lru + +# 日志 +loglevel notice +logfile "" + +# 慢日志 +slowlog-log-slower-than 10000 +slowlog-max-len 128 + +# 客户端 +maxclients 1000 diff --git a/deploy/docker/scripts/.gitignore b/deploy/docker/scripts/.gitignore new file mode 100644 index 0000000..4503ccb --- /dev/null +++ b/deploy/docker/scripts/.gitignore @@ -0,0 +1 @@ +server.env diff --git a/deploy/docker/scripts/bootstrap-remote-env.sh b/deploy/docker/scripts/bootstrap-remote-env.sh new file mode 100755 index 0000000..7eec3f6 --- /dev/null +++ b/deploy/docker/scripts/bootstrap-remote-env.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# ============================================================= +# 首次部署:在远端创建 .env 模板(仅在缺失时创建) +# 同步代码后执行: ./bootstrap-remote-env.sh +# 之后 ssh 上去 vim 这两个文件填入真实密码即可 +# ============================================================= + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +if [ -f "$SCRIPT_DIR/server.env" ]; then + set -a; . "$SCRIPT_DIR/server.env"; set +a +fi + +SERVER_HOST="${SERVER_HOST:?}" +SERVER_USER="${SERVER_USER:-root}" +SERVER_PORT="${SERVER_PORT:-22}" +REMOTE_DIR="${REMOTE_DIR:-/root/integral-shop}" + +if [ -n "${SSHPASS:-}" ]; then + command -v sshpass >/dev/null || { echo "需要 sshpass"; exit 1; } + export SSHPASS + SSH=(sshpass -e ssh -p "$SERVER_PORT" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null) +else + SSH=(ssh -p "$SERVER_PORT" -o StrictHostKeyChecking=no) +fi + +"${SSH[@]}" "${SERVER_USER}@${SERVER_HOST}" bash -se < "$TMPENV/.env" < "$TMPENV/houtai.env" </dev/null 2>&1 || { echo "需要 sshpass"; exit 1; } + export SSHPASS + SSH=(sshpass -e ssh -p "$SERVER_PORT" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -t) +else + SSH=(ssh -p "$SERVER_PORT" -o StrictHostKeyChecking=no -t) +fi + +run_remote() { + "${SSH[@]}" "${SERVER_USER}@${SERVER_HOST}" "cd ${REMOTE_DIR}/deploy/docker && $*" +} + +cmd="${1:-up}" +shift || true + +case "$cmd" in + up) + # 预检:必须存在 .env + run_remote "test -f .env && test -f integral-resell/.env" || { + cat < server.env,填入主机/密码 +# 2. ./sync-to-server.sh # 仅同步 +# ./sync-to-server.sh up # 同步后在远端 docker compose build && up -d +# ./sync-to-server.sh logs # 远端 docker compose logs +# ============================================================= + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" + +# 读取服务器配置 +if [ -f "$SCRIPT_DIR/server.env" ]; then + # shellcheck disable=SC1091 + set -a + . "$SCRIPT_DIR/server.env" + set +a +elif [ -f "$SCRIPT_DIR/server.env.example" ]; then + echo "[!] 未发现 server.env,请先 cp server.env.example server.env 并修改" + exit 1 +fi + +SERVER_HOST="${SERVER_HOST:?SERVER_HOST 未配置}" +SERVER_USER="${SERVER_USER:-root}" +SERVER_PORT="${SERVER_PORT:-22}" +REMOTE_DIR="${REMOTE_DIR:-/root/integral-shop}" + +# ---------- 选择 SSH/rsync 通道 ---------- +if [ -n "${SSHPASS:-}" ]; then + if ! command -v sshpass >/dev/null 2>&1; then + echo "[!] 检测到 SSHPASS 但未安装 sshpass" + echo " macOS: brew install hudochenkov/sshpass/sshpass" + echo " Linux: apt-get install -y sshpass" + exit 1 + fi + export SSHPASS + SSH=(sshpass -e ssh -p "$SERVER_PORT" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null) + RSYNC_SSH="sshpass -e ssh -p $SERVER_PORT -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" +else + SSH=(ssh -p "$SERVER_PORT" -o StrictHostKeyChecking=no -o ServerAliveInterval=30) + RSYNC_SSH="ssh -p $SERVER_PORT -o StrictHostKeyChecking=no -o ServerAliveInterval=30" +fi + +remote() { + "${SSH[@]}" "${SERVER_USER}@${SERVER_HOST}" "$@" +} + +# ---------- 1. 远端目录准备 ---------- +echo "[1/3] 准备远端目录 ${SERVER_USER}@${SERVER_HOST}:${REMOTE_DIR}" +remote "mkdir -p '${REMOTE_DIR}'" + +# 优先使用 homebrew rsync(macOS 内置版本 2.6.9 太旧) +RSYNC_BIN="/opt/homebrew/bin/rsync" +[ -x "$RSYNC_BIN" ] || RSYNC_BIN="rsync" + +# ---------- 2. rsync ---------- +echo "[2/3] rsync ${PROJECT_ROOT}/ -> ${SERVER_USER}@${SERVER_HOST}:${REMOTE_DIR}/" +"$RSYNC_BIN" -avz --delete --partial \ + -e "$RSYNC_SSH" \ + --exclude '.git/' \ + --exclude '.DS_Store' \ + --exclude '*.log' \ + --exclude '**/.idea/' \ + --exclude '**/.cursor/' \ + --exclude '**/.vscode/' \ + --exclude '**/node_modules/' \ + --exclude '**/target/' \ + --exclude '**/unpackage/cache/' \ + --exclude '**/unpackage/dist/dev/' \ + --exclude 'integral-resell/houtai/runtime/logs/' \ + --exclude 'integral-resell/houtai/runtime/sessions/' \ + --exclude 'integral-resell/houtai/runtime/login/' \ + --exclude 'integral-resell/houtai/runtime/webman.pid' \ + --exclude 'single-shop-22/backend/logs/' \ + --exclude 'single-shop-22/backend/crmebimage/' \ + --exclude 'single-shop-22/backend-adminend/dist/' \ + --exclude 'MER-2.2_2601/' \ + --exclude 'db/mysql-recover-20260514/' \ + --exclude 'db/yangtangyoupin.sql' \ + --exclude 'deploy/docker/.env' \ + --exclude 'deploy/docker/integral-resell/.env' \ + --exclude 'deploy/docker/scripts/server.env' \ + "${PROJECT_ROOT}/" "${SERVER_USER}@${SERVER_HOST}:${REMOTE_DIR}/" + +# ---------- 3. 远端 env 文件提示 ---------- +echo "[3/3] 检查远端环境文件" +remote "test -f ${REMOTE_DIR}/deploy/docker/.env || echo '[!] 远端缺少 deploy/docker/.env,请按下面提示创建'" +remote "test -f ${REMOTE_DIR}/deploy/docker/integral-resell/.env || echo '[!] 远端缺少 deploy/docker/integral-resell/.env'" + +echo +echo "===============================================" +echo " rsync 完成" +echo " 远端目录: ${REMOTE_DIR}" +echo "===============================================" + +# ---------- 后续动作 ---------- +case "${1:-${AUTO_UP:-}}" in + up|yes|YES) + echo "[远端] 执行 docker compose build && up -d" + "$SCRIPT_DIR/remote-up.sh" up + ;; + build) + "$SCRIPT_DIR/remote-up.sh" build + ;; + logs) + shift || true + "$SCRIPT_DIR/remote-up.sh" logs "$@" + ;; + "") + echo "下一步:" + echo " $0 up # 同步并启动" + echo " $0 build # 仅构建" + echo " $0 logs # 查看日志" + ;; + *) + echo "未知参数: $1" + exit 2 + ;; +esac diff --git a/deploy/docker/single-shop/admin-api.Dockerfile b/deploy/docker/single-shop/admin-api.Dockerfile new file mode 100644 index 0000000..29c5199 --- /dev/null +++ b/deploy/docker/single-shop/admin-api.Dockerfile @@ -0,0 +1,62 @@ +# ============================================================= +# 寄卖商城 管理后台 API (miao-admin-2.2.jar) +# build context = single-shop-22/backend +# 对应宿主机启动命令: +# nohup java -Xms128m -Xmx256m -jar miao-admin-2.2.jar > admin.log & +# ============================================================= +# syntax=docker/dockerfile:1.6 + +FROM maven:3.8.8-eclipse-temurin-17 AS builder +WORKDIR /src +COPY pom.xml ./ +COPY crmeb-common/pom.xml crmeb-common/pom.xml +COPY crmeb-service/pom.xml crmeb-service/pom.xml +COPY crmeb-admin/pom.xml crmeb-admin/pom.xml +COPY crmeb-front/pom.xml crmeb-front/pom.xml +RUN mvn -B -pl crmeb-admin -am dependency:go-offline -DskipTests || true +COPY . . +RUN mvn -B clean package -pl crmeb-admin -am -DskipTests + +FROM eclipse-temurin:17-jre-jammy +ENV TZ=Asia/Shanghai \ + DEBIAN_FRONTEND=noninteractive \ + LANG=C.UTF-8 LC_ALL=C.UTF-8 + +# 堆大小:可通过 compose 的 JAVA_HEAP_OPTS 覆盖 +ENV JAVA_HEAP_OPTS="-Xms128m -Xmx256m" + +# Spring Boot 2.2.6 + Java 17 必须的模块开放参数(固定,不允许 compose 覆盖) +ENV JAVA_MODULE_OPTS="\ + --add-opens java.base/java.lang=ALL-UNNAMED \ + --add-opens java.base/java.lang.reflect=ALL-UNNAMED \ + --add-opens java.base/java.util=ALL-UNNAMED \ + --add-opens java.base/java.io=ALL-UNNAMED \ + --add-opens java.base/java.math=ALL-UNNAMED \ + --add-opens java.base/sun.net.util=ALL-UNNAMED \ + --add-opens java.base/java.net=ALL-UNNAMED" + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + tzdata ca-certificates curl \ + fontconfig fonts-dejavu fonts-wqy-zenhei \ + && ln -sf /usr/share/zoneinfo/$TZ /etc/localtime \ + && echo $TZ > /etc/timezone \ + && rm -rf /var/lib/apt/lists/* \ + && mkdir -p /app /config /usr/local/crmeb/crmebimage /app/log + +WORKDIR /app +COPY --from=builder /src/crmeb-admin/target/miao-admin-2.2.jar /app/app.jar + +EXPOSE 30032 + +# 等价于:nohup java -Xms128m -Xmx256m -jar miao-admin-2.2.jar > admin.log & +# 日志直接输出到容器 stdout,docker logs 可查看 +ENTRYPOINT ["sh","-c","exec java \ + $JAVA_HEAP_OPTS \ + $JAVA_MODULE_OPTS \ + -Dfile.encoding=UTF-8 \ + -Duser.timezone=$TZ \ + -jar /app/app.jar \ + --spring.profiles.active=${SPRING_PROFILES_ACTIVE:-docker} \ + --spring.config.additional-location=file:/config/ \ + --server.port=${SERVER_PORT:-30032}"] diff --git a/deploy/docker/single-shop/admin-web.Dockerfile b/deploy/docker/single-shop/admin-web.Dockerfile new file mode 100644 index 0000000..13c959d --- /dev/null +++ b/deploy/docker/single-shop/admin-web.Dockerfile @@ -0,0 +1,88 @@ +# ============================================================= +# 寄卖商城 管理后台前端 (Vue 2 / Vue CLI 4) +# build context = single-shop-22/backend-adminend +# 多阶段: Node 构建 -> Nginx 运行;可通过 ARG VUE_APP_BASE_API 注入 API 域名 +# +# 想直接使用源码里已有的 dist/: 用 --target=fast 构建 +# ============================================================= +# syntax=docker/dockerfile:1.6 + +# ---------- 构建阶段(默认) ---------- +FROM node:16-alpine AS builder + +# 留空(默认)→ 浏览器走与 nginx 同域的 /api/;填具体 URL 则直连后端 +ARG VUE_APP_BASE_API="" +ENV NODE_OPTIONS=--openssl-legacy-provider \ + NPM_CONFIG_REGISTRY=https://registry.npmmirror.com + +WORKDIR /app +COPY package.json yarn.lock* package-lock.json* ./ +RUN (yarn install --frozen-lockfile 2>/dev/null) || npm ci || npm install --legacy-peer-deps + +COPY . . +# 覆盖 .env.production,使用 build arg +RUN printf "ENV='production'\nVUE_APP_BASE_API=%s\n" "$VUE_APP_BASE_API" > .env.production \ + && npm run build:prod + +# ---------- 运行阶段 ---------- +FROM nginx:1.25-alpine AS runtime +ENV TZ=Asia/Shanghai +RUN apk add --no-cache tzdata \ + && cp /usr/share/zoneinfo/$TZ /etc/localtime \ + && echo $TZ > /etc/timezone + +COPY --from=builder /app/dist /usr/share/nginx/html + +RUN cat > /etc/nginx/conf.d/default.conf <<'NGX' +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + client_max_body_size 50m; + add_header X-Frame-Options SAMEORIGIN always; + + location ~* \.(?:js|css|png|jpg|jpeg|gif|svg|woff2?|ttf|map)$ { + expires 30d; + add_header Cache-Control "public, max-age=2592000, immutable"; + try_files $uri =404; + } + + # 反代到管理后台 API + location /api/ { + proxy_pass http://single-admin-api:30032/api/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 120s; + client_max_body_size 50m; + } + + # CRMEB 部分接口直接命中 /adminapi (兼容) + location /adminapi/ { + proxy_pass http://single-admin-api:30032/adminapi/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + location / { + try_files $uri $uri/ /index.html; + } +} +NGX + +EXPOSE 80 + +# ---------- 备选: 直接复用源码已构建的 dist/(fast 模式) ---------- +# 构建命令: docker compose build --target fast single-admin-web +FROM nginx:1.25-alpine AS fast +ENV TZ=Asia/Shanghai +RUN apk add --no-cache tzdata \ + && cp /usr/share/zoneinfo/$TZ /etc/localtime \ + && echo $TZ > /etc/timezone +COPY dist/ /usr/share/nginx/html +COPY --from=runtime /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf +EXPOSE 80 diff --git a/deploy/docker/single-shop/application-docker.yml b/deploy/docker/single-shop/application-docker.yml new file mode 100644 index 0000000..663b9ab --- /dev/null +++ b/deploy/docker/single-shop/application-docker.yml @@ -0,0 +1,68 @@ +# ============================================================= +# 寄卖商城 Docker 部署专用 Spring profile +# 通过 --spring.config.additional-location=file:/config/ + --spring.profiles.active=docker +# 加载本文件,并由环境变量覆盖关键参数 +# ============================================================= + +server: + port: ${SERVER_PORT:30032} + +crmeb: + imagePath: /usr/local/crmeb/crmebimage/ + captchaOn: false + asyncConfig: true + demoSite: false + +spring: + datasource: + name: ${MYSQL_DATABASE} + 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&allowPublicKeyRetrieval=true + username: ${MYSQL_USERNAME} + password: ${MYSQL_PASSWORD} + druid: + initial-size: 5 + min-idle: 5 + max-active: 50 + max-wait: 60000 + validation-query: SELECT 1 + test-while-idle: true + test-on-borrow: false + test-on-return: false + redis: + host: ${REDIS_HOST:redis} + port: ${REDIS_PORT:6379} + password: ${REDIS_PASSWORD:} + database: ${REDIS_DATABASE:0} + timeout: 10000 + jedis: + pool: + max-active: 200 + max-wait: -1 + max-idle: 10 + min-idle: 0 + time-between-eviction-runs: -1 + +# 订单同步(无 MER 时填默认) +sync: + source-id: ${SYNC_SOURCE_ID:} + target-mer-id: ${SYNC_TARGET_MER_ID:0} + +logging: + level: + io.swagger.*: error + com.zbjk.crmeb: info + org.springframework.boot.autoconfigure: ERROR + config: classpath:logback-spring.xml + file: + path: /app/log + +mybatis-plus: + configuration: + log-impl: + +swagger: + basic: + enable: false + check: false diff --git a/deploy/docker/single-shop/front-api.Dockerfile b/deploy/docker/single-shop/front-api.Dockerfile new file mode 100644 index 0000000..c66cb22 --- /dev/null +++ b/deploy/docker/single-shop/front-api.Dockerfile @@ -0,0 +1,62 @@ +# ============================================================= +# 寄卖商城 用户端 API (miao-front-2.2.jar) +# build context = single-shop-22/backend +# 对应宿主机启动命令: +# nohup java -Xms128m -Xmx256m -jar miao-front-2.2.jar > front.log & +# ============================================================= +# syntax=docker/dockerfile:1.6 + +FROM maven:3.8.8-eclipse-temurin-17 AS builder +WORKDIR /src +COPY pom.xml ./ +COPY crmeb-common/pom.xml crmeb-common/pom.xml +COPY crmeb-service/pom.xml crmeb-service/pom.xml +COPY crmeb-admin/pom.xml crmeb-admin/pom.xml +COPY crmeb-front/pom.xml crmeb-front/pom.xml +RUN mvn -B -pl crmeb-front -am dependency:go-offline -DskipTests || true +COPY . . +RUN mvn -B clean package -pl crmeb-front -am -DskipTests + +FROM eclipse-temurin:17-jre-jammy +ENV TZ=Asia/Shanghai \ + DEBIAN_FRONTEND=noninteractive \ + LANG=C.UTF-8 LC_ALL=C.UTF-8 + +# 堆大小:可通过 compose 的 JAVA_HEAP_OPTS 覆盖 +ENV JAVA_HEAP_OPTS="-Xms128m -Xmx256m" + +# Spring Boot 2.2.6 + Java 17 必须的模块开放参数(固定,不允许 compose 覆盖) +ENV JAVA_MODULE_OPTS="\ + --add-opens java.base/java.lang=ALL-UNNAMED \ + --add-opens java.base/java.lang.reflect=ALL-UNNAMED \ + --add-opens java.base/java.util=ALL-UNNAMED \ + --add-opens java.base/java.io=ALL-UNNAMED \ + --add-opens java.base/java.math=ALL-UNNAMED \ + --add-opens java.base/sun.net.util=ALL-UNNAMED \ + --add-opens java.base/java.net=ALL-UNNAMED" + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + tzdata ca-certificates curl \ + fontconfig fonts-dejavu fonts-wqy-zenhei \ + && ln -sf /usr/share/zoneinfo/$TZ /etc/localtime \ + && echo $TZ > /etc/timezone \ + && rm -rf /var/lib/apt/lists/* \ + && mkdir -p /app /config /usr/local/crmeb/crmebimage /app/log + +WORKDIR /app +COPY --from=builder /src/crmeb-front/target/miao-front-2.2.jar /app/app.jar + +EXPOSE 30031 + +# 等价于:nohup java -Xms128m -Xmx256m -jar miao-front-2.2.jar > front.log & +# 日志直接输出到容器 stdout,docker logs 可查看 +ENTRYPOINT ["sh","-c","exec java \ + $JAVA_HEAP_OPTS \ + $JAVA_MODULE_OPTS \ + -Dfile.encoding=UTF-8 \ + -Duser.timezone=$TZ \ + -jar /app/app.jar \ + --spring.profiles.active=${SPRING_PROFILES_ACTIVE:-docker} \ + --spring.config.additional-location=file:/config/ \ + --server.port=${SERVER_PORT:-30031}"] diff --git a/deploy/docker/single-shop/h5.Dockerfile b/deploy/docker/single-shop/h5.Dockerfile new file mode 100644 index 0000000..ee51ddd --- /dev/null +++ b/deploy/docker/single-shop/h5.Dockerfile @@ -0,0 +1,96 @@ +# ============================================================= +# 寄卖商城 用户端 H5 (uni-app) +# build context = single-shop-22/single_uniapp22miao +# 多阶段: Node 构建 H5 -> Nginx 运行 +# 通过 ARG H5_API_DOMAIN 注入 API 域名(留空走同域 /api/) +# +# 直接复用源码已构建产物: 用 --target=fast 构建 +# ============================================================= +# syntax=docker/dockerfile:1.6 + +# ---------- 构建阶段 ---------- +FROM node:16-alpine AS builder +ARG H5_API_DOMAIN="" +ENV NODE_OPTIONS=--openssl-legacy-provider \ + NPM_CONFIG_REGISTRY=https://registry.npmmirror.com + +WORKDIR /app +COPY package.json package-lock.json* ./ +RUN npm install --legacy-peer-deps + +COPY . . + +# 重写 config/app.js 中的 domain +# 留空时使用同域: let domain = '' +RUN sed -i -E "s|^let[[:space:]]+domain[[:space:]]*=.*|let domain = '${H5_API_DOMAIN}'|" config/app.js \ + && sed -i -E "s|HTTP_H5_URL:[[:space:]]*'[^']*'|HTTP_H5_URL: '${H5_API_DOMAIN}'|" config/app.js \ + && cat config/app.js + +RUN npm run build:h5 + +# uni-app 默认产物路径 +# unpackage/dist/build/h5 (Vue CLI Plugin uni 旧版: unpackage/dist/build/web) + +# ---------- 运行阶段 ---------- +FROM nginx:1.25-alpine AS runtime +ENV TZ=Asia/Shanghai +RUN apk add --no-cache tzdata \ + && cp /usr/share/zoneinfo/$TZ /etc/localtime \ + && echo $TZ > /etc/timezone + +COPY --from=builder /app/unpackage/dist/build/ /tmp/h5build/ +# 兼容两种输出目录名 h5/ 或 web/ +RUN if [ -d /tmp/h5build/h5 ]; then cp -r /tmp/h5build/h5/. /usr/share/nginx/html/; \ + elif [ -d /tmp/h5build/web ]; then cp -r /tmp/h5build/web/. /usr/share/nginx/html/; \ + else echo "未找到 h5 / web 产物"; exit 1; fi \ + && rm -rf /tmp/h5build + +RUN cat > /etc/nginx/conf.d/default.conf <<'NGX' +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + client_max_body_size 50m; + add_header X-Frame-Options SAMEORIGIN always; + + location ~* \.(?:js|css|png|jpg|jpeg|gif|svg|woff2?|ttf|map)$ { + expires 30d; + add_header Cache-Control "public, max-age=2592000, immutable"; + try_files $uri =404; + } + + location /api/ { + proxy_pass http://single-front-api:30031/api/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 120s; + client_max_body_size 50m; + } + + location / { + try_files $uri $uri/ /index.html; + } +} +NGX + +EXPOSE 80 + +# ---------- 备选: 直接复用源码已构建的 unpackage/dist/build/h5 ---------- +# 构建: docker compose build --target fast single-h5 +FROM nginx:1.25-alpine AS fast +ENV TZ=Asia/Shanghai +RUN apk add --no-cache tzdata \ + && cp /usr/share/zoneinfo/$TZ /etc/localtime \ + && echo $TZ > /etc/timezone + +COPY unpackage/dist/build/ /tmp/h5build/ +RUN if [ -d /tmp/h5build/h5 ]; then cp -r /tmp/h5build/h5/. /usr/share/nginx/html/; \ + elif [ -d /tmp/h5build/web ]; then cp -r /tmp/h5build/web/. /usr/share/nginx/html/; \ + else echo "未找到 h5 / web 产物"; exit 1; fi \ + && rm -rf /tmp/h5build +COPY --from=runtime /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf +EXPOSE 80 diff --git a/deploy/docker/single-shop/nginx-admin-web.conf b/deploy/docker/single-shop/nginx-admin-web.conf new file mode 100644 index 0000000..dc88c9c --- /dev/null +++ b/deploy/docker/single-shop/nginx-admin-web.conf @@ -0,0 +1,37 @@ +# 仅供参考: 内容已内联到 admin-web.Dockerfile +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + client_max_body_size 50m; + add_header X-Frame-Options SAMEORIGIN always; + + location ~* \.(?:js|css|png|jpg|jpeg|gif|svg|woff2?|ttf|map)$ { + expires 30d; + add_header Cache-Control "public, max-age=2592000, immutable"; + try_files $uri =404; + } + + location /api/ { + proxy_pass http://single-admin-api:30032/api/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 120s; + client_max_body_size 50m; + } + + location /adminapi/ { + proxy_pass http://single-admin-api:30032/adminapi/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + location / { + try_files $uri $uri/ /index.html; + } +} diff --git a/deploy/docker/single-shop/nginx-h5.conf b/deploy/docker/single-shop/nginx-h5.conf new file mode 100644 index 0000000..84837c3 --- /dev/null +++ b/deploy/docker/single-shop/nginx-h5.conf @@ -0,0 +1,30 @@ +# 仅供参考: 内容已内联到 h5.Dockerfile +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + client_max_body_size 50m; + add_header X-Frame-Options SAMEORIGIN always; + + location ~* \.(?:js|css|png|jpg|jpeg|gif|svg|woff2?|ttf|map)$ { + expires 30d; + add_header Cache-Control "public, max-age=2592000, immutable"; + try_files $uri =404; + } + + location /api/ { + proxy_pass http://single-front-api:30031/api/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 120s; + client_max_body_size 50m; + } + + location / { + try_files $uri $uri/ /index.html; + } +} diff --git a/deploy/docker/ssl-cert/.gitignore b/deploy/docker/ssl-cert/.gitignore new file mode 100644 index 0000000..f746035 --- /dev/null +++ b/deploy/docker/ssl-cert/.gitignore @@ -0,0 +1,7 @@ +# 忽略证书文件,不入库 +*.pem +*.key +*.crt +*.cer +*.p12 +*.pfx diff --git a/deploy/docker/step1-integral/.env.example b/deploy/docker/step1-integral/.env.example new file mode 100644 index 0000000..e77ba45 --- /dev/null +++ b/deploy/docker/step1-integral/.env.example @@ -0,0 +1,31 @@ +# ============================================================= +# 步骤一:寄卖商城环境变量 — 池州雷蕾商贸 czleilei240 +# cp .env.example .env 并填入真实密码 +# .env 不入库 +# ============================================================= + +TZ=Asia/Shanghai + +# ---------- Redis(容器内) ---------- +REDIS_PASSWORD=change-me-redis + +# ---------- H5 对外域名(浏览器可达) ---------- +INTEGRAL_TITLE=池州雷蕾商贸 +INTEGRAL_API_PUBLIC_URL=https://leileiadmin.czchunfang.com +INTEGRAL_IMG_PUBLIC_URL=https://leileiadmin.czchunfang.com +INTEGRAL_H5_PUBLIC_URL=https://leilei.czchunfang.com/ +INTEGRAL_SN_ID=17533260260517 +INTEGRAL_APP_STR=ZFyTNQTWEkCBczKzyUDJWE9Ecx260517 +INTEGRAL_CONTRACT_PAGE=10012 + +# ---------- 宿主机暴露端口 ---------- +INTEGRAL_H5_PORT=18080 +# webman API 直连端口(宝塔 Nginx leileiadmin.czchunfang.com → 此端口) +RESELL_API_PORT=18085 + +# ---------- 宿主机目录映射(bind mount,与原部署路径一致)---------- +# 寄卖商城 H5 静态文件目录(手动改 JS/configs.js 直接生效,无需重建镜像) +RESELL_H5_DIR=/www/wwwroot/leilei.czchunfang.com +# webman 后台完整应用目录(FTP 上传新 webman.bin/public/ 后 restart 容器即可更新) +# 上传图片、public/upload 等均包含在此目录内,无需单独挂载 +RESELL_HOUTAI_DIR=/www/wwwroot/leileiadmin.czchunfang.com diff --git a/deploy/docker/step1-integral/.gitignore b/deploy/docker/step1-integral/.gitignore new file mode 100644 index 0000000..4621727 --- /dev/null +++ b/deploy/docker/step1-integral/.gitignore @@ -0,0 +1,2 @@ +.env +houtai.env diff --git a/deploy/docker/step1-integral/README.md b/deploy/docker/step1-integral/README.md new file mode 100644 index 0000000..a46e27c --- /dev/null +++ b/deploy/docker/step1-integral/README.md @@ -0,0 +1,126 @@ +# 步骤一:寄卖商城 Docker 部署(池州雷蕾商贸 czleilei240) + +项目:`integral-resell`(寄卖商城) +服务:`redis` · `integral-houtai`(Webman PHP 8.0)· `integral-h5`(Nginx 静态站) + +步骤二(积分商城)与本步骤完全独立,可以单独部署、单独重启。 + +--- + +## 快速部署 + +```bash +cd deploy/docker/step1-integral + +# 1. 准备环境变量 +cp .env.example .env +cp houtai.env.example houtai.env +vim .env # 填入 REDIS_PASSWORD +vim houtai.env # 填入 DB_PASSWORD(RDS 密码)、REDIS_PASSWORD(同 .env) + +# 2. 首次部署:在服务器上确保宿主机目录存在 +# (若原部署目录已存在则跳过) +mkdir -p /www/wwwroot/leilei.czchunfang.com +mkdir -p /www/wwwroot/leileiadmin.czchunfang.com/public/upload + +# 3. 将 H5 静态文件同步到宿主机目录(首次 / 每次前端更新后) +rsync -av integral-resell/h5/ /www/wwwroot/leilei.czchunfang.com/ + +# 4. 构建并启动 +docker compose --env-file .env up -d --build + +# 5. 查看状态 +docker compose --env-file .env ps +docker compose --env-file .env logs -f integral-houtai +``` + +--- + +## 目录映射(宿主机 ↔ 容器) + +| 宿主机路径 | 容器路径 | 用途 | +|---|---|---| +| `/www/wwwroot/leilei.czchunfang.com` | `/usr/share/nginx/html` | H5 静态文件,手动改 JS 即时生效 | +| `/www/wwwroot/leileiadmin.czchunfang.com/public/upload` | `/app/public/upload` | webman 后台上传文件 | +| `./houtai.env` | `/app/.env` | 运行时配置,只读挂入,不打进镜像 | +| `integral-runtime`(named vol)| `/app/runtime` | webman PID、session 等运行时数据 | + +> **H5 文件更新流程**:直接修改 `/www/wwwroot/leilei.czchunfang.com/` 下的文件(如 JS bundle、configs.js), +> Nginx 下次请求时自动读取新文件,**无需重启容器**。 +> 仅当 Nginx 配置或镜像本身需要变更时,才需要 `docker compose build integral-h5`。 + +| 域名 | 用途 | Docker 容器端口 | 宿主机端口 | 宝塔 upstream | +|---|---|---|---|---| +| `leilei.czchunfang.com` | 寄卖商城 H5 | integral-h5:80 | **18080** | `resell_h5` | +| `leileiadmin.czchunfang.com` | 寄卖商城 API / 后台 | integral-houtai:**8785** | **18085** | `resell_api` | + +> webman.bin 写死监听 **8785** 端口。 +> - H5 容器内部 Nginx 已将 `/api/` 和 `/upload/` 代理到 `integral-houtai:8785`(Docker 内网,无需暴露) +> - 宝塔 Nginx 的 `leileiadmin.czchunfang.com` 直连宿主机 **18085**(映射到 webman 8785) + +--- + +## 宝塔 Nginx 配置 + +将以下两个文件内容分别粘贴到宝塔面板对应站点的「配置文件」中: + +| 配置文件 | 说明 | +|---|---| +| `deploy/docker/nginx/leilei.czchunfang.com.conf` | H5 站点,upstream → 127.0.0.1:18080 | +| `deploy/docker/nginx/leileiadmin.czchunfang.com.conf` | API 站点,upstream → 127.0.0.1:18085 | + +证书路径(文件已在项目中): + +``` +deploy/docker/ssl-cert/ + leilei.czchunfang.com_cert/nginx/leilei.czchunfang.com.{pem,key} + leileiadmin.czchunfang.com_cert/nginx/leileiadmin.czchunfang.com.{pem,key} +``` + +--- + +## 验证 + +| 地址 | 预期 | +|------|------| +| `https://leilei.czchunfang.com/` | 寄卖商城 H5 首页(生产) | +| `https://leileiadmin.czchunfang.com/api/...` | 寄卖商城 API(生产) | +| `http://116.62.83.240:18080/` | H5 直连测试(绕过域名/SSL) | + +--- + +## 常用命令 + +```bash +# 重启 webman +docker compose --env-file .env restart integral-houtai + +# 看 webman 日志 +docker compose --env-file .env logs -f integral-houtai + +# 进入 webman 容器 +docker compose --env-file .env exec integral-houtai bash + +# 仅重建 H5(改了 .env 中的域名参数后) +docker compose --env-file .env build integral-h5 +docker compose --env-file .env up -d integral-h5 + +# 停止(保留卷) +docker compose --env-file .env down + +# 停止并删除所有卷(慎用:清空上传图片和 runtime) +docker compose --env-file .env down -v +``` + +--- + +## 关键一致性检查 + +| 位置 | 值 | +|---|---| +| `.env` INTEGRAL_API_PUBLIC_URL | `https://leileiadmin.czchunfang.com` | +| `.env` INTEGRAL_H5_PUBLIC_URL | `https://leilei.czchunfang.com/` | +| `.env` INTEGRAL_APP_STR | `ZFyTNQTWEkCBczKzyUDJWE9Ecx260517` | +| `houtai.env` APP_SECRET | **同上** | +| `.env` INTEGRAL_SN_ID | `17533260260517` | +| `h5/static/configs.js` sn_id | **同上** | diff --git a/deploy/docker/step1-integral/docker-compose.yml b/deploy/docker/step1-integral/docker-compose.yml new file mode 100644 index 0000000..acee8d5 --- /dev/null +++ b/deploy/docker/step1-integral/docker-compose.yml @@ -0,0 +1,95 @@ +# ============================================================= +# 步骤一:寄卖商城(integral-resell)独立部署 +# 客户:池州雷蕾商贸 czleilei240 +# 包含服务:redis · integral-houtai(webman) · integral-h5(Nginx) +# ============================================================= + +name: resell-czleilei240 + +x-common: &common + restart: unless-stopped + environment: + TZ: ${TZ:-Asia/Shanghai} + logging: + driver: json-file + options: + max-size: "20m" + max-file: "5" + +networks: + integral-net: + driver: bridge + +volumes: + integral-redis-data: + integral-runtime: + +services: + # ---------- Redis ---------- + redis: + <<: *common + build: + context: . + dockerfile: redis.Dockerfile + image: resell-czleilei240/redis:local + container_name: integral-redis + command: ["--requirepass", "${REDIS_PASSWORD}", "--appendonly", "yes"] + volumes: + - integral-redis-data:/data + networks: [integral-net] + healthcheck: + test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"] + interval: 10s + timeout: 3s + retries: 5 + + # ---------- Webman 后端 ---------- + integral-houtai: + <<: *common + build: + context: ../../../integral-resell/houtai + dockerfile: ../../deploy/docker/integral-resell/houtai.Dockerfile + image: resell-czleilei240/houtai:latest + container_name: integral-houtai + networks: [integral-net] + ports: + # 宝塔 Nginx 直连 webman API(webman.bin 写死监听 8785) + - "${RESELL_API_PORT:-18085}:8785" + volumes: + # 整个应用目录挂到宿主机 /www/wwwroot/leileiadmin.czchunfang.com/ + # FTP 上传新 webman.bin / public/ 后 docker compose restart integral-houtai 即可生效 + - ${RESELL_HOUTAI_DIR}:/app + # .env 单独挂入(覆盖宿主机目录里的 .env),避免明文密码出现在 wwwroot + - ./houtai.env:/app/.env:ro + # runtime 使用命名卷(日志/session/pid 不受 FTP 覆盖影响) + - integral-runtime:/app/runtime + depends_on: + redis: + condition: service_healthy + + # ---------- H5 静态站 ---------- + integral-h5: + <<: *common + build: + context: ../../../integral-resell/h5 + dockerfile: ../../deploy/docker/integral-resell/h5.Dockerfile + image: resell-czleilei240/h5:latest + container_name: integral-h5 + networks: [integral-net] + environment: + TZ: ${TZ:-Asia/Shanghai} + INTEGRAL_TITLE: ${INTEGRAL_TITLE} + INTEGRAL_API_PUBLIC_URL: ${INTEGRAL_API_PUBLIC_URL} + INTEGRAL_IMG_PUBLIC_URL: ${INTEGRAL_IMG_PUBLIC_URL} + INTEGRAL_H5_PUBLIC_URL: ${INTEGRAL_H5_PUBLIC_URL} + INTEGRAL_SN_ID: ${INTEGRAL_SN_ID} + INTEGRAL_APP_STR: ${INTEGRAL_APP_STR} + INTEGRAL_CONTRACT_PAGE: ${INTEGRAL_CONTRACT_PAGE} + volumes: + # H5 静态文件目录挂到宿主机,手动更新 JS/configs.js 直接生效,无需重建镜像 + # 子目录 crmebimage/ 同时由步骤二 Java 后端写入(PDF/图片),Nginx 直接对外提供访问 + - ${RESELL_H5_DIR}:/usr/share/nginx/html + ports: + - "${INTEGRAL_H5_PORT:-18080}:80" + depends_on: + - integral-houtai diff --git a/deploy/docker/step1-integral/houtai.env.example b/deploy/docker/step1-integral/houtai.env.example new file mode 100644 index 0000000..193ff21 --- /dev/null +++ b/deploy/docker/step1-integral/houtai.env.example @@ -0,0 +1,37 @@ +# ============================================================= +# Webman 后端运行时配置 — 池州雷蕾商贸 czleilei240(寄卖商城) +# cp houtai.env.example houtai.env 并填入真实密码 +# houtai.env 不入库,由 docker-compose volumes: 挂入 /app/.env +# ============================================================= + +# MySQL(阿里云 RDS) +DB_HOST = 'rm-bp1a178eq62lxba9xbo.mysql.rds.aliyuncs.com' +DB_PORT = 3306 +DB_DATABASE = 'yangtangyoupin' +DB_USERNAME = 'yangtangyoupin' +DB_PASSWORD = 'change-me' + +# Redis(指向同 compose 内的 redis 容器) +REDIS_HOST = 'redis' +REDIS_PORT = 6379 +REDIS_PASSWORD = 'change-me-redis' + +# 短信(池州雷蕾商贸专属通道) +SMS_CHANNEL = 'alibaba' +SMS_SIGNNAME = '池州雷蕾商贸' +SMS_TEMPLATE = 'SMS_334320185' +SMS_KEYID = 'LTAI5t7CfS15hZGdNLLEMUwG' +SMS_KEYSECRET = 'ikfTvHbMMg5sStGgdvLNL8iuVYdner' +SMS_SDKAPPID = '' + +# OSS(不启用则走本地 public/upload) +FILE_STORAGE = 'public' +OSS_ACCESS_ID = '' +OSS_ACCESS_SECRET = '' +OSS_BUCKET = '' +OSS_ENDPOINT = '' +OSS_URL = '' + +# 业务标识(须与 H5 configs.js 的 sn_id / appStr 以及积分商城 admin 后台一致) +APP_SIGN = '1' +APP_SECRET = 'ZFyTNQTWEkCBczKzyUDJWE9Ecx260517' diff --git a/deploy/docker/step1-integral/redis.Dockerfile b/deploy/docker/step1-integral/redis.Dockerfile new file mode 100644 index 0000000..58e1edd --- /dev/null +++ b/deploy/docker/step1-integral/redis.Dockerfile @@ -0,0 +1,13 @@ +# 使用 Alpine 通过 apk 安装 Redis,绕过镜像源问题 +FROM alpine:3.19 + +RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \ + && apk add --no-cache redis tzdata \ + && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ + && echo "Asia/Shanghai" > /etc/timezone + +VOLUME /data +WORKDIR /data +EXPOSE 6379 + +ENTRYPOINT ["redis-server"] diff --git a/deploy/docker/step2-single-shop/.env.example b/deploy/docker/step2-single-shop/.env.example new file mode 100644 index 0000000..8069c39 --- /dev/null +++ b/deploy/docker/step2-single-shop/.env.example @@ -0,0 +1,37 @@ +# ============================================================= +# 步骤二:积分商城环境变量 — 池州雷蕾商贸 czleilei240 +# cp .env.example .env 并填入真实密码 +# .env 不入库 +# ============================================================= + +TZ=Asia/Shanghai + +# ---------- Redis(容器内,与步骤一独立) ---------- +REDIS_PASSWORD=change-me-redis + +# ---------- 阿里云 RDS ---------- +RDS_HOST=rm-bp1a178eq62lxba9xbo.mysql.rds.aliyuncs.com +RDS_DB=yangtangyoupin +RDS_USER=yangtangyoupin +RDS_PASSWORD=change-me + +# ---------- 积分商城 admin web 打包目标 URL ---------- +# VUE_APP_BASE_API(backend-adminend 打包时注入,指向 single-shop-22 admin-api) +SINGLE_ADMIN_API_PUBLIC_URL=https://leilei-jf.czchunfang.com + +# ---------- 积分商城 H5 打包目标 URL ---------- +# H5_API_DOMAIN(uni-app 打包时注入 config/app.js,指向 single-shop-22 front-api) +SINGLE_FRONT_API_PUBLIC_URL=https://leilei-jf.czchunfang.com + +# ---------- 订单同步(多商户 source / target) ---------- +SYNC_SOURCE_ID=shop_15 +SYNC_TARGET_MER_ID=15 + +# ---------- 图片/PDF 目录(与步骤一 H5 Nginx 共享宿主机路径)---------- +# Java 后端写入 /usr/local/crmeb/crmebimage/ → 宿主机 /www/wwwroot/leilei.czchunfang.com/crmebimage/ +# 步骤一的 H5 Nginx 从 /www/wwwroot/leilei.czchunfang.com/ 对外提供访问 +CRMEB_IMAGE_DIR=/www/wwwroot/leilei.czchunfang.com/crmebimage + +# ---------- 宿主机暴露端口 ---------- +SINGLE_ADMIN_PORT=18081 +SINGLE_H5_PORT=18082 diff --git a/deploy/docker/step2-single-shop/.gitignore b/deploy/docker/step2-single-shop/.gitignore new file mode 100644 index 0000000..4c49bd7 --- /dev/null +++ b/deploy/docker/step2-single-shop/.gitignore @@ -0,0 +1 @@ +.env diff --git a/deploy/docker/step2-single-shop/README.md b/deploy/docker/step2-single-shop/README.md new file mode 100644 index 0000000..4b09135 --- /dev/null +++ b/deploy/docker/step2-single-shop/README.md @@ -0,0 +1,130 @@ +# 步骤二:积分商城 Docker 部署(池州雷蕾商贸 czleilei240) + +项目:`single-shop-22`(积分商城) +服务:`redis` · `single-front-api`(Spring Boot)· `single-admin-api`(Spring Boot) +`single-admin-web`(Vue 管理后台)· `single-h5`(uni-app H5) + +步骤一(寄卖商城)与本步骤完全独立,可以单独部署、单独重启。 + +--- + +## 快速部署 + +```bash +cd deploy/docker/step2-single-shop + +# 1. 准备环境变量 +cp .env.example .env +vim .env # 填入 RDS_PASSWORD、REDIS_PASSWORD + +# 2. 全量构建并启动(首次,会编译 Java jar + 打包前端) +docker compose --env-file .env up -d --build + +# 3. 查看状态 +docker compose --env-file .env ps +docker compose --env-file .env logs -f single-front-api +docker compose --env-file .env logs -f single-admin-api +``` + +> ⚠️ Java 构建需要从 Maven Central 下载依赖,首次约需 10-20 分钟,请耐心等待。 + +--- + +## 域名与端口 + +| 域名 | 用途 | 宿主机端口 | +|---|---|---| +| `leilei-jf.czchunfang.com` | 积分商城 H5(uni-app) | **18082** | +| `leilei-jfadmin.czchunfang.com` | 积分商城管理后台(Vue) | **18081** | + +> Spring Boot API 端口(30032 / 30033)仅容器内使用,不对外暴露,通过 Nginx 反代访问。 + +--- + +## 宝塔 Nginx 配置 + +将以下两个文件内容分别粘贴到宝塔面板对应站点的「配置文件」中: + +| 配置文件 | 说明 | +|---|---| +| `deploy/docker/nginx/leilei-jf.czchunfang.com.conf` | H5 站点,upstream → 127.0.0.1:18082 | +| `deploy/docker/nginx/leilei-jfadmin.czchunfang.com.conf` | 管理后台,upstream → 127.0.0.1:18081 | + +证书路径(文件已在项目中): + +``` +deploy/docker/ssl-cert/ + leilei-jf.czchunfang.com_cert/nginx/leilei-jf.czchunfang.com.{pem,key} + leilei-jfadmin.czchunfang.com_cert/nginx/leilei-jfadmin.czchunfang.com.{pem,key} +``` + +--- + +## 验证 + +| 地址 | 预期 | +|------|------| +| `https://leilei-jf.czchunfang.com/` | 积分商城 H5(生产) | +| `https://leilei-jfadmin.czchunfang.com/` | 积分商城管理后台(生产) | +| `http://116.62.83.240:18082/` | H5 直连测试(绕过域名/SSL) | +| `http://116.62.83.240:18081/` | 管理后台直连测试 | + +--- + +## 仅重建前端(改了域名后) + +前端镜像在 build time 注入了 API 域名(`VUE_APP_BASE_API` / `H5_API_DOMAIN`), +修改 `.env` 中的 URL 后需要重新构建: + +```bash +# 重建管理后台(改了 SINGLE_ADMIN_API_PUBLIC_URL) +docker compose --env-file .env build single-admin-web +docker compose --env-file .env up -d single-admin-web + +# 重建 H5(改了 SINGLE_FRONT_API_PUBLIC_URL) +docker compose --env-file .env build single-h5 +docker compose --env-file .env up -d single-h5 +``` + +--- + +## 常用命令 + +```bash +# 重启某个服务 +docker compose --env-file .env restart single-admin-api + +# 实时日志 +docker compose --env-file .env logs -f single-admin-api +docker compose --env-file .env logs -f single-front-api + +# 进入容器 +docker compose --env-file .env exec single-admin-api bash + +# 停止(保留卷) +docker compose --env-file .env down + +# 停止并删除卷(慎用:清空图片/日志) +docker compose --env-file .env down -v +``` + +--- + +## czleilei240 关键配置对照 + +| 配置项 | 值 | +|---|---| +| RDS Host | `rm-bp1a178eq62lxba9xbo.mysql.rds.aliyuncs.com` | +| DB / User | `yangtangyoupin` | +| admin-web API URL(VUE_APP_BASE_API) | `https://leilei-jf.czchunfang.com` | +| H5 API Domain(H5_API_DOMAIN) | `https://leilei-jf.czchunfang.com` | +| SYNC_SOURCE_ID | `shop_15` | +| SYNC_TARGET_MER_ID | `15` | +| Spring profile | `docker`(application-docker.yml 通过 env 注入) | + +--- + +## 备注 + +- `single-images` 卷挂载到两个 API 容器,确保图片文件共享。 +- JVM 参数已包含 Java 17 + Spring Boot 2.2.6 所需的 `--add-opens` 标志(见 Dockerfile)。 diff --git a/deploy/docker/step2-single-shop/docker-compose.yml b/deploy/docker/step2-single-shop/docker-compose.yml new file mode 100644 index 0000000..0941867 --- /dev/null +++ b/deploy/docker/step2-single-shop/docker-compose.yml @@ -0,0 +1,163 @@ +# ============================================================= +# 步骤二:积分商城(single-shop-22)独立部署 +# 客户:池州雷蕾商贸 czleilei240 +# 包含服务:redis · single-admin-api · single-front-api +# single-admin-web(Vue) · single-h5(uni-app) +# ============================================================= + +name: jifenmall-czleilei240 + +x-common: &common + restart: unless-stopped + environment: + TZ: ${TZ:-Asia/Shanghai} + logging: + driver: json-file + options: + max-size: "20m" + max-file: "5" + +x-spring-common: &spring-common + <<: *common + environment: + TZ: ${TZ:-Asia/Shanghai} + MYSQL_HOST: ${RDS_HOST} + MYSQL_DATABASE: ${RDS_DB} + MYSQL_USERNAME: ${RDS_USER} + MYSQL_PASSWORD: ${RDS_PASSWORD} + REDIS_HOST: redis + REDIS_PORT: 6379 + REDIS_PASSWORD: ${REDIS_PASSWORD} + SYNC_SOURCE_ID: ${SYNC_SOURCE_ID:-shop_15} + SYNC_TARGET_MER_ID: ${SYNC_TARGET_MER_ID:-15} + +networks: + single-net: + driver: bridge + +volumes: + single-redis-data: + single-front-logs: + single-admin-logs: + +services: + # ---------- Redis ---------- + redis: + <<: *common + image: redis:6.2-alpine + container_name: single-redis + command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}", "--appendonly", "yes"] + volumes: + - single-redis-data:/data + networks: [single-net] + healthcheck: + test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"] + interval: 10s + timeout: 3s + retries: 5 + + # ---------- Front API(用户端 Spring Boot) ---------- + single-front-api: + <<: *spring-common + build: + context: ../../../single-shop-22/backend + dockerfile: ../../deploy/docker/single-shop/front-api.Dockerfile + image: jifenmall-czleilei240/front-api:latest + container_name: single-front-api + networks: [single-net] + volumes: + # 图片/PDF 目录 bind mount 到宿主机,与步骤一 H5 Nginx 共享同一路径 + # /www/wwwroot/leilei.czchunfang.com/crmebimage/ → 通过 leilei.czchunfang.com 对外访问 + - ${CRMEB_IMAGE_DIR}:/usr/local/crmeb/crmebimage + - single-front-logs:/app/log + - ../single-shop/application-docker.yml:/config/application-docker.yml:ro + environment: + TZ: ${TZ:-Asia/Shanghai} + MYSQL_HOST: ${RDS_HOST} + MYSQL_DATABASE: ${RDS_DB} + MYSQL_USERNAME: ${RDS_USER} + MYSQL_PASSWORD: ${RDS_PASSWORD} + REDIS_HOST: redis + REDIS_PORT: 6379 + REDIS_PASSWORD: ${REDIS_PASSWORD} + SYNC_SOURCE_ID: ${SYNC_SOURCE_ID:-shop_15} + SYNC_TARGET_MER_ID: ${SYNC_TARGET_MER_ID:-15} + SERVER_PORT: 30033 + depends_on: + redis: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "curl -sf http://localhost:30033/actuator/health || exit 1"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 90s + + # ---------- Admin API(管理端 Spring Boot) ---------- + single-admin-api: + <<: *spring-common + build: + context: ../../../single-shop-22/backend + dockerfile: ../../deploy/docker/single-shop/admin-api.Dockerfile + image: jifenmall-czleilei240/admin-api:latest + container_name: single-admin-api + networks: [single-net] + volumes: + # 图片/PDF 目录 bind mount 到宿主机,与步骤一 H5 Nginx 共享同一路径 + # /www/wwwroot/leilei.czchunfang.com/crmebimage/ → 通过 leilei.czchunfang.com 对外访问 + - ${CRMEB_IMAGE_DIR}:/usr/local/crmeb/crmebimage + - single-admin-logs:/app/log + - ../single-shop/application-docker.yml:/config/application-docker.yml:ro + environment: + TZ: ${TZ:-Asia/Shanghai} + MYSQL_HOST: ${RDS_HOST} + MYSQL_DATABASE: ${RDS_DB} + MYSQL_USERNAME: ${RDS_USER} + MYSQL_PASSWORD: ${RDS_PASSWORD} + REDIS_HOST: redis + REDIS_PORT: 6379 + REDIS_PASSWORD: ${REDIS_PASSWORD} + SYNC_SOURCE_ID: ${SYNC_SOURCE_ID:-shop_15} + SYNC_TARGET_MER_ID: ${SYNC_TARGET_MER_ID:-15} + SERVER_PORT: 30032 + depends_on: + redis: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "curl -sf http://localhost:30032/actuator/health || exit 1"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 90s + + # ---------- Admin Web(Vue 管理后台) ---------- + single-admin-web: + <<: *common + build: + context: ../../../single-shop-22/backend-adminend + dockerfile: ../../deploy/docker/single-shop/admin-web.Dockerfile + args: + VUE_APP_BASE_API: ${SINGLE_ADMIN_API_PUBLIC_URL} + image: jifenmall-czleilei240/admin-web:latest + container_name: single-admin-web + networks: [single-net] + ports: + - "${SINGLE_ADMIN_PORT:-18081}:80" + depends_on: + - single-admin-api + + # ---------- H5 前端(uni-app) ---------- + single-h5: + <<: *common + build: + context: ../../../single-shop-22/single_uniapp22miao + dockerfile: ../../deploy/docker/single-shop/h5.Dockerfile + args: + H5_API_DOMAIN: ${SINGLE_FRONT_API_PUBLIC_URL} + image: jifenmall-czleilei240/h5:latest + container_name: single-h5 + networks: [single-net] + ports: + - "${SINGLE_H5_PORT:-18082}:80" + depends_on: + - single-front-api diff --git a/deploy/ssl/leilei-jf.czchunfang.com_cert.zip b/deploy/ssl/leilei-jf.czchunfang.com_cert.zip new file mode 100644 index 0000000000000000000000000000000000000000..98d07b39c94f38bea587ab6eb96903aafe400b42 GIT binary patch literal 35713 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 S0)hX1Fo1)Ad=CHP?Ee5oNNkV* literal 0 HcmV?d00001 diff --git a/deploy/ssl/leilei-jfadmin.czchunfang.com_cert.zip b/deploy/ssl/leilei-jfadmin.czchunfang.com_cert.zip new file mode 100644 index 0000000000000000000000000000000000000000..c0f7b213a82e9de37c57f7f463d678797bd38cc5 GIT binary patch literal 35804 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 literal 0 HcmV?d00001 diff --git a/deploy/ssl/leilei.czchunfang.com_cert.zip b/deploy/ssl/leilei.czchunfang.com_cert.zip new file mode 100644 index 0000000000000000000000000000000000000000..a86f7d0b73cc61ff4dca3632f6964a5e67e3feda GIT binary patch literal 35655 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 T$`%mJ?-dgi2nZ|eucQA1wJI$m literal 0 HcmV?d00001 diff --git a/deploy/ssl/leileiadmin.czchunfang.com_cert.zip b/deploy/ssl/leileiadmin.czchunfang.com_cert.zip new file mode 100644 index 0000000000000000000000000000000000000000..b9359b920cd74f77743d5d3bb7911b470f6a83e9 GIT binary patch literal 35765 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