部署总览
前端打包: 我们将配置 package.json
,使用 npm run build
(内部调用 vite build
) 来打包。这个过程将完全在 Docker 构建镜像的过程中自动完成,你的主机上甚至不需要安装 Node.js。
后端打包: 我们将配置 pom.xml
,使用 mvn clean package
来打包。这一步需要在执行 Docker Compose 之前手动完成一次,以生成 JAR 文件。
部署: 使用 docker-compose up
一键启动所有服务。
请在你的电脑上创建如下的完整目录和文件结构。你只需将已有的代码复制到对应的 src
目录,并用下面提供的内容创建或覆盖配置文件。
/my-fullstack-app # 你的项目根目录
|
├── docker-compose.yml # ✅ (下面提供内容)
|
├── .env # ✅ (下面提供内容)
|
├── backend/ # 后端 Spring Boot 项目
│ ├── src/main/java/ # 你的 Java 源代码放在这里
│ ├── src/main/resources/
│ │ └── application.properties # ✅ (下面提供内容)
│ ├── pom.xml # ✅ (下面提供内容)
│ └── Dockerfile # ✅ (下面提供内容)
|
├── frontend/ # 前端 Vite + React 项目
│ ├── src/ # 你的 React 源代码放在这里
│ ├── public/
│ ├── .env.production # ✅ (下面提供内容)
│ ├── package.json # ✅ (下面提供内容)
│ └── Dockerfile # ✅ (下面提供内容)
│ ├── index.html # ✅ (下面提供内容)
│ └── vite.config.js # ✅ (下面提供内容)
|
└── nginx/
└── nginx.conf # ✅ (下面提供内容)
backend/pom.xml
这个文件定义了项目依赖和 最重要的打包插件 (spring-boot-maven-plugin
)。
4.0.0
org.springframework.boot
spring-boot-starter-parent
3.2.5
com.example
my-backend
0.0.1-SNAPSHOT
my-backend
My Spring Boot Backend
17
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-data-jpa
com.mysql
mysql-connector-j
runtime
org.springframework.boot
spring-boot-maven-plugin
backend/src/main/resources/application.properties
配置文件,用于从环境变量中读取数据库连接信息。
# 服务器端口
server.port=8080
# 数据库连接配置 (值将由 Docker Compose 环境变量注入)
spring.datasource.url=jdbc:mysql://${SPRING_DATASOURCE_HOST:db}:${SPRING_DATASOURCE_PORT:3306}/${MYSQL_DATABASE}?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.username=${MYSQL_USER}
spring.datasource.password=${MYSQL_PASSWORD}
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# JPA/Hibernate 配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
backend/Dockerfile
用于构建后端服务镜像。
# 使用一个包含 Java 17 JRE 的官方镜像
FROM eclipse-temurin:17-jre-alpine
# 设置工作目录
WORKDIR /app
# 将打包好的 JAR 文件复制到容器中,并重命名为 app.jar
# target/*.jar 会匹配 target 目录下的任何 .jar 文件
COPY target/*.jar app.jar
# 暴露 Spring Boot 应用的端口
EXPOSE 8080
# 容器启动时运行 java -jar 命令
ENTRYPOINT ["java", "-jar", "app.jar"]
frontend/package.json
这个文件定义了前端依赖和 打包脚本 build
。
{
"name": "my-frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"axios": "^1.7.2",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@vitejs/plugin-react": "^4.2.1",
"eslint": "^8.57.0",
"eslint-plugin-react": "^7.34.1",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.6",
"vite": "^5.2.0"
}
}
frontend/.env.production
生产环境变量,VITE_API_BASE_URL
会在 npm run build
时被嵌入代码。
VITE_API_BASE_URL=/api
frontend/Dockerfile
多阶段构建 Dockerfile,它会自动执行 npm install
和 npm run build
。
# ----- Build Stage -----
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
# 运行在 package.json 中定义的 "build" 脚本
RUN npm run build
# ----- Production Stage -----
FROM nginx:stable-alpine
# 从 'builder' 阶段复制构建好的静态文件 (在 /app/dist 目录中)
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
nginx/nginx.conf
Nginx 配置文件,用于托管前端静态文件和反向代理后端 API。
server {
listen 80;
server_name localhost;
# 根目录指向容器内 Nginx 存放静态文件的位置
location / {
root /usr/share/nginx/html;
index index.html index.htm;
# 单页应用(SPA)路由配置,避免刷新404
try_files $uri $uri/ /index.html;
}
# API 反向代理配置
location /api/ {
# 将请求转发给名为 'backend' 的服务 (由 Docker Compose 定义)
proxy_pass http://backend:8080/api/;
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;
}
}
.env
(在项目根目录)存放所有密码和配置,此文件绝对不要上传到 Git 仓库。
# /my-fullstack-app/.env
# --- MySQL 配置 ---
# 请务必修改成你的强密码
MYSQL_ROOT_PASSWORD=your_strong_root_password
MYSQL_DATABASE=my_app_db
MYSQL_USER=my_app_user
MYSQL_PASSWORD=your_strong_password
# --- Spring Boot 将使用的环境变量 ---
SPRING_DATASOURCE_HOST=db
SPRING_DATASOURCE_PORT=3306
docker-compose.yml
(在项目根目录)最终的编排文件,它将所有服务串联起来。
version: '3.8'
services:
# 前端服务 (Nginx)
frontend:
build:
context: ./frontend
container_name: my-app-frontend
ports:
- "80:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- backend
restart: always
networks:
- app-network
# 后端服务 (Spring Boot)
backend:
build:
context: ./backend
container_name: my-app-backend
environment:
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- SPRING_DATASOURCE_HOST=${SPRING_DATASOURCE_HOST}
- SPRING_DATASOURCE_PORT=${SPRING_DATASOURCE_PORT}
depends_on:
db:
condition: service_healthy
restart: always
networks:
- app-network
# 数据库服务 (MySQL)
db:
image: mysql:8.0
container_name: my-app-db
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
volumes:
# 持久化数据库数据
- mysql-data:/var/lib/mysql
# ✅ 将你的初始化 SQL 文件挂载到容器的初始化目录
- ./backend/src/main/resources/db.sql:/docker-entrypoint-initdb.d/init.sql
ports:
- "3307:3306"
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost", "-u", "${MYSQL_USER}", "-p${MYSQL_PASSWORD}"]
interval: 10s
timeout: 5s
retries: 5
restart: always
networks:
- app-network
# 定义共享网络
networks:
app-network:
driver: bridge
# 定义数据卷
volumes:
mysql-data:
driver: local
现在,万事俱备。你只需要按顺序执行以下命令。
这是在运行 docker-compose
之前唯一需要手动执行的打包步骤。
# 首先,进入后端项目目录
cd backend
# 执行 Maven 打包命令。(-DskipTests 会跳过测试,加快打包速度)
# Mac/Linux:
mvn clean package -DskipTests
# Windows (CMD):
# mvnw.cmd clean package -DskipTests
# 这会在 backend/target/ 目录下生成一个 .jar 文件。
# 完成后,返回项目根目录
cd ..
确保你在项目根目录 /my-fullstack-app
下执行此命令。 这个命令会自动完成前端的打包(在 Docker 内部)、构建所有镜像并启动容器。
# --build: 强制重新构建镜像 (当你修改了代码时使用)
# -d: 后台运行
docker-compose up --build -d
访问前端: 打开浏览器,访问 http://localhost
。
检查 API: 在你的应用中进行需要调用后端的操作,确认功能正常。
查看日志: 如果遇到问题,使用 docker-compose logs -f backend
或 docker-compose logs -f frontend
查看实时日志。
# 查看所有正在运行的容器
docker-compose ps
# 停止并移除所有容器
docker-compose down
docker-compose down --rmi all --volumes
你现在拥有了一个完整的、可重复的、自动化的部署流程。以后每次更新代码,流程都一样:
如果后端代码变了,就去 backend
目录执行 mvn clean package -DskipTests
。
回到根目录,执行 docker-compose up --build -d
。 就是这么简单!