好的,没问题!我们可以使用 Docker Compose 来一键部署你的 Spring Boot 后端、React 前端和 MySQL 数据库。下面是详细的步骤和项目结构。
这个方案假设:
- 你的 Spring Boot 项目可以打包成一个可执行的 JAR 文件。
- 你的 React 项目可以通过
npm run build
(或类似命令) 构建成静态文件。
🚀 项目结构
首先,我们来规划一下整个项目的目录结构。建议将你的后端项目、前端项目和 Docker 相关配置文件放在一个统一的父目录下,例如 my-fullstack-app
:
my-fullstack-app/
├── backend/ # 你的 Spring Boot 后端项目
│ ├── src/
│ │ └── main/
│ │ └── resources/
│ │ └── db.sql # 你的数据库初始化脚本
│ ├── pom.xml
│ └── Dockerfile # 后端项目的 Dockerfile
│
├── frontend/ # 你的 React 前端项目
│ ├── public/
│ ├── src/
│ ├── package.json
│ ├── vite.config.js # (或其他 Vite 配置文件)
│ └── Dockerfile # 前端项目的 Dockerfile (用于构建和准备 Nginx)
│
├── mysql/
│ └── init.sql # (可选,另一种初始化方式,这里我们会用后端的方式)
│
└── docker-compose.yml # Docker Compose 配置文件
说明:
backend/
和frontend/
目录分别存放你已有的 GitHub 项目代码。backend/src/main/resources/db.sql
是你提供的数据库初始化脚本。- 我们会在
backend/
和frontend/
目录下分别创建一个Dockerfile
。 docker-compose.yml
是核心的编排文件。
🐳 Dockerfile 配置
接下来,我们为前端和后端应用创建 Dockerfile。
1. 后端 Spring Boot 应用 ( backend/Dockerfile
)
这个 Dockerfile 会将你的 Spring Boot 应用打包成一个可执行的 JAR 文件,并运行它。
Dockerfile
# 使用一个包含 JDK 的基础镜像
FROM openjdk:17-jdk-slim as builder
# 设置工作目录
WORKDIR /app
# 复制 Maven Wrapper 相关文件 (如果你的项目使用 Maven Wrapper)
COPY .mvn/ .mvn
COPY mvnw .
COPY pom.xml .
# 下载依赖 (利用 Docker 缓存机制)
RUN ./mvnw dependency:go-offline -B
# 复制源代码
COPY src ./src
# 打包应用
RUN ./mvnw package -DskipTests
# ---- 第二阶段:运行阶段 ----
# 使用一个更小的 JRE 镜像来运行应用
FROM openjdk:17-jre-slim
WORKDIR /app
# 从构建阶段复制 JAR 文件
COPY --from=builder /app/target/*.jar app.jar
# 暴露 Spring Boot 应用的端口 (默认为 8080)
EXPOSE 8080
# 运行应用
ENTRYPOINT ["java", "-jar", "app.jar"]
注意:
- 请确保你的 Spring Boot 项目根目录下有
mvnw
(Maven Wrapper)。如果没有,你需要先在你的项目中设置 Maven Wrapper,或者修改 Dockerfile 以使用全局安装的 Maven。 openjdk:17-jdk-slim
和openjdk:17-jre-slim
是示例,你可以根据你的项目选择合适的 Java 版本。-DskipTests
在构建 Docker 镜像时跳过测试,可以加快构建速度。
2. 前端 React 应用 ( frontend/Dockerfile
)
这个 Dockerfile 会分两个阶段:
- 构建阶段: 使用 Node.js 环境构建你的 React 应用,生成静态文件。
- 运行阶段: 使用 Nginx 镜像来托管这些静态文件。
Dockerfile
# ---- 构建阶段 ----
FROM node:18-alpine as builder
# 设置工作目录
WORKDIR /app
# 复制 package.json 和 package-lock.json (或 yarn.lock)
COPY package*.json ./
# 如果使用 yarn
# COPY yarn.lock ./
# 安装依赖
RUN npm install
# 如果使用 yarn
# RUN yarn install
# 复制所有项目文件
COPY . .
# 构建应用
RUN npm run build
# 如果使用 yarn
# RUN yarn build
# ---- 运行阶段 ----
FROM nginx:stable-alpine
# 复制 Nginx 配置文件
COPY nginx.conf /etc/nginx/conf.d/default.conf
# 从构建阶段复制构建好的静态文件到 Nginx 的 www 目录
COPY --from=builder /app/dist /usr/share/nginx/html
# 注意: /app/dist 路径可能需要根据你的 Vite build outputDir 配置进行调整
# 暴露 Nginx 端口 (默认为 80)
EXPOSE 80
# 启动 Nginx
CMD ["nginx", "-g", "daemon off;"]
创建 Nginx 配置文件 ( frontend/nginx.conf
):
在你的 frontend
目录下创建一个名为 nginx.conf
的文件,用于配置 Nginx。
Nginx
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
# 处理 React Router 的路由
location / {
try_files $uri $uri/ /index.html;
}
# 可以添加其他 Nginx 配置,例如反向代理到后端 API
# location /api/ {
# proxy_pass http://backend:8080/; # "backend" 是 docker-compose.yml 中定义的服务名
# 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;
# }
}
注意:
node:18-alpine
是一个示例 Node.js 版本,请选择适合你项目的版本。npm run build
是 Vite 项目通常的构建命令,如果你的命令不同,请相应修改。frontend/dist
是 Vite 默认的构建输出目录。如果你的vite.config.js
中build.outDir
配置不同,请修改 Dockerfile 中的COPY --from=builder /app/dist ...
路径。nginx.conf
中的try_files $uri $uri/ /index.html;
对于单页应用(SPA)很重要,它确保了所有未匹配到静态文件的请求都会 fallback 到index.html
,让 React Router 能够处理路由。nginx.conf
中注释掉的location /api/
部分是一个示例,如果你希望通过 Nginx 代理后端的 API 请求 (例如,避免 CORS 问题),可以取消注释并根据需要修改。
🐳 Docker Compose 配置 ( docker-compose.yml
)
这是将所有服务(后端、前端、数据库)串联起来的核心文件。
YAML
version: '3.8'
services:
# 后端 Spring Boot 应用
backend:
build:
context: ./backend # Dockerfile 所在的目录
dockerfile: Dockerfile
container_name: my-springboot-app
ports:
- "8080:8080" # 将主机的 8080 端口映射到容器的 8080 端口
environment:
# Spring Boot 连接 MySQL 的环境变量
- SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/mydatabase?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
- SPRING_DATASOURCE_USERNAME=myuser
- SPRING_DATASOURCE_PASSWORD=mypassword
- SPRING_JPA_HIBERNATE_DDL_AUTO=update # 或者 validate, none (如果完全依赖 db.sql)
# 如果你的 db.sql 包含了创建数据库的语句,并且希望 Spring Boot 等待数据库初始化完成
# 可以考虑使用 depends_on 的 condition,或者在应用启动脚本中加入等待逻辑
depends_on:
db:
condition: service_healthy # 等待 MySQL 服务健康后再启动后端
networks:
- my-app-network
# 前端 React 应用 (Nginx)
frontend:
build:
context: ./frontend # Dockerfile 所在的目录
dockerfile: Dockerfile
container_name: my-react-app
ports:
- "80:80" # 将主机的 80 端口映射到容器的 80 端口 (Nginx)
depends_on:
- backend # 前端可能需要调用后端 API
networks:
- my-app-network
# MySQL 数据库
db:
image: mysql:8.0 # 使用官方 MySQL 8.0 镜像
container_name: my-mysql-db
restart: unless-stopped
environment:
MYSQL_DATABASE: mydatabase
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
MYSQL_ROOT_PASSWORD: rootpassword # MySQL root 用户密码
volumes:
- mysql_data:/var/lib/mysql # 数据持久化
- ./backend/src/main/resources/db.sql:/docker-entrypoint-initdb.d/init.sql # 挂载初始化脚本
ports:
- "3306:3306" # (可选) 将主机的 3306 端口映射到容器的 3306,方便外部工具连接调试
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost", "-u$$MYSQL_USER", "-p$$MYSQL_PASSWORD"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s # 给 MySQL 足够的时间启动
networks:
- my-app-network
# Docker 网络
networks:
my-app-network:
driver: bridge
# Docker 数据卷 (用于持久化 MySQL 数据)
volumes:
mysql_data:
关键点解释:
version: '3.8'
:指定 Docker Compose 文件格式版本。services
: 定义了三个服务:backend
、frontend
、db
。backend
服务:build
: 指向backend
目录,并使用该目录下的Dockerfile
进行构建。ports
: 将你本机的8080
端口映射到容器的8080
端口。environment
: 设置 Spring Boot 连接数据库所需的环境变量。SPRING_DATASOURCE_URL
: JDBC 连接字符串。注意db:3306
中的db
是下面定义的 MySQL 服务的名称,Docker Compose 会在内部网络中解析它。mydatabase
是你希望创建的数据库名。SPRING_DATASOURCE_USERNAME
和SPRING_DATASOURCE_PASSWORD
: 与 MySQL 服务中设置的用户名和密码一致。SPRING_JPA_HIBERNATE_DDL_AUTO
: 控制 Hibernate 如何处理数据库 schema。update
会在启动时根据实体类更新表结构,如果你的db.sql
已经完整定义了表结构,可以考虑设置为validate
(只验证) 或none
(不做任何操作)。
depends_on.db.condition: service_healthy
: 确保后端服务在 MySQL 服务完全启动并健康后才启动。这对于依赖数据库初始化的应用很重要。
frontend
服务:build
: 指向frontend
目录,并使用该目录下的Dockerfile
进行构建。ports
: 将你本机的80
端口映射到容器的80
端口(Nginx 默认端口)。depends_on: - backend
: 表示前端服务依赖后端服务。这不是强制的,但如果你在 Nginx 配置中设置了反向代理到后端,这样写更清晰。
db
服务:image: mysql:8.0
: 使用官方的 MySQL 8.0 镜像。restart: unless-stopped
: 除非手动停止,否则容器总会自动重启。environment
:MYSQL_DATABASE
: 当容器第一次启动时,会自动创建名为mydatabase
的数据库。MYSQL_USER
和MYSQL_PASSWORD
: 创建一个具有指定用户名和密码的用户,并授予其对mydatabase
的所有权限。MYSQL_ROOT_PASSWORD
: 设置 MySQL 的 root 用户密码。
volumes
:mysql_data:/var/lib/mysql
: 将 MySQL 的数据存储目录挂载到宿主机的 Docker volumemysql_data
上,这样即使容器被删除,数据也不会丢失。./backend/src/main/resources/db.sql:/docker-entrypoint-initdb.d/init.sql
: 这是关键的一步 。MySQL 镜像在第一次启动时,会自动执行/docker-entrypoint-initdb.d/
目录下的所有.sh
,.sql
,.sql.gz
文件。我们将你的db.sql
挂载到这个目录,MySQL 就会用它来初始化表结构和数据。
ports
: (可选) 将主机的3306
端口映射到容器的3306
,方便你使用本地的数据库客户端 (如 DBeaver, DataGrip, MySQL Workbench) 连接到 Docker 中的 MySQL 进行调试。生产环境中不建议直接暴露数据库端口到公网。healthcheck
: 定义了如何检查 MySQL 服务是否健康。这与backend
服务的depends_on.condition
配合使用。
networks
:my-app-network
: 创建一个自定义的桥接网络,让所有服务都在同一个网络中,可以通过服务名相互通信(例如,后端可以通过db:3306
连接 MySQL)。
volumes
:mysql_data
: 定义一个命名的 volume,用于持久化 MySQL 数据。
🛠️ 部署步骤
-
准备代码:
- 将你的后端 Spring Boot 项目代码放到
my-fullstack-app/backend/
目录下。 - 确保后端项目的
src/main/resources/
目录下有db.sql
文件。 - 将你的前端 React 项目代码放到
my-fullstack-app/frontend/
目录下。
- 将你的后端 Spring Boot 项目代码放到
-
创建 Dockerfile:
- 在
my-fullstack-app/backend/
目录下创建上面提供的Dockerfile
。 - 在
my-fullstack-app/frontend/
目录下创建上面提供的Dockerfile
和nginx.conf
文件。
- 在
-
创建 docker-compose.yml:
- 在
my-fullstack-app/
(项目根目录) 下创建上面提供的docker-compose.yml
文件。
- 在
-
修改配置 (重要):
- 后端
Dockerfile
: 检查 Java 版本,Maven Wrapper 是否正确。 - 前端
Dockerfile
: 检查 Node.js 版本,构建命令 (npm run build
),以及 Vite 的输出目录 (dist
)是否与你的项目一致。 docker-compose.yml
:- 数据库凭证 : 修改
db
服务和backend
服务中的MYSQL_DATABASE
,MYSQL_USER
,MYSQL_PASSWORD
,MYSQL_ROOT_PASSWORD
以及SPRING_DATASOURCE_USERNAME
,SPRING_DATASOURCE_PASSWORD
。请务必使用强密码! - 后端数据库连接 URL : 确保
SPRING_DATASOURCE_URL
中的数据库名 (mydatabase
) 与db
服务中MYSQL_DATABASE
的值一致。 - 端口映射 : 如果你本机的
80
或8080
端口已被占用,可以修改ports
部分的左侧端口号 (例如8081:80
)。
- 数据库凭证 : 修改
- 后端
-
构建并启动服务:
-
打开终端 (命令行工具)。
-
进入到
my-fullstack-app/
目录。 -
执行以下命令:
Bash
docker-compose up --build
--build
: 这个参数会强制 Docker Compose 在启动服务前重新构建镜像。第一次运行时是必需的,之后如果你的代码或 Dockerfile 没有改变,可以省略--build
直接使用docker-compose up
。- Docker Compose 会按照依赖顺序依次构建和启动
db
、backend
、frontend
服务。 - 你会看到很多日志输出,包括数据库的初始化、Spring Boot 应用的启动、Nginx 的启动等。
-
-
访问应用:
- 前端 : 打开浏览器,访问
http://localhost
(或者你在docker-compose.yml
中为frontend
服务映射的主机端口,例如http://localhost:8081
如果你改了端口)。 - 后端 API : 如果你直接暴露了后端端口,可以访问
http://localhost:8080
(或者你映射的后端端口)。通常前端会通过 Nginx 代理或者直接请求这个地址。 - 数据库 : 如果你映射了数据库的
3306
端口,可以使用数据库客户端连接到localhost:3306
,用户名为myuser
,密码为mypassword
(或你设置的值),数据库为mydatabase
。
- 前端 : 打开浏览器,访问
-
查看日志:
-
如果你想看特定服务的日志,可以打开新的终端窗口,执行: Bash
docker-compose logs -f backend # 查看后端日志 docker-compose logs -f frontend # 查看前端 (Nginx) 日志 docker-compose logs -f db # 查看数据库日志
-f
参数表示持续跟踪日志输出。
-
-
停止服务:
-
在运行
docker-compose up
的终端中,按Ctrl + C
。 -
或者,在项目目录下打开新的终端,执行: Bash
docker-compose down
这个命令会停止并移除容器。如果希望移除数据卷 (删除 MySQL 数据),可以执行
docker-compose down -v
。
-
💡 一些额外的提示
-
环境变量管理 : 对于敏感信息(如数据库密码),在生产环境中更好的做法是使用
.env
文件或 Docker Secrets 来管理,而不是直接写在docker-compose.yml
文件中。-
在
my-fullstack-app/
目录下创建一个.env
文件,例如: 代码段MYSQL_USER_ENV=myuser MYSQL_PASSWORD_ENV=mypassword MYSQL_DATABASE_ENV=mydatabase MYSQL_ROOT_PASSWORD_ENV=rootpassword
-
然后在
docker-compose.yml
中引用这些变量: YAML# ... environment: MYSQL_DATABASE: ${MYSQL_DATABASE_ENV} MYSQL_USER: ${MYSQL_USER_ENV} MYSQL_PASSWORD: ${MYSQL_PASSWORD_ENV} MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD_ENV} # ... environment: - SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/${MYSQL_DATABASE_ENV}?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC - SPRING_DATASOURCE_USERNAME=${MYSQL_USER_ENV} - SPRING_DATASOURCE_PASSWORD=${MYSQL_PASSWORD_ENV} # ...
-
-
Spring Boot
application.properties
/application.yml
: 确保你的 Spring Boot 应用的配置文件 (application.properties
或application.yml
) 使用了环境变量来配置数据库连接信息,例如:application.properties
:Properties
spring.datasource.url=${SPRING_DATASOURCE_URL} spring.datasource.username=${SPRING_DATASOURCE_USERNAME} spring.datasource.password=${SPRING_DATASOURCE_PASSWORD} spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.jpa.hibernate.ddl-auto=${SPRING_JPA_HIBERNATE_DDL_AUTO:update}
application.yml
:
YAMLspring: datasource: url: ${SPRING_DATASOURCE_URL} username: ${SPRING_DATASOURCE_USERNAME} password: ${SPRING_DATASOURCE_PASSWORD} driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: ddl-auto: ${SPRING_JPA_HIBERNATE_DDL_AUTO:update}
这样
docker-compose.yml
中设置的环境变量才能被 Spring Boot 应用正确读取。 -
开发与生产:
- 这里的配置是一个基础的部署方案。对于生产环境,你可能还需要考虑更复杂的 Nginx 配置 (HTTPS, 缓存, 限流等)、日志收集、监控、更安全的密钥管理等。
- 你也可以为开发环境和生产环境创建不同的
docker-compose.override.yml
文件来覆盖或扩展基础配置。
-
Maven Wrapper : 如果你的 Spring Boot 项目没有
mvnw
和.mvn
目录,请先在你的项目根目录下运行mvn -N io.takari:maven:wrapper
(或者根据你的 Maven 版本使用mvn wrapper:wrapper
) 来生成它们。
这个指南应该能帮助你顺利地用 Docker Compose 部署你的全栈应用!如果在过程中遇到任何问题,随时可以提出来。
我需要2个项目都从github拉取。 不是已经拉取好的
显示思路
好的,如果你的项目代码托管在 GitHub 上的公共仓库,我们可以修改 Dockerfile,让 Docker 在构建镜像的过程中直接从 GitHub 拉取最新的代码。
这样做的好处是,你本地只需要保留 Docker 相关的文件 (Dockerfile
, docker-compose.yml
, nginx.conf
等),代码总是从 GitHub 获取。
下面是更新后的方案:
🚀 项目结构 (更新后)
你的本地项目结构会变得更简洁:
my-fullstack-app/
├── backend/ # 存放后端项目的 Dockerfile
│ └── Dockerfile
│
├── frontend/ # 存放前端项目的 Dockerfile 和 Nginx 配置
│ ├── Dockerfile
│ └── nginx.conf
│
├── db_init/ # 存放数据库初始化脚本
│ └── db.sql # 你需要手动将后端的 db.sql 放到这里
│
└── docker-compose.yml # Docker Compose 配置文件
重要说明:
backend/
和frontend/
目录现在只包含各自的Dockerfile
(前端目录还包含nginx.conf
)。实际的应用代码将在 Docker 镜像构建时从 GitHub 克隆。db_init/db.sql
: 因为 MySQL 服务需要在启动时访问db.sql
,而此时后端代码可能还没被克隆到 Docker 镜像中,所以你需要手动将你的db.sql
文件(从你的后端 GitHub 仓库的src/main/resources/db.sql
或相应位置获取)放到这个db_init
目录下。
🐳 Dockerfile 配置 (从 GitHub 拉取)
1. 后端 Spring Boot 应用 ( backend/Dockerfile
)
这个 Dockerfile 会先安装 git
,然后克隆你的 GitHub 仓库,最后再构建 Spring Boot 应用。
Dockerfile
# 使用一个包含 JDK 和 Git 的基础镜像
FROM openjdk:17-jdk-slim as builder
# 安装 git
RUN apt-get update && apt-get install -y git
# 定义 GitHub 仓库 URL 和分支的参数 (可以在 docker-compose.yml 中设置)
ARG GIT_REPO_URL
ARG GIT_BRANCH=main # 默认使用 main 分支
WORKDIR /app
# 克隆指定的仓库和分支
RUN git clone --branch ${GIT_BRANCH} ${GIT_REPO_URL} .
# 如果克隆失败,打印错误信息并退出
# RUN git clone --branch ${GIT_BRANCH} ${GIT_REPO_URL} . || { echo "Git clone failed"; exit 1; }
# -- 下面的步骤假设你的 Spring Boot 项目结构和之前一样 --
# -- 确保 pom.xml, .mvn 目录在克隆下来的项目的根目录下 --
# 复制 Maven Wrapper 相关文件 (如果你的项目使用 Maven Wrapper)
# 注意:这里的路径是相对于克隆下来的项目根目录
COPY .mvn/ .mvn
COPY mvnw .
COPY pom.xml .
# 下载依赖 (利用 Docker 缓存机制)
# 如果你的 pom.xml 不在仓库根目录,需要调整这里的路径
# 例如,如果项目在 'my-backend-app' 子目录:
# WORKDIR /app/my-backend-app
# RUN ./mvnw dependency:go-offline -B
RUN ./mvnw dependency:go-offline -B
# 复制源代码 (这一步其实在 git clone 后已经完成了整个项目代码的复制)
# 所以,如果 pom.xml 和 src 在克隆后的 /app 目录下,这里不需要额外复制 src
# COPY src ./src
# 打包应用 (确保在正确的目录下执行)
RUN ./mvnw package -DskipTests
# ---- 第二阶段:运行阶段 ----
FROM openjdk:17-jre-slim
WORKDIR /app
# 从构建阶段复制 JAR 文件
# 注意:这里的路径可能需要根据你的 target 目录和 JAR 文件名调整
# 通常是 target/*.jar,如果你的仓库名或模块名影响了路径,需要确认
COPY --from=builder /app/target/*.jar app.jar
# 暴露 Spring Boot 应用的端口 (默认为 8080)
EXPOSE 8080
# 运行应用
ENTRYPOINT ["java", "-jar", "app.jar"]
重要修改和说明:
FROM openjdk:17-jdk-slim as builder
: 确保基础镜像可以安装 git。slim
版本可能不带,所以用apt-get install -y git
。ARG GIT_REPO_URL
: 定义一个构建参数,用于接收你的后端 GitHub 仓库 URL。ARG GIT_BRANCH=main
: 定义一个构建参数,用于接收分支名,默认为main
。RUN git clone --branch ${GIT_BRANCH} ${GIT_REPO_URL} .
: 克隆仓库到当前工作目录 (/app
)。.
表示克隆到当前目录。- 路径调整 :
git clone
之后,你的所有项目文件 (包括pom.xml
,.mvn
,mvnw
,src
) 都会在/app
目录下。确保后续的COPY
和RUN ./mvnw
命令的路径是正确的。如果你的 Spring Boot 项目本身在一个子目录内(例如,仓库根目录不是直接的 Maven 项目根目录),你需要调整WORKDIR
或COPY
和RUN
命令中的路径。例如,如果项目在克隆下来的my-actual-project-folder
子目录中,你可能需要WORKDIR /app/my-actual-project-folder
。 db.sql
的位置 : 这个 Dockerfile 不再直接处理db.sql
。db.sql
会被克隆到镜像中,但我们使用上面提到的db_init/db.sql
方案来初始化数据库。
2. 前端 React 应用 ( frontend/Dockerfile
)
类似地,前端的 Dockerfile 也会先安装 git
并克隆仓库。
Dockerfile
# ---- 构建阶段 ----
FROM node:18-alpine as builder
# 安装 git
RUN apk add --no-cache git
# 定义 GitHub 仓库 URL 和分支的参数
ARG GIT_REPO_URL
ARG GIT_BRANCH=main # 默认使用 main 分支
WORKDIR /app
# 克隆指定的仓库和分支
RUN git clone --branch ${GIT_BRANCH} ${GIT_REPO_URL} .
# RUN git clone --branch ${GIT_BRANCH} ${GIT_REPO_URL} . || { echo "Git clone failed"; exit 1; }
# -- 下面的步骤假设你的 React 项目结构和之前一样 --
# -- 确保 package.json 在克隆下来的项目的根目录下 --
# 复制 package.json 和 package-lock.json (或 yarn.lock)
# 注意:这里的路径是相对于克隆下来的项目根目录
COPY package*.json ./
# 如果使用 yarn
# COPY yarn.lock ./
# 安装依赖 (确保在正确的目录下执行)
RUN npm install
# 如果使用 yarn
# RUN yarn install
# 复制所有项目文件 (这一步其实在 git clone 后已经完成了整个项目代码的复制)
# COPY . .
# 构建应用 (确保在正确的目录下执行)
RUN npm run build
# 如果使用 yarn
# RUN yarn build
# ---- 运行阶段 ----
FROM nginx:stable-alpine
# 复制 Nginx 配置文件 (这个文件还是从本地的 frontend 目录复制)
COPY nginx.conf /etc/nginx/conf.d/default.conf
# 从构建阶段复制构建好的静态文件到 Nginx 的 www 目录
# 注意: /app/dist 路径可能需要根据你的 Vite build outputDir 配置进行调整
# 这个路径是相对于克隆后项目构建的输出路径
COPY --from=builder /app/dist /usr/share/nginx/html
# 暴露 Nginx 端口 (默认为 80)
EXPOSE 80
# 启动 Nginx
CMD ["nginx", "-g", "daemon off;"]
重要修改和说明:
FROM node:18-alpine as builder
:alpine
版本的 Node 镜像通常不带git
,所以用apk add --no-cache git
安装。ARG GIT_REPO_URL
和ARG GIT_BRANCH
: 与后端类似,用于接收前端 GitHub 仓库 URL 和分支。RUN git clone ...
: 克隆前端仓库。- 路径调整 : 同样,确保
package.json
等文件以及npm install
,npm run build
命令在克隆下来的项目根目录或正确的子目录中执行。Vite 构建的输出目录 (dist
) 路径也需要正确。 COPY nginx.conf ...
:nginx.conf
文件仍然从你本地的frontend/
目录复制,因为它不是项目代码的一部分,而是部署配置文件。
Nginx 配置文件 (frontend/nginx.conf
)
这个文件保持不变,和之前提供的一样。
Nginx
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
location / {
try_files $uri $uri/ /index.html;
}
# 如果你需要通过 Nginx 代理 API 请求到后端
# location /api/ {
# proxy_pass http://backend:8080/; # "backend" 是 docker-compose.yml 中定义的服务名
# 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;
# }
}
🐳 Docker Compose 配置 ( docker-compose.yml
) (更新后)
现在我们需要在 docker-compose.yml
的 build
部分传递 GitHub 仓库的 URL 和分支名给 Dockerfile。
YAML
version: '3.8'
services:
# 后端 Spring Boot 应用
backend:
build:
context: ./backend # Dockerfile 所在的目录
dockerfile: Dockerfile
args:
# 替换为你的后端 GitHub 仓库 URL
GIT_REPO_URL: https://github.com/YOUR_USERNAME/YOUR_BACKEND_REPO.git
# GIT_BRANCH: your-feature-branch # 如果不是 main/master,取消注释并修改
container_name: my-springboot-app
ports:
- "8080:8080"
environment:
- SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/mydatabase?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
- SPRING_DATASOURCE_USERNAME=myuser
- SPRING_DATASOURCE_PASSWORD=mypassword
- SPRING_JPA_HIBERNATE_DDL_AUTO=update # 或者 validate, none
depends_on:
db:
condition: service_healthy
networks:
- my-app-network
# 前端 React 应用 (Nginx)
frontend:
build:
context: ./frontend # Dockerfile 所在的目录
dockerfile: Dockerfile
args:
# 替换为你的前端 GitHub 仓库 URL
GIT_REPO_URL: https://github.com/YOUR_USERNAME/YOUR_FRONTEND_REPO.git
# GIT_BRANCH: your-feature-branch # 如果不是 main/master,取消注释并修改
container_name: my-react-app
ports:
- "80:80"
depends_on:
- backend
networks:
- my-app-network
# MySQL 数据库
db:
image: mysql:8.0
container_name: my-mysql-db
restart: unless-stopped
environment:
MYSQL_DATABASE: mydatabase
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
MYSQL_ROOT_PASSWORD: rootpassword
volumes:
- mysql_data:/var/lib/mysql
# 关键:从本地的 db_init 目录挂载初始化脚本
- ./db_init/db.sql:/docker-entrypoint-initdb.d/init.sql
ports:
- "3306:3306" # (可选) 方便本地调试
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost", "-u$$MYSQL_USER", "-p$$MYSQL_PASSWORD"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
networks:
- my-app-network
networks:
my-app-network:
driver: bridge
volumes:
mysql_data:
关键修改和说明:
build.args
:- 在
backend
和frontend
服务的build
配置下,我们添加了args
。 GIT_REPO_URL
: 你必须将https://github.com/YOUR_USERNAME/YOUR_BACKEND_REPO.git
和https://github.com/YOUR_USERNAME/YOUR_FRONTEND_REPO.git
替换为你自己项目的实际 GitHub URL。GIT_BRANCH
: 如果你想拉取特定分支而不是默认的main
(或master
),取消注释并修改这一行。
- 在
db.volumes
:./db_init/db.sql:/docker-entrypoint-initdb.d/init.sql
: 这里明确了 MySQL 服务会从你本地项目根目录下的db_init/db.sql
文件加载初始化脚本。
🛠️ 部署步骤 (更新后)
-
准备本地项目结构:
- 创建父目录
my-fullstack-app/
。 - 在
my-fullstack-app/
下创建backend/
目录,并在其中放入更新后的后端Dockerfile
。 - 在
my-fullstack-app/
下创建frontend/
目录,并在其中放入更新后的前端Dockerfile
和nginx.conf
文件。 - 在
my-fullstack-app/
下创建db_init/
目录。从你的后端 GitHub 仓库中获取db.sql
文件 (通常在src/main/resources/db.sql
),并将其放入my-fullstack-app/db_init/
目录下。
- 创建父目录
-
创建 docker-compose.yml:
- 在
my-fullstack-app/
(项目根目录) 下创建上面提供的docker-compose.yml
文件。
- 在
-
修改配置 (重要):
docker-compose.yml
:- GitHub 仓库 URL : 在
backend
和frontend
服务的build.args
部分,将GIT_REPO_URL
的值更新为你的实际 GitHub 仓库地址。如果需要,也设置GIT_BRANCH
。 - 数据库凭证 : 检查并修改
db
服务和backend
服务中的数据库相关环境变量 (MYSQL_DATABASE
,MYSQL_USER
,MYSQL_PASSWORD
,MYSQL_ROOT_PASSWORD
,SPRING_DATASOURCE_USERNAME
,SPRING_DATASOURCE_PASSWORD
)。 - 端口映射: 如果需要,调整端口。
- GitHub 仓库 URL : 在
Dockerfile
(后端和前端) :-
仔细检查
git clone
后的文件路径是否与mvnw
、pom.xml
、package.json
、构建命令 (mvn package
,npm run build
) 以及最终产物 (JAR 文件,dist
目录) 的路径一致。如果你的 GitHub 仓库的根目录不是 Maven/NPM 项目的根目录 (例如,代码在一个子文件夹里),你需要在 Dockerfile 中调整WORKDIR
或者相关命令的路径。 -
例如,如果后端代码在克隆下来的仓库中的
project-subfolder/
目录下: Dockerfile# backend/Dockerfile # ... RUN git clone --branch ${GIT_BRANCH} ${GIT_REPO_URL} repo_code WORKDIR /app/repo_code/project-subfolder # 进入实际项目目录 # 现在 ./mvnw, pom.xml 等应该能被找到 RUN ./mvnw dependency:go-offline -B RUN ./mvnw package -DskipTests # ... COPY --from=builder /app/repo_code/project-subfolder/target/*.jar app.jar
-
-
构建并启动服务:
-
打开终端,进入
my-fullstack-app/
目录。 -
运行: Bash
docker-compose up --build
Docker 会先为后端和前端构建镜像,这个过程会包括从 GitHub 克隆代码。然后启动所有服务。
-
-
访问和管理服务:
- 访问方式、查看日志、停止服务等步骤与之前的指南相同。
- 前端:
http://localhost
(或你映射的端口) - 后端:
http://localhost:8080
(或你映射的端口)
- 前端:
- 访问方式、查看日志、停止服务等步骤与之前的指南相同。
这个方案通过在 Docker 构建时动态拉取代码,使得部署更加自动化,本地依赖更少。记得仔细替换 URL 和检查 Dockerfile 中的路径!