# 中科兴皖 Docker 部署说明 > 适用对象:甲方运维人员 > 部署方式:**预构建应用镜像 + compose**(交付包**不含**前后端源码;基础镜像 MySQL/Redis/MinIO 由甲方联网拉取) > 对外端口:**8112** --- ## 1. 环境要求 | 项 | 要求 | |----|------| | 操作系统 | Linux x86_64(推荐 Ubuntu 22.04 / CentOS 7+) | | Docker | ≥ 24.0 | | Docker Compose | v2(`docker compose` 子命令) | | 网络 | 可访问 Docker Hub 或已配置国内镜像加速 | | 硬件 | 建议 4 核 CPU、8 GB 内存、磁盘 ≥ 50 GB | | 端口 | 宿主机 **8112** 未被占用 | 验证: ```bash docker --version docker compose version docker info | grep -A2 "Registry Mirrors" # 建议已配置国内加速 ``` --- ## 1.1 Docker 镜像加速(国内强烈建议) **要配。** 与 pip / npm 镜像不是一回事: | 类型 | 作用 | 本项目中谁需要 | |------|------|----------------| | **Docker Registry 镜像** | 加速 `docker pull` / 构建时拉 `python:3.9-slim` 等 | **发版方打包** + **甲方首次 `compose up`** | | **PyPI / npm 镜像** | 构建镜像时 `pip install`、`pnpm install` | 仅发版方打包(已写在 Dockerfile 里) | 甲方 `docker load` 只导入你们提供的 `zkxw-backend` / `zkxw-web`;首次启动仍会 **pull** 例如: - `mysql:5.7.36`、`redis:7-alpine`、`minio/minio`、`minio/mc` 发版方在 Mac 上 `docker build` 时也要拉 `python:3.9-slim`、`node:20-alpine`、`nginx:1.27-alpine`。 ### macOS(Docker Desktop) **Settings → Docker Engine**,在 JSON 中增加(示例,任选可用加速地址): ```json { "registry-mirrors": [ "https://docker.1ms.run", "https://docker.m.daocloud.io" ] } ``` 保存后 **Apply & Restart**。你本机若 `docker info` 已显示 `Registry Mirrors: https://docker.1ms.run/`,说明已配置,无需重复。 ### Linux 云主机(发版 / 甲方) 编辑 `/etc/docker/daemon.json`: ```json { "registry-mirrors": [ "https://docker.1ms.run", "https://docker.m.daocloud.io" ] } ``` 然后: ```bash sudo systemctl daemon-reload sudo systemctl restart docker ``` ### 说明 - 镜像加速由 Docker 守护进程配置,**写进 Dockerfile 无效**。 - 公司若已有 **阿里云 ACR 个人版加速地址**,优先用官方提供的专属 URL。 - 应用镜像 `zkxw-*` 来自交付包 `docker load`,**不经过** Hub 拉取。 - 若 `docker.1ms.run` 拉取 `node`/`nginx` 报 **not found**,前端构建 Dockerfile 已默认改用 `docker.m.daocloud.io/library/...`;或在 Docker Engine 中把 DaoCloud 放在 `registry-mirrors` 第一条。 --- ## 2. 交付方打包(我方,含源码仓库) 在**己方**开发机或 CI(有完整 Git 仓库)执行: ```bash ./scripts/package-docker-deploy.sh # 默认日期版本 ./scripts/package-docker-deploy.sh v1.0.0 # 指定版本号 ./scripts/package-docker-deploy.sh v1.1.0 # 含 mobile-oa-h5(/oa-h5/)+ 微信开关 ``` `package-docker-deploy.sh` 固定构建 **`linux/amd64`** 镜像(适配甲方 Linux x86 云主机)。仅在对方确认为 ARM 云主机时,发版前改脚本中的 `DOCKER_PLATFORM` 为 `linux/arm64`。 脚本会: 1. 本地 `docker build` 生成 `zkxw-backend:<版本>`、`zkxw-web:<版本>`(**web 镜像内含 web-admin + `/oa-h5/`(mobile-oa-h5)**) 2. `docker save` 导出为 `images/zkxw-app-images.tar` 3. 打包 compose、`.env.example`、`docs/sql/zkxw.sql`(**不含** `backend/`、`web-admin/`、`mobile-oa-h5/` 源码) 产物:`dist/zkxw-docker-deploy-<版本>.tar.gz` 仅重新构建镜像、不重新打交付包时: ```bash ./scripts/build-docker-images.sh v1.0.0 ``` 发版方在仓库内从源码本地调试构建: ```bash cd deploy/docker docker compose -f docker-compose.yml -f docker-compose.build.yml build docker compose up -d ``` **交付前自检:** ```bash tar -xzf dist/zkxw-docker-deploy-*.tar.gz -C /tmp cd /tmp/zkxw-docker-deploy-* docker load -i images/zkxw-app-images.tar cd deploy/docker && cp .env.example .env docker compose up -d curl -s http://127.0.0.1:8112/health ``` --- ## 3. 交付包目录说明(甲方收到的内容) ```text zkxw-docker-deploy-<版本>/ ├── images/ │ └── zkxw-app-images.tar # 预构建前后端镜像(无源码) ├── deploy/docker/ │ ├── docker-compose.yml │ ├── .env.example # 含 ZKXW_*_IMAGE 版本号 │ └── mysql/init/ ├── docs/sql/zkxw.sql # 首次部署自动建库用 ├── 部署说明.md ├── 部署指导手册.html # 客户安装手册(浏览器打开,推荐交付) └── VERSION.txt ``` **不包含**:`backend/`、`web-admin/`、`mobile-oa-h5/`、Dockerfile、`.vue` / `.py` 业务源码。 数据库脚本 `zkxw.sql` 仅为表结构与基线数据,非应用源代码。 Nginx 反代配置已打入 `zkxw-web` 镜像(含管理端 `/` 与 OA H5 `/oa-h5/`),无需单独配置。 --- ## 3.1 从 v1.0.0 增量升级到 v1.1.0(小程序 OA H5 + 微信配置) 适用:已在运行 `zkxw-backend:v1.0.0` / `zkxw-web:v1.0.0`,数据卷保留,**不重装** MySQL/Redis/MinIO。 典型目录(以现网调查为准): ```text /opt/zkxw/zkxw-docker-deploy-v1.0.0/deploy/docker ``` ### 发版方 ```bash ./scripts/package-docker-deploy.sh v1.1.0 # 产物:dist/zkxw-docker-deploy-v1.1.0.tar.gz ``` ### 内网机(192.168.200.24)运维 ```bash # 1) 用户自行上传 tar 到内网机后解压(路径自定,示例) cd /opt/zkxw tar -xzf zkxw-docker-deploy-v1.1.0.tar.gz docker load -i zkxw-docker-deploy-v1.1.0/images/zkxw-app-images.tar # 2) 改现网 .env cd /opt/zkxw/zkxw-docker-deploy-v1.0.0/deploy/docker # 只改镜像 tag(示例): # ZKXW_BACKEND_IMAGE=zkxw-backend:v1.1.0 # ZKXW_WEB_IMAGE=zkxw-web:v1.1.0 # # 微信/小程序:新交付包 .env.example 打包时会从发版机注入; # - 推荐:保留现网 MYSQL/SECRET/MINIO 密码,把包内 WX_MP_* / WXPAY_* 段合并进来 # - 切勿用「仅含 change-me 库口令」的全新 .env 整文件覆盖现网,否则连不上原数据库 # 3) 只滚动应用(数据卷不动) docker compose up -d backend web # 4) 本机验收 curl -sI http://127.0.0.1:8112/ | head -5 curl -sI http://127.0.0.1:8112/oa-h5/ | head -5 curl -s http://127.0.0.1:8112/health ``` ### 公网网关 39.102.214.125(xwyd.zkxw.cn → 112.30.112.8:60001) 现网 `xwyd.zkxw.cn` 对 `/` 做整站 `proxy_pass` 到内网 `60001`,**一般无需改 Nginx**: - `https://xwyd.zkxw.cn/` → 管理端 - `https://xwyd.zkxw.cn/oa-h5/` → OA H5(新) - `https://xwyd.zkxw.cn/api/`、`/minio/zkxw/` → 随同反代 内网 `112.30.112.8:60001 → 192.168.200.24:8112` 映射**保持不动**。升级后公网验收: ```bash curl -skI https://xwyd.zkxw.cn/oa-h5/ | head -5 ``` 若 `/oa-h5/` 404 而本机 `8112` 正常,再查网关是否对路径做了白名单(当前配置为整站反代则无需改)。 --- ## 4. 甲方服务器上线步骤 ```bash # 1) 安装 Docker + Compose(若未安装) docker --version && docker compose version # 2) 上传并解压交付包 mkdir -p /opt/zkxw && cd /opt/zkxw tar -xzf zkxw-docker-deploy-*.tar.gz cd zkxw-docker-deploy-* # 3) 导入应用镜像(前后端,无源码) docker load -i images/zkxw-app-images.tar docker images | grep zkxw- # 4) 配置并启动 cd deploy/docker cp .env.example .env vi .env # 改密码;确认 ZKXW_BACKEND_IMAGE / ZKXW_WEB_IMAGE 与 load 的 tag 一致 # 5) 启动(会拉取 mysql:5.7.36、redis、minio 等基础镜像,无需 --build) docker compose up -d # 6) 查看进度(首次 MySQL 导入约 1~3 分钟) docker compose ps docker compose logs -f mysql docker compose logs -f backend # 7) 验收 curl -s http://127.0.0.1:8112/health # 浏览器打开 http://<服务器IP>:8112/ 账号 admin / 111111 ``` 防火墙 / 安全组放行 **TCP 8112**。 | 地址 | 说明 | |------|------| | `http://<服务器IP>:8112/` | Web 管理端 | | `http://<服务器IP>:8112/health` | 健康检查 | | `http://<服务器IP>:8112/docs` | Swagger | 默认账号:`admin` / `111111`(首次登录后请修改)。 默认 `COMPOSE_PROFILES=full`:自带 MySQL、Redis、MinIO,首次启动自动导入 `docs/sql/zkxw.sql`。 **Mac(M 芯片)本地试跑**:`mysql:5.7.36` 无 arm64 包,compose 已统一 `platform: linux/amd64`(模拟运行,会慢一些)。**不必**为 Mac 重新打 `zkxw-app-images.tar`。 --- ## 5. 服务架构 ```text 浏览器 :8112 └── web(Nginx + 前端静态) ├── /api/* → backend:8111(FastAPI) └── /minio/zkxw/* → minio:9000(附件,仅容器内网络) backend → mysql:3306(业务库 zkxw) → redis:6379(会话) → minio:9000(对象存储) minio-init(首次/每次 up 时执行一次):自动创建 `MINIO_BUCKET`(默认 zkxw),并设置 **匿名可读(download)**,供 Nginx `/minio/zkxw/` 反代访问附件;上传仍由后端 API 鉴权后写入。 ``` **重要**:MySQL、Redis、MinIO **不映射宿主机端口**,只在 Docker 内部网络通信,**不会**与甲方已有 3306/6379/9000 服务冲突。对外仅开放 **8112**。 **API 传输**:Docker 交付默认**关闭**前后端 API 加解密(`API_ENCRYPT_ENABLED=false` / `VITE_API_ENCRYPT_ENABLED=false`),请求与响应为明文 JSON。若需启用,须同时改 `.env` 与 `web-admin/.env.docker` 后重建 `backend`、`web` 镜像。 --- ## 6. 两种部署 Profile 通过 `.env` 中 `COMPOSE_PROFILES` 切换。 ### 6.1 `full`(默认,全栈) ```env COMPOSE_PROFILES=full ``` 启动:MySQL + Redis + MinIO + 后端 + 前端。 `.env` 中使用 Docker 服务名: ```env DATABASE_URL=mysql+pymysql://root:<密码>@mysql:3306/zkxw REDIS_HOST=redis MINIO_ENDPOINT=minio:9000 MINIO_BASE_URL=/minio/zkxw ``` ### 6.2 `app`(仅应用,连接甲方已有中间件) 甲方已有 MySQL、Redis、MinIO 时使用: ```env COMPOSE_PROFILES=app DATABASE_URL=mysql+pymysql://user:pass@10.0.0.10:3306/zkxw REDIS_HOST=10.0.0.11 REDIS_PORT=6379 MINIO_ENDPOINT=10.0.0.12:9000 MINIO_ACCESS_KEY=... MINIO_SECRET_KEY=... MINIO_BUCKET=zkxw MINIO_BASE_URL=http://10.0.0.12:9000/zkxw ``` ```bash docker compose up -d --build ``` **注意**:若 MinIO 不在 Docker 网络内,需同步修改 `web-admin/.env.docker` 中的 `VITE_MINIO_BASE_URL` 并重新构建 web 镜像;或保留 MinIO 容器见下节。 ### 6.3 `app,storage`(外部库 + 自带 MinIO) 已有 MySQL/Redis,但希望 MinIO 仍由本 compose 提供: ```env COMPOSE_PROFILES=app,storage ``` `.env` 中 `DATABASE_URL`、`REDIS_HOST` 指向甲方地址;`MINIO_ENDPOINT` 仍用 `minio:9000`。 --- ## 7. 常用运维命令 ```bash cd deploy/docker # 停止 docker compose down # 重启 docker compose restart # 仅重建后端 docker compose up -d --build backend # 仅重建前端 docker compose up -d --build web # 查看日志 docker compose logs -f backend docker compose logs -f web # 进入后端容器 docker compose exec backend bash ``` --- ## 8. 数据持久化与备份 Docker 卷(`docker volume ls | grep zkxw`): | 卷名 | 内容 | |------|------| | `zkxw_mysql_data` | MySQL 数据 | | `zkxw_redis_data` | Redis 持久化 | | `zkxw_minio_data` | 附件对象 | | `zkxw_backend_uploads` | 本地存储模式下的上传目录 | MySQL 备份示例: ```bash docker compose exec mysql mysqldump -uroot -p zkxw > zkxw_backup.sql ``` **警告**:`docker compose down -v` 会删除所有卷,导致数据丢失。 --- ## 9. 升级发版 ```bash cd /opt/zkxw/zkxw-docker-deploy-<新版本> # 1) 备份数据库与 MinIO 卷 # 2) 导入新应用镜像 docker load -i images/zkxw-app-images.tar # 3) 更新 deploy/docker/.env 中 ZKXW_BACKEND_IMAGE、ZKXW_WEB_IMAGE cd deploy/docker docker compose up -d # 4) 验证 curl -s http://127.0.0.1:8112/health ``` 若仅有数据库结构变更,由交付方提供增量 SQL,**不要**删除已有 `mysql_data` 卷。 --- ## 10. 环境变量要点 | 变量 | 说明 | |------|------| | `HTTP_PORT` | 对外端口,默认 8112 | | `MYSQL_ROOT_PASSWORD` | MySQL root 密码(full profile) | | `DATABASE_URL` | 须与 MySQL 账号密码一致 | | `SECRET_KEY` | JWT 密钥,生产必须改为长随机串 | | `API_ENCRYPT_ENABLED` | Docker 交付默认 `false`(前后端 API 不加密) | | `MINIO_*` | 对象存储;bucket 由 minio-init 自动创建并设为匿名下载(供 `/minio/zkxw/` 访问) | 修改 `.env` 后: ```bash docker compose up -d docker compose restart backend ``` 修改 `web-admin/.env.docker` 后须重建 web: ```bash docker compose up -d --build web ``` --- ## 11. 常见问题 ### 8112 无法访问 - 检查防火墙 / 安全组是否放行 8112 - `docker compose ps` 确认 `web` 为 running - `docker compose logs web` ### `/api` 返回 502 - 后端未就绪:`docker compose logs backend` - MySQL 初始化未完成(首次启动约 1~3 分钟):`docker compose logs mysql` ### 数据库初始化失败需重来 仅**首次部署失败**且可接受清空数据时: ```bash docker compose down -v docker compose up -d ``` ### 附件无法访问 - 确认 `STORAGE_TYPE=minio` - `docker compose logs minio-init`(应看到 bucket 创建与 `anonymous set download` 成功) - 浏览器 Network 中附件 URL 应为 `/minio/zkxw/...` - 若 bucket 在加入匿名策略前已存在,可手动执行:`docker compose run --rm minio-init` 或删除 `minio_data` 卷后重新 `up`(会清空附件) ### 拉取镜像慢或失败 见上文 **§1.1 Docker 镜像加速**,配置 `registry-mirrors` 后重试 `docker compose up -d`。 ### 发版方打包时 pip / pnpm 很慢或超时 - 已默认 **阿里云 PyPI** + **npmmirror**,并启用 BuildKit 缓存。 - 默认 **npmmirror**(`https://registry.npmmirror.com`)。**国内 Intel / Linux 机器不要设 `NPM_REGISTRY=https://registry.npmjs.org`**,该地址在国内常 ETIMEDOUT。 - 若 npmmirror 不稳定,可换其它国内源: ```bash NPM_REGISTRY=https://mirrors.cloud.tencent.com/npm/ ./scripts/package-docker-deploy.sh v1.0.0 # 或 NPM_REGISTRY=https://repo.huaweicloud.com/repository/npm/ ./scripts/package-docker-deploy.sh v1.0.0 ``` - 安装 pnpm 失败时 Dockerfile 会自动回退为 tarball 直装;`pnpm install` 出现 ETIMEDOUT 时会重试,日志可能长时间不动,**不要误按 Ctrl+C**。 - **在 Mac(M 芯片)上交叉构建 `linux/amd64` 很慢**(后端 pip 常见 15~40 分钟);**Intel Linux 同架构构建**通常 5~15 分钟,推荐在发版机上直接执行 `./scripts/package-docker-deploy.sh v1.0.0`(无需设 `NPM_REGISTRY`)。 默认已使用阿里云 PyPI(`mirrors.aliyun.com`)。若需改用清华源: ```bash PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple \ PIP_TRUSTED_HOST=pypi.tuna.tsinghua.edu.cn \ ./scripts/package-docker-deploy.sh v1.0.0 ``` --- ## 12. 与手工部署的关系 本方案与 `deploy/test/README.md` 中「Nginx 10001 + 同域 `/api` 反代后端 10002」拓扑一致。应用以**预构建镜像**交付,甲方执行 `docker load` + `docker compose up -d` 即可,无需源码与 `pnpm`/`pip` 构建环境。