Docker 部署
Docker 部署
本篇讲解用 docker-compose 一键拉起 MySQL + 后端 + 前端三服务,并指出仓库自带 docker-compose.yml 中的端口与 SQL 初始化注意事项。
一、仓库自带的 docker-compose
仓库根目录的 docker-compose.yml 定义了三个服务:
| 服务 | 镜像 / 构建 | 端口映射 | 说明 |
|---|---|---|---|
mysql | mysql:8.0 | 3306:3306 | 库 lowcode,root 密码 root,挂载 docs/SQL_INIT.sql 初始化 |
backend | build: ./backend | 8080:8080 | 多阶段构建,JDK 17 运行 |
frontend | build: ./frontend | 80:80 | 多阶段构建,Nginx 托管 dist/ 并反代 /api |
# docker-compose.yml(节选)
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: lowcode
volumes:
- mysql-data:/var/lib/mysql
- ./docs/SQL_INIT.sql:/docker-entrypoint-initdb.d/init.sql
backend:
build: ./backend
ports:
- "8080:8080"
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/lowcode?...
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: root
frontend:
build: ./frontend
ports:
- "80:80"二、⚠️ 自带配置的两个必改问题
直接 docker-compose up 仓库自带配置会踩两个坑,部署前必须修复。
问题 1:后端端口不一致(服务无法访问)
端口不一致
- 后端应用实际监听 52856(
application.yml中server.port: 52856) - 但
backend/Dockerfile中EXPOSE 8080 docker-compose.yml映射8080:8080frontend/nginx.conf反代到http://backend:8080/api
三者按 8080 约定,应用却跑在 52856,结果:容器内后端监听 52856,而 Nginx 反代到 8080,请求全部 502。
修复方案 A(推荐,改动最小):给 backend 服务加环境变量 SERVER_PORT=8080,让应用在容器内监听 8080,与 Dockerfile / Nginx 对齐:
backend:
build: ./backend
ports:
- "8080:8080"
environment:
SERVER_PORT: 8080 # 新增:覆盖 application.yml 的 52856
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/lowcode?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: root
TZ: Asia/Shanghai
depends_on:
- mysqlSpring Boot 会读取 SERVER_PORT 环境变量覆盖 server.port,容器内即监听 8080。
修复方案 B:把 Dockerfile / compose / nginx 全部改成 52856,与 application.yml 保持一致:
# backend/Dockerfile
EXPOSE 52856# docker-compose.yml
backend:
ports:
- "52856:52856"# frontend/nginx.conf
location /api {
proxy_pass http://backend:52856/api;
}问题 2:MySQL 仅初始化 13 张表
SQL_INIT.sql 不够
自带配置只挂载了 docs/SQL_INIT.sql(13 张基础表),缺少 BPM、ERP、HR、消息、报表等 40+ 张表。后端启动后访问这些模块会报「表不存在」。
修复:把完整 SQL 都挂载到 /docker-entrypoint-initdb.d/,MySQL 容器首次启动时按文件名顺序自动执行:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: lowcode
TZ: Asia/Shanghai
volumes:
- mysql-data:/var/lib/mysql
- ./docs/SQL_INIT.sql:/docker-entrypoint-initdb.d/01-init.sql
- ./docs/SQL_EXTENSION.sql:/docker-entrypoint-initdb.d/02-extension.sql
- ./sql/mysql/bpm.sql:/docker-entrypoint-initdb.d/03-bpm.sql
- ./sql/mysql/hr_employee.sql:/docker-entrypoint-initdb.d/04-hr.sql
- ./backend/src/main/resources/data-mysql.sql:/docker-entrypoint-initdb.d/05-fix.sql
- ./sql/mysql/migration-column-meta-options.sql:/docker-entrypoint-initdb.d/06-migration.sql
command:
--character-set-server=utf8mb4
--collation-server=utf8mb4_unicode_ci
--default-authentication-plugin=mysql_native_password文件名前缀决定执行顺序
MySQL 官方镜像按 /docker-entrypoint-initdb.d/ 下文件名字母序执行 SQL。用 01-、02- 前缀确保 SQL_INIT.sql 先于 SQL_EXTENSION.sql 执行,避免外键 / 依赖问题。
仅首次启动生效
docker-entrypoint-initdb.d 中的脚本只在 MySQL 数据目录为空(首次启动)时执行。若 mysql-data 卷已有数据,修改挂载不会重新导入。需先 docker-compose down -v 删除卷再重启。
三、修正后的完整 docker-compose.yml
version: '3.8'
services:
mysql:
image: mysql:8.0
container_name: lowcode-mysql
restart: always
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: lowcode
TZ: Asia/Shanghai
volumes:
- mysql-data:/var/lib/mysql
- ./docs/SQL_INIT.sql:/docker-entrypoint-initdb.d/01-init.sql
- ./docs/SQL_EXTENSION.sql:/docker-entrypoint-initdb.d/02-extension.sql
- ./sql/mysql/bpm.sql:/docker-entrypoint-initdb.d/03-bpm.sql
- ./sql/mysql/hr_employee.sql:/docker-entrypoint-initdb.d/04-hr.sql
- ./backend/src/main/resources/data-mysql.sql:/docker-entrypoint-initdb.d/05-fix.sql
- ./sql/mysql/migration-column-meta-options.sql:/docker-entrypoint-initdb.d/06-migration.sql
command:
--character-set-server=utf8mb4
--collation-server=utf8mb4_unicode_ci
--default-authentication-plugin=mysql_native_password
networks:
- lowcode-network
backend:
build: ./backend
container_name: lowcode-backend
restart: always
ports:
- "8080:8080"
depends_on:
- mysql
environment:
SERVER_PORT: 8080
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/lowcode?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: root
REDIS_HOST: 124.71.29.50 # 默认远程 Redis,生产请换成自有 Redis
REDIS_PORT: 6379
TZ: Asia/Shanghai
networks:
- lowcode-network
frontend:
build: ./frontend
container_name: lowcode-frontend
restart: always
ports:
- "80:80"
depends_on:
- backend
networks:
- lowcode-network
volumes:
mysql-data:
networks:
lowcode-network:
driver: bridge四、Dockerfile 说明
backend/Dockerfile(多阶段构建)
# 阶段1:Maven 构建
FROM maven:3.9-eclipse-temurin-17 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn clean package -DskipTests
# 阶段2:JRE 运行
FROM eclipse-temurin:17-jre-jammy
WORKDIR /app
RUN apt-get update && apt-get install -y tzdata && rm -rf /var/lib/apt/lists/*
ENV TZ=Asia/Shanghai
COPY --from=builder /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "-Xms512m", "-Xmx2048m", "app.jar"]- 构建阶段用
maven:3.9-eclipse-temurin-17(JDK 17,规避 Lombok×JDK21 问题)。 - 运行阶段用
eclipse-temurin:17-jre-jammy,体积更小。 - JVM 参数
-Xms512m -Xmx2048m已内置。 EXPOSE 8080需与SERVER_PORT/ nginx 反代目标一致(见上文问题 1)。
frontend/Dockerfile(多阶段构建)
# 阶段1:Node 构建
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm config set registry https://registry.npmmirror.com
RUN npm install
COPY . .
RUN npm run build
# 阶段2:Nginx 运行
FROM nginx:alpine
WORKDIR /usr/share/nginx/html
COPY --from=builder /app/dist .
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]- 构建阶段用
node:20-alpine,npm 镜像源切到 npmmirror 加速。 - 运行阶段用
nginx:alpine,把dist/拷到 Nginx 默认目录。 nginx.conf与 Dockerfile 同目录,反代/api到http://backend:8080/api。
五、启动与验证
# 构建并后台启动
docker-compose up -d --build
# 查看日志
docker-compose logs -f backend
docker-compose logs -f frontend
# 查看服务状态
docker-compose ps验证:
- 访问
http://服务器IP,应看到登录页。 - 用
admin / admin123登录(MySQL 首次启动由DataInitializer创建,见 )。 - 检查后端日志无「表不存在」错误。
访问后端 Swagger / 直连
若 SERVER_PORT=8080 且映射 8080:8080,可直接访问 http://服务器IP:8080 调试后端。生产环境建议去掉 8080:8080 映射,仅由 Nginx 反代暴露 /api。
六、自定义 Dockerfile
如需自定义(如换基础镜像、加 APM 探针),可修改 backend/Dockerfile:
# 例:换用更小的发行版 + 阿里云镜像加速
FROM maven:3.9-eclipse-temurin-17 AS builder
WORKDIR /app
# 阿里云 Maven 镜像
RUN mkdir -p /root/.m2 && echo '<settings>...</settings>' > /root/.m2/settings.xml
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn clean package -DskipTests
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
ENV TZ=Asia/Shanghai
COPY --from=builder /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "-Xms512m", "-Xmx2048m", "app.jar"]构建时 Lombok
Maven 构建阶段务必用 JDK 17 基础镜像。若改用 JDK 21 镜像,mvn package 会因 Lombok TypeTag 失败,详见 。
七、常见容器问题
backend 容器一直重启 / 连不上 MySQL
后端启动比 MySQL 快,首次启动时 MySQL 还在初始化。depends_on 只保证容器启动顺序,不保证 MySQL 就绪。可:
- 加重启策略
restart: always(已配),后端会自动重试直到 MySQL 就绪。 - 或在 backend 启动脚本中加
wait-for-it.sh mysql:3306等待。
frontend 容器 502 Bad Gateway
检查 nginx.conf 中 proxy_pass 的端口与 backend 实际监听端口是否一致(见问题 1)。进入 frontend 容器 curl http://backend:8080/api/system/health 测试网络连通性。
MySQL 容器没有自动建表
确认 mysql-data 卷为空(首次启动)。若已存在旧数据,docker-entrypoint-initdb.d 脚本不会执行。执行 docker-compose down -v 删除卷后重新 up。
下一步:数据库细节见 ;环境问题见 。
