# Docker 部署指南 ## 项目简介 仓库物料管理系统 (WMMS) - 前后端分离架构 - **后端**: Go + Gin + MySQL (端口 8082) - **前端**: Vue 3 + Vite + Nginx (端口 80) - **数据库**: MySQL 8.0 (端口 3306) ## 快速启动 (Windows) ### 前置条件 1. 安装 [Docker Desktop](https://www.docker.com/products/docker-desktop/) (Windows 10/11) 2. 启动 Docker Desktop ### 启动服务 ```bash # 进入项目目录 cd c:\1111\12.project\VSCode\warehouse-mms # 启动所有服务 docker-compose up -d # 查看服务状态 docker-compose ps ``` ### 访问应用 - 前端地址: http://localhost - 后端API: http://localhost:8082/api (绑定在 `127.0.0.1`,仅限本机) - 健康检查: http://localhost:8082/api/health ### 用手机 / 局域网其他设备访问 手机连上**与电脑同一个 WiFi**,浏览器打开 `http://<电脑的局域网IP>`,用下节账号登录即可,**不需要带端口号**(80 是 HTTP 的默认端口,浏览器会自动使用)。 先查看电脑的局域网 IP —— 取 `WLAN` 那一行的地址,忽略 `vEthernet (WSL)`、`VMware Network Adapter` 这些虚拟网卡: ```bash ipconfig ``` 例如地址是 `192.168.31.76`,手机就访问 `http://192.168.31.76`。 **为什么不需要改配置**:前端请求走相对路径 `/api`,手机访问时会自动打到 `http://<电脑IP>/api`,再由 Nginx 反代给后端容器。前后端都没有硬编码 `localhost`,所以换任何 IP 访问都能正常工作。 #### 端口绑定策略 | 服务 | 绑定地址 | 局域网可访问 | 原因 | |------|----------|--------------|------| | frontend | `0.0.0.0:80` | ✅ 是 | 手机、其他设备要打开网页 | | backend | `127.0.0.1:8082` | ❌ 否 | 前端经 Nginx 走**容器内部网络**反代(`proxy_pass http://backend:8082`),不经过宿主机端口 | | db | `127.0.0.1:3307` | ❌ 否 | 数据库不应暴露;本机仍可用客户端连 3307 调试 | 后端和数据库绑定在 `127.0.0.1` 是**有意的安全设置**,只允许本机访问。若你临时需要让别的机器直连后端 API 调试,把 `docker-compose.yml` 里对应那行改回 `"8082:8082"`,再执行 `docker compose up -d`(改完记得改回去)。 #### 手机打不开时怎么查 1. **确认同一个 WiFi**:手机和电脑必须是同一个 SSID。 2. **WiFi 的客户端隔离(AP 隔离)**:单位、公共场所的网络常开启此功能,导致设备之间无法互访。这属于网络策略,与本项目无关 —— 用手机开热点让电脑连上试一次即可确认。 3. **Windows 防火墙**:需放行 80 端口入站。Docker Desktop 安装时会按其网络类别自动添加放行规则,若仍不通,用管理员 PowerShell 临时加一条: ```powershell New-NetFirewallRule -DisplayName "WMMS 80" -Direction Inbound -LocalPort 80 -Protocol TCP -Action Allow # 测试完删除:Remove-NetFirewallRule -DisplayName "WMMS 80" ``` 4. **IP 会变**:`192.168.x.x` 由 DHCP 分配,路由器重启后可能变化。想长期使用,建议在路由器上给这台电脑做静态 IP 绑定。 > ⚠️ 数据库使用默认密码 `wmms1234`,后端 API 也没有额外的访问控制,因此**不要把 8082 / 3307 暴露到公网**。 ### 默认用户 | 用户名 | 密码 | 角色 | |--------|------|------| | admin | admin123 | 管理员 | | user | user123 | 普通用户 | ## 常用命令 ```bash # 查看日志 docker-compose logs -f # 查看后端日志 docker-compose logs -f backend # 停止服务 docker-compose down # 重新构建并启动 docker-compose up -d --build # 删除所有数据(谨慎操作) docker-compose down -v ``` ## 数据持久化 - **MySQL数据**: `mysql_data` Docker volume - **上传文件**: `uploads_data` Docker volume ### ⚠️ 数据卷复用会导致表结构落后于代码 MySQL 官方镜像**只在数据目录为空时**才执行 `/docker-entrypoint-initdb.d/` 下的脚本。也就是说 `scripts/init.sql` **只在 `mysql_data` 卷第一次创建时执行一次**;只要卷还在,后续 `docker compose up -d` 一律直接复用旧数据,`init.sql` 完全不执行。 `docker compose down` **不带 `-v` 时卷会保留**,所以改过 schema 之后重新部署,新代码会跑在旧表结构上。典型症状是**容器全部 healthy、日志干净,但部分接口返回 500**: ``` Error 1054 (42S22): Unknown column 'inbound_no' in 'field list' ``` **部署前先确认现有表结构**: ```bash docker compose exec db mysql -uroot -pwmms1234 -e "SHOW COLUMNS FROM inbound_orders; SHOW COLUMNS FROM outbound_orders; SHOW COLUMNS FROM material_categories;" wmms ``` 将实际字段与当前 `scripts/init.sql` 对比。数据卷的创建时间只能作为排查线索,不能证明表结构是否一致。 **方式一:清空重建(推荐,最简单可靠)** ```bash docker compose down -v && docker compose up -d --build ``` `-v` 会删除 `mysql_data` 和 `uploads_data` 两个卷,**库中数据全部丢失**。执行前务必确认没有需要保留的业务数据,必要时先备份: ```bash docker compose exec db mysqldump -uroot -pwmms1234 --default-character-set=utf8mb4 wmms > backup.sql ``` **方式二:保留数据并更新结构** 需要保留业务数据时,先备份数据库,再根据实际表结构与 `scripts/init.sql` 的差异编写并审核增量 SQL,在备份副本上验证后执行。 当前 `scripts/init.sql` 用于空库首次初始化,已包含出入库单号、操作人、备注、分类说明、6 个大类和 28 个子类,以及对应编码规则。库存预警阈值为 0 是有效配置,新库无需清理历史规则。不要将完整初始化脚本直接用于已有业务数据的数据库。 ## 环境变量 | 变量 | 默认值 | 说明 | |------|--------|------| | DB_DSN | root:wmms1234@tcp(db:3306)/wmms?charset=utf8mb4&parseTime=true | 数据库连接字符串 | | GIN_MODE | release | Gin 运行模式 | ## 手动构建 ```bash # 构建后端 docker build -t wmms-backend . # 构建前端 cd frontend docker build -t wmms-frontend . # 启动 docker-compose up -d ``` ## 故障排查 ### 端口冲突 如果 80 或 3306 端口被占用: ```bash # 查看端口占用 netstat -ano | findstr ":80" netstat -ano | findstr ":3306" # 修改 docker-compose.yml 中的端口映射 ``` ### 数据库连接失败 ```bash # 检查数据库是否就绪 docker-compose logs db # 等待数据库启动完成(约10秒) ``` ### 接口返回 500:Unknown column 'xxx' **症状**:容器状态全部 healthy,`docker compose logs` 也看不到异常,但某些接口返回 500,例如: ``` Error 1054 (42S22): Unknown column 'description' in 'field list' ``` **原因**:`mysql_data` 卷是旧的,`init.sql` 没有执行,表结构落后于当前代码。详见上文《数据持久化 → ⚠️ 数据卷复用会导致表结构落后于代码》。 **确认**: ```bash docker compose exec db mysql -uroot -pwmms1234 -e "SHOW COLUMNS FROM material_categories;" wmms ``` 检查报错涉及的表是否缺少字段,并与当前 `scripts/init.sql` 对比。 **解决**:确认数据库和上传文件均无需保留后,可执行 `docker compose down -v && docker compose up -d --build` 重建;需要保留数据时,先备份,再按实际结构差异准备并验证增量 SQL。 ### 其他排查技巧 **哪些表结构会不一致?** 直接在容器里对比: ```bash # 看当前库到底建了哪些表和列 docker compose exec db mysql -uroot -pwmms1234 -e "SHOW TABLES;" wmms docker compose exec db mysql -uroot -pwmms1234 -e "SHOW COLUMNS FROM inbound_orders;" wmms ``` ### 查看容器内部 ```bash # 进入后端容器 docker exec -it wmms-backend sh # 进入数据库容器 docker exec -it wmms-db mysql -u root -p ```