一键化部署
好的,我明白了。你希望脚本变得更简洁,主要负责:
- 代码克隆:从 GitHub 克隆你的后端和前端项目,并在克隆前确保目标目录为空。
- 文件复制:将你预先准备好的
Dockerfile
(后端和前端各一个)、前端的nginx.conf
以及docker-compose.yml
文件从你本地的指定位置复制到新创建的项目目录结构中。 - 数据库脚本处理:尝试从克隆的后端项目中复制
db.sql
。 - 一键部署:使用复制过来的
docker-compose.yml
文件启动服务。
这样,Dockerfile
和 docker-compose.yml
的具体内容就由你维护在本地文件中,脚本只负责“组装”和执行。
步骤 1: 准备你的本地配置文件
在运行脚本之前,你需要在你的电脑上准备好以下文件。假设你将这些文件统一存放在一个地方,例如 ~/my_docker_configs/
目录下 (你可以选择任何你方便的路径,并在脚本中配置)。
-
后端 Dockerfile (
~/my_docker_configs/Dockerfile.backend
):- 这个
Dockerfile
用于构建你的 Spring Boot 应用。 - 它不应该包含
git clone
指令。 - 内容可以参考我们之前讨论过的后端
Dockerfile
(没有git clone
的版本)。例如: Dockerfile# ~/my_docker_configs/Dockerfile.backend FROM openjdk:17-jdk-slim WORKDIR /app COPY .mvn/ .mvn COPY mvnw . COPY pom.xml . RUN ./mvnw dependency:go-offline -B COPY src ./src RUN ./mvnw package -DskipTests FROM openjdk:17-jre-slim WORKDIR /app COPY --from=0 /app/target/*.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]
- 这个
-
前端 Dockerfile (
~/my_docker_configs/Dockerfile.frontend
):- 这个
Dockerfile
用于构建你的 React 应用并配置 Nginx。 - 它不应该包含
git clone
指令。 - 内容可以参考我们之前讨论过的前端
Dockerfile
(没有git clone
的版本)。例如: Dockerfile# ~/my_docker_configs/Dockerfile.frontend FROM node:18-alpine as builder WORKDIR /app COPY package*.json ./ RUN npm install COPY . . RUN npm run build FROM nginx:stable-alpine COPY --from=builder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf # nginx.conf 将被脚本复制到构建上下文中 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
- 这个
-
前端 Nginx 配置文件 (
~/my_docker_configs/nginx.conf
):- 这是 Nginx 用来服务 React 应用的配置文件。
- 内容可以参考我们之前讨论过的
nginx.conf
。例如: Nginx# ~/my_docker_configs/nginx.conf server {listen 80;server_name localhost;root /usr/share/nginx/html;index index.html index.htm;location / {try_files $uri $uri/ /index.html;} }
-
Docker Compose 文件 (
~/my_docker_configs/docker-compose.yml.template
):- 这是核心的编排文件。注意,我建议将其命名为
docker-compose.yml.template
,脚本会将其复制并重命名为docker-compose.yml
。 - 重要: 这个
docker-compose.yml
文件中的build.context
应该指向脚本克隆代码后并放入Dockerfile
的目录。 - 内容可以参考我们之前讨论过的
docker-compose.yml
,但build
部分是关键。例如: YAML# ~/my_docker_configs/docker-compose.yml.template version: '3.8'services:backend:build:context: ./backend # 脚本会将代码克隆到 'backend', Dockerfile 也会被复制到 'backend/Dockerfile'dockerfile: Dockerfilecontainer_name: my-springboot-appports:- "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=updatedepends_on:db:condition: service_healthynetworks:- my-app-networkfrontend:build:context: ./frontend # 脚本会将代码克隆到 'frontend', Dockerfile 和 nginx.conf 也会被复制到这里dockerfile: Dockerfilecontainer_name: my-react-appports:- "80:80"depends_on:- backendnetworks:- my-app-networkdb:image: mysql:8.0container_name: my-mysql-dbrestart: unless-stoppedenvironment:MYSQL_DATABASE: mydatabaseMYSQL_USER: myuserMYSQL_PASSWORD: mypasswordMYSQL_ROOT_PASSWORD: rootpassword # 请使用强密码volumes:- mysql_data_volume:/var/lib/mysql- ./db_init/init.sql:/docker-entrypoint-initdb.d/init.sql # 脚本会尝试创建这个文件healthcheck:test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost", "-u$${MYSQL_USER}", "-p$${MYSQL_PASSWORD}"]interval: 10stimeout: 5sretries: 5start_period: 30snetworks:- my-app-networknetworks:my-app-network:driver: bridgevolumes:mysql_data_volume:
- 这是核心的编排文件。注意,我建议将其命名为
步骤 2: 部署脚本 (setup_and_deploy_local_files.sh
)
将以下内容保存为一个名为 setup_and_deploy_local_files.sh
的文件:
Bash
#!/bin/bash# --- 配置项 ---
# !!! 请修改以下 GitHub 仓库 URL 为你自己的项目 URL !!!
BACKEND_REPO_URL="https://github.com/YOUR_USERNAME/YOUR_BACKEND_SPRINGBOOT_REPO.git"
FRONTEND_REPO_URL="https://github.com/YOUR_USERNAME/YOUR_FRONTEND_REACT_REPO.git"# !!! 请修改以下路径为你本地存放 Dockerfile 和 docker-compose.yml 模板文件的实际路径 !!!
LOCAL_CONFIG_BASE_PATH="${HOME}/my_docker_configs" # 示例路径: 用户家目录下的 my_docker_configs
DOCKERFILE_BACKEND_SOURCE="${LOCAL_CONFIG_BASE_PATH}/Dockerfile.backend"
DOCKERFILE_FRONTEND_SOURCE="${LOCAL_CONFIG_BASE_PATH}/Dockerfile.frontend"
NGINX_CONF_SOURCE="${LOCAL_CONFIG_BASE_PATH}/nginx.conf"
DOCKER_COMPOSE_YML_SOURCE="${LOCAL_CONFIG_BASE_PATH}/docker-compose.yml.template"# 项目目录名称
MAIN_PROJECT_DIR="my_fullstack_app_from_local_configs" # 最终部署的项目会在这里创建
BACKEND_CODE_DIR="backend" # 代码会克隆到 MAIN_PROJECT_DIR/backend
FRONTEND_CODE_DIR="frontend" # 代码会克隆到 MAIN_PROJECT_DIR/frontend
DB_INIT_DIR="db_init"# --- 脚本检查 ---
function check_file_exists() {if [ ! -f "$1" ]; thenecho "❌ 错误: 必需的配置文件 '$1' 未找到。"echo "请确保已按照说明准备好所有本地配置文件,并正确设置脚本中的路径。"exit 1fi
}check_file_exists "${DOCKERFILE_BACKEND_SOURCE}"
check_file_exists "${DOCKERFILE_FRONTEND_SOURCE}"
check_file_exists "${NGINX_CONF_SOURCE}"
check_file_exists "${DOCKER_COMPOSE_YML_SOURCE}"# --- 脚本开始 ---
echo "🚀 开始使用本地配置文件部署全栈项目..."# 1. 创建主项目目录
echo "创建主项目目录: ${MAIN_PROJECT_DIR}"
mkdir -p "${MAIN_PROJECT_DIR}"
cd "${MAIN_PROJECT_DIR}" || exit # 进入主项目目录,后续操作都在此目录下进行# 2. 清理并克隆后端仓库
echo "🔄 清理并克隆后端仓库到 ./${BACKEND_CODE_DIR}/ ..."
if [ -d "${BACKEND_CODE_DIR}" ]; thenecho "删除已存在的后端代码目录: ${BACKEND_CODE_DIR}"rm -rf "${BACKEND_CODE_DIR}"
fi
mkdir -p "${BACKEND_CODE_DIR}"
git clone "${BACKEND_REPO_URL}" "${BACKEND_CODE_DIR}"
if [ $? -ne 0 ]; thenecho "❌ 克隆后端仓库失败!请检查 URL 或网络连接。"exit 1
fi
echo "✅ 后端仓库克隆完成。"# 3. 清理并克隆前端仓库
echo "🔄 清理并克隆前端仓库到 ./${FRONTEND_CODE_DIR}/ ..."
if [ -d "${FRONTEND_CODE_DIR}" ]; thenecho "删除已存在的前端代码目录: ${FRONTEND_CODE_DIR}"rm -rf "${FRONTEND_CODE_DIR}"
fi
mkdir -p "${FRONTEND_CODE_DIR}"
git clone "${FRONTEND_REPO_URL}" "${FRONTEND_CODE_DIR}"
if [ $? -ne 0 ]; thenecho "❌ 克隆前端仓库失败!请检查 URL 或网络连接。"exit 1
fi
echo "✅ 前端仓库克隆完成。"# 4. 复制本地 Dockerfile 和配置文件到相应位置
echo "📝 复制本地配置文件..."
cp "${DOCKERFILE_BACKEND_SOURCE}" "./${BACKEND_CODE_DIR}/Dockerfile"
echo " > 后端 Dockerfile 已复制到 ./${BACKEND_CODE_DIR}/Dockerfile"cp "${DOCKERFILE_FRONTEND_SOURCE}" "./${FRONTEND_CODE_DIR}/Dockerfile"
echo " > 前端 Dockerfile 已复制到 ./${FRONTEND_CODE_DIR}/Dockerfile"cp "${NGINX_CONF_SOURCE}" "./${FRONTEND_CODE_DIR}/nginx.conf"
echo " > Nginx 配置文件已复制到 ./${FRONTEND_CODE_DIR}/nginx.conf"cp "${DOCKER_COMPOSE_YML_SOURCE}" "./docker-compose.yml"
echo " > Docker Compose 文件已复制到 ./docker-compose.yml"
echo "✅ 本地配置文件复制完毕。"# 5. 创建数据库初始化目录并尝试复制 db.sql
echo "📝 创建数据库初始化目录 (./${DB_INIT_DIR}) 并尝试复制 db.sql..."
mkdir -p "${DB_INIT_DIR}"
DB_SQL_SOURCE_PATH="./${BACKEND_CODE_DIR}/src/main/resources/db.sql" # 假设的 db.sql 路径
DB_SQL_DEST_PATH="./${DB_INIT_DIR}/init.sql"if [ -f "${DB_SQL_SOURCE_PATH}" ]; thencp "${DB_SQL_SOURCE_PATH}" "${DB_SQL_DEST_PATH}"echo "✅ db.sql 已从 ${DB_SQL_SOURCE_PATH} 复制到 ${DB_SQL_DEST_PATH}"
elseecho "⚠️ 未在 ${DB_SQL_SOURCE_PATH} 找到 db.sql。"echo "👉 请手动将你的数据库初始化脚本命名为 init.sql 并放置在 ${MAIN_PROJECT_DIR}/${DB_INIT_DIR}/ 目录下。"echo " (如果不需要数据库初始化脚本,可以忽略此消息)"
fi# 6. 构建并启动 Docker Compose 服务
echo "🐳 构建并启动 Docker 服务 (docker-compose up -d --build)..."
docker-compose up -d --buildif [ $? -eq 0 ]; thenecho "🎉 项目部署成功!"echo "前端应用应该可以通过 http://localhost 访问 (如果80端口未被占用)"echo "后端应用应该可以通过 http://localhost:8080 访问 (如果8080端口未被占用)"echo "MySQL 数据库正在运行。"echo "使用 'docker-compose logs -f' 查看日志。"echo "使用 'docker-compose down' 停止服务。"
elseecho "❌ Docker Compose 启动失败。请查看上面的错误日志。"
fiecho "🚀 部署脚本执行完毕。"
步骤 3: 如何使用脚本
- 准备文件: 确保你已经按照 步骤 1 创建并保存了
Dockerfile.backend
,Dockerfile.frontend
,nginx.conf
, 和docker-compose.yml.template
在你本地的某个目录下 (例如~/my_docker_configs/
)。 - 保存脚本: 将 步骤 2 中的脚本代码复制并粘贴到一个新文件中,例如
setup_and_deploy_local_files.sh
。 - 修改脚本配置:
- 打开
setup_and_deploy_local_files.sh
文件。 - 必须修改:
BACKEND_REPO_URL
和FRONTEND_REPO_URL
为你的 GitHub 仓库地址。LOCAL_CONFIG_BASE_PATH
为你在步骤 1 中存放配置文件的实际路径。
- (可选)你可以修改
MAIN_PROJECT_DIR
来更改最终生成的项目目录名称。
- 打开
- 授予执行权限: 在终端中,进入脚本所在的目录,然后运行: Bash
chmod +x setup_and_deploy_local_files.sh
- 运行脚本: Bash
./setup_and_deploy_local_files.sh
脚本执行流程
- 检查本地文件: 脚本会先检查你在
LOCAL_CONFIG_BASE_PATH
中指定的 Dockerfile、nginx.conf 和 docker-compose.yml 模板文件是否存在,如果不存在则会报错退出。 - 创建主目录: 创建
MAIN_PROJECT_DIR
并进入该目录。 - 克隆代码: 清理可能已存在的
backend
和frontend
子目录,然后从 GitHub 克隆你的项目代码到这两个目录中。 - 复制配置文件:
- 将
LOCAL_DOCKERFILE_BACKEND_SOURCE
复制到MAIN_PROJECT_DIR/backend/Dockerfile
。 - 将
LOCAL_DOCKERFILE_FRONTEND_SOURCE
复制到MAIN_PROJECT_DIR/frontend/Dockerfile
。 - 将
LOCAL_NGINX_CONF_SOURCE
复制到MAIN_PROJECT_DIR/frontend/nginx.conf
。 - 将
LOCAL_DOCKER_COMPOSE_YML_SOURCE
(你的模板) 复制到MAIN_PROJECT_DIR/docker-compose.yml
。
- 将
- 处理
db.sql
: 与之前的脚本一样,尝试从克隆的后端项目中找到db.sql
并复制到db_init/init.sql
。 - 启动服务: 使用复制过来的
docker-compose.yml
文件执行docker-compose up -d --build
来构建镜像并启动所有服务。
这样,你的部署脚本会更专注于流程的编排,而具体的 Docker 配置则由你维护在独立的本地文件中,方便阅读和修改。
好的,这个脚本将帮助你自动化以下操作:
- 创建一个主项目目录。
- 清空并克隆你的 Spring Boot 后端和 React 前端 GitHub 仓库到各自的子目录中。
- 在克隆下来的代码目录中生成对应的
Dockerfile
和前端的nginx.conf
。 - 创建
db_init
目录,并尝试从后端项目中复制db.sql
(如果找到)。 - 生成
docker-compose.yml
文件。 - 最后,使用
docker-compose up -d --build
一键构建并启动所有服务。
重要前提:
- 你需要在你的机器上安装好 Docker 和 Docker Compose。
- 这个脚本使用
git
命令,所以也需要安装 Git。 - 脚本会删除已存在的
backend
和frontend
目录(在主项目录下)以确保它们是空的,然后再克隆。请谨慎操作,确保这些目录中没有你需要保留的未提交更改。
脚本内容 (setup_and_deploy.sh
)
请将以下内容保存为一个名为 setup_and_deploy.sh
的文件:
#!/bin/bash# --- 配置项 ---
# !!! 请修改以下 GitHub 仓库 URL 为你自己的项目 URL !!!
BACKEND_REPO_URL="https://github.com/YOUR_USERNAME/YOUR_BACKEND_SPRINGBOOT_REPO.git"
FRONTEND_REPO_URL="https://github.com/YOUR_USERNAME/YOUR_FRONTEND_REACT_REPO.git"# 项目目录名称
MAIN_PROJECT_DIR="my_fullstack_app_deployed"
BACKEND_DIR="backend"
FRONTEND_DIR="frontend"
DB_INIT_DIR="db_init"# MySQL 配置 (可以根据需要修改 docker-compose.yml 中的环境变量)
MYSQL_DATABASE="mydatabase"
MYSQL_USER="myuser"
MYSQL_PASSWORD="mypassword" # !!! 生产环境请使用更强壮的密码,并考虑使用 .env 文件 !!!
MYSQL_ROOT_PASSWORD="rootpassword" # !!! 生产环境请使用更强壮的密码 !!!# --- 脚本开始 ---
echo "🚀 开始部署全栈项目..."# 1. 创建主项目目录
echo "创建主项目目录: ${MAIN_PROJECT_DIR}"
mkdir -p "${MAIN_PROJECT_DIR}"
cd "${MAIN_PROJECT_DIR}" || exit# 2. 清理并克隆后端仓库
echo "🔄 清理并克隆后端仓库..."
if [ -d "${BACKEND_DIR}" ]; thenecho "删除已存在的后端目录: ${BACKEND_DIR}"rm -rf "${BACKEND_DIR}"
fi
mkdir -p "${BACKEND_DIR}"
git clone "${BACKEND_REPO_URL}" "${BACKEND_DIR}"
if [ $? -ne 0 ]; thenecho "❌ 克隆后端仓库失败!请检查 URL 或网络连接。"exit 1
fi
echo "✅ 后端仓库克隆完成到 ${BACKEND_DIR}/"# 3. 清理并克隆前端仓库
echo "🔄 清理并克隆前端仓库..."
if [ -d "${FRONTEND_DIR}" ]; thenecho "删除已存在的前端目录: ${FRONTEND_DIR}"rm -rf "${FRONTEND_DIR}"
fi
mkdir -p "${FRONTEND_DIR}"
git clone "${FRONTEND_REPO_URL}" "${FRONTEND_DIR}"
if [ $? -ne 0 ]; thenecho "❌ 克隆前端仓库失败!请检查 URL 或网络连接。"exit 1
fi
echo "✅ 前端仓库克隆完成到 ${FRONTEND_DIR}/"# 4. 生成后端 Dockerfile
# Dockerfile 将存放在克隆下来的后端代码目录的根目录下
echo "📝 生成后端 Dockerfile (${BACKEND_DIR}/Dockerfile)..."
cat << EOF > "${BACKEND_DIR}/Dockerfile"
# 使用一个包含 JDK 的基础镜像 (例如 OpenJDK 17)
FROM openjdk:17-jdk-slim# 设置工作目录
WORKDIR /app# 复制 Maven Wrapper 相关文件 (如果项目使用 Maven Wrapper)
COPY .mvn/ .mvn
COPY mvnw .
COPY pom.xml .# 下载依赖 (利用 Docker 缓存机制)
# 如果 pom.xml 不在仓库根目录,或者 mvnw 不可用,需要调整
RUN ./mvnw dependency:go-offline -B || { echo "Maven go-offline failed. Check mvnw and pom.xml presence."; exit 1; }# 复制源代码
COPY src ./src# 打包应用
RUN ./mvnw package -DskipTests# ---- 第二阶段:运行阶段 ----
# 使用一个更小的 JRE 镜像来运行应用
FROM openjdk:17-jre-slimWORKDIR /app# 从构建阶段复制 JAR 文件 (通常在 target/*.jar)
COPY --from=0 /app/target/*.jar app.jar# 暴露 Spring Boot 应用的端口 (默认为 8080)
EXPOSE 8080# 运行应用
ENTRYPOINT ["java", "-jar", "app.jar"]
EOF
echo "✅ 后端 Dockerfile 生成完毕。"# 5. 生成前端 Dockerfile
# Dockerfile 将存放在克隆下来的前端代码目录的根目录下
echo "📝 生成前端 Dockerfile (${FRONTEND_DIR}/Dockerfile)..."
cat << EOF > "${FRONTEND_DIR}/Dockerfile"
# ---- 构建阶段 ----
# 使用 Node.js 镜像 (例如 Node 18 Alpine)
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 . .# 构建应用 (通常是 npm run build)
RUN npm run build# ---- 运行阶段 ----
FROM nginx:stable-alpine# 复制 Nginx 配置文件 (nginx.conf 需要和 Dockerfile 在同一构建上下文)
COPY nginx.conf /etc/nginx/conf.d/default.conf# 从构建阶段复制构建好的静态文件到 Nginx 的 www 目录
# Vite 默认输出到 dist 目录
COPY --from=builder /app/dist /usr/share/nginx/html# 暴露 Nginx 端口 (默认为 80)
EXPOSE 80# 启动 Nginx
CMD ["nginx", "-g", "daemon off;"]
EOF
echo "✅ 前端 Dockerfile 生成完毕。"# 6. 生成前端 Nginx 配置文件
# nginx.conf 将存放在克隆下来的前端代码目录的根目录下
echo "📝 生成前端 Nginx 配置文件 (${FRONTEND_DIR}/nginx.conf)..."
cat << EOF > "${FRONTEND_DIR}/nginx.conf"
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;# }
}
EOF
echo "✅ 前端 Nginx 配置文件生成完毕。"# 7. 创建数据库初始化目录并尝试复制 db.sql
echo "📝 创建数据库初始化目录 (${DB_INIT_DIR})..."
mkdir -p "${DB_INIT_DIR}"
DB_SQL_SOURCE_PATH="${BACKEND_DIR}/src/main/resources/db.sql" # 假设的 db.sql 路径
DB_SQL_DEST_PATH="${DB_INIT_DIR}/init.sql"if [ -f "${DB_SQL_SOURCE_PATH}" ]; thencp "${DB_SQL_SOURCE_PATH}" "${DB_SQL_DEST_PATH}"echo "✅ db.sql 已从 ${DB_SQL_SOURCE_PATH} 复制到 ${DB_SQL_DEST_PATH}"
elseecho "⚠️ 未在 ${DB_SQL_SOURCE_PATH} 找到 db.sql。"echo "👉 请手动将你的数据库初始化脚本 (例如 db.sql) 命名为 init.sql 并放置在 ${MAIN_PROJECT_DIR}/${DB_INIT_DIR}/ 目录下。"echo " MySQL 容器启动时会自动执行 /docker-entrypoint-initdb.d/init.sql"
fi# 8. 生成 docker-compose.yml 文件
echo "📝 生成 docker-compose.yml 文件..."
cat << EOF > "docker-compose.yml"
version: '3.8'services:backend:build:context: ./${BACKEND_DIR} # 构建上下文指向克隆的后端代码目录dockerfile: Dockerfile # Dockerfile 在该目录的根下container_name: my-springboot-appports:- "8080:8080"environment:- SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/${MYSQL_DATABASE}?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC- SPRING_DATASOURCE_USERNAME=${MYSQL_USER}- SPRING_DATASource_PASSWORD=${MYSQL_PASSWORD}- SPRING_JPA_HIBERNATE_DDL_AUTO=update # 或 validate, none (如果完全依赖 db.sql)depends_on:db:condition: service_healthynetworks:- my-app-networkfrontend:build:context: ./${FRONTEND_DIR} # 构建上下文指向克隆的前端代码目录dockerfile: Dockerfile # Dockerfile 在该目录的根下container_name: my-react-appports:- "80:80"depends_on:- backendnetworks:- my-app-networkdb:image: mysql:8.0container_name: my-mysql-dbrestart: unless-stoppedenvironment:MYSQL_DATABASE: ${MYSQL_DATABASE}MYSQL_USER: ${MYSQL_USER}MYSQL_PASSWORD: ${MYSQL_PASSWORD}MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}volumes:- mysql_data_volume:/var/lib/mysql- ./${DB_INIT_DIR}/init.sql:/docker-entrypoint-initdb.d/init.sql # 挂载初始化脚本healthcheck:test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost", "-u\${MYSQL_USER}", "-p\${MYSQL_PASSWORD}"]interval: 10stimeout: 5sretries: 5start_period: 30snetworks:- my-app-networknetworks:my-app-network:driver: bridgevolumes:mysql_data_volume: # 数据卷名称
EOF
echo "✅ docker-compose.yml 生成完毕。"# 9. (可选,如果需要 .env 文件管理敏感信息)
# echo "📝 (可选) 生成 .env 文件..."
# cat << ENV_EOF > ".env"
# MYSQL_DATABASE=${MYSQL_DATABASE}
# MYSQL_USER=${MYSQL_USER}
# MYSQL_PASSWORD=${MYSQL_PASSWORD}
# MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
# SPRING_DATASOURCE_USERNAME=${MYSQL_USER}
# SPRING_DATASOURCE_PASSWORD=${MYSQL_PASSWORD}
# ENV_EOF
# echo "✅ .env 文件已生成。你可以在 docker-compose.yml 中使用 \${VARIABLE_NAME} 引用这些变量。"
# echo " 例如: MYSQL_USER=\${MYSQL_USER_ENV} (并在 .env 中定义 MYSQL_USER_ENV)"
# echo " 注意:如果使用 .env 文件,请确保 .env 文件不被提交到 Git 仓库 (添加到 .gitignore)。"# 10. 构建并启动 Docker Compose 服务
echo "🐳 构建并启动 Docker 服务 (docker-compose up -d --build)..."
docker-compose up -d --buildif [ $? -eq 0 ]; thenecho "🎉 项目部署成功!"echo "前端应用应该可以通过 http://localhost 访问 (如果80端口未被占用)"echo "后端应用应该可以通过 http://localhost:8080 访问 (如果8080端口未被占用)"echo "MySQL 数据库正在运行,但通常不直接从外部访问。"echo "使用 'docker-compose logs -f' 查看日志。"echo "使用 'docker-compose down' 停止服务。"
elseecho "❌ Docker Compose 启动失败。请查看上面的错误日志。"
fiecho "🚀 部署脚本执行完毕。"
如何使用脚本
- 保存脚本: 将上面的代码复制并粘贴到一个新文件中,例如
setup_and_deploy.sh
。 - 修改配置:
- 最重要: 打开
setup_and_deploy.sh
文件,将BACKEND_REPO_URL
和FRONTEND_REPO_URL
的值修改为你自己后端和前端项目的实际 GitHub 仓库 URL。 - (可选)你可以修改脚本顶部的
MYSQL_DATABASE
,MYSQL_USER
,MYSQL_PASSWORD
,MYSQL_ROOT_PASSWORD
等变量。强烈建议为生产环境或任何共享环境使用更安全的密码,并考虑使用.env
文件来管理这些敏感信息,而不是直接写在脚本里。 (脚本中已注释掉生成.env
的部分,你可以按需启用)。
- 最重要: 打开
- 授予执行权限: 在终端中,进入脚本所在的目录,然后运行: Bash
chmod +x setup_and_deploy.sh
- 运行脚本: Bash
./setup_and_deploy.sh
脚本执行流程详解
- 创建主目录: 脚本首先创建一个名为
my_fullstack_app_deployed
(或你自定义的MAIN_PROJECT_DIR
) 的主目录,并进入该目录。之后的所有操作都在这个主目录内进行。 - 克隆代码:
- 它会检查是否存在
backend
和frontend
子目录。如果存在,会先删除它们,以确保是从一个干净的状态开始克隆最新的代码。 - 然后使用
git clone
从你提供的 URL 克隆后端和前端项目的代码到各自的backend
和frontend
目录中。
- 它会检查是否存在
- 生成 Dockerfile:
- 后端: 在
backend
目录(即克隆下来的后端代码根目录)下生成一个Dockerfile
。这个Dockerfile
用于构建 Spring Boot 应用。 - 前端: 在
frontend
目录(即克隆下来的前端代码根目录)下生成一个Dockerfile
。这个Dockerfile
用于构建 React 应用并准备 Nginx。
- 后端: 在
- 生成 Nginx 配置: 在
frontend
目录下生成nginx.conf
文件,供前端 Dockerfile 中的 Nginx 使用。 - 处理
db.sql
:- 创建一个
db_init
目录。 - 脚本会尝试从后端克隆下来的代码的
src/main/resources/db.sql
路径复制db.sql
文件到db_init/init.sql
。 - 如果找不到
db.sql
(例如路径不同或文件不存在),脚本会提示你手动将数据库初始化脚本命名为init.sql
并放到db_init
目录下。MySQL 容器启动时会自动执行这个目录下的.sql
文件。
- 创建一个
- 生成
docker-compose.yml
: 在主项目录 (my_fullstack_app_deployed
) 下生成docker-compose.yml
文件。这个文件定义了backend
,frontend
, 和db
三个服务。backend
和frontend
服务的build.context
分别指向./backend
和./frontend
目录,这样 Docker Compose 就会在这些目录中查找Dockerfile
并构建镜像。- MySQL 服务会挂载
db_init/init.sql
来初始化数据库。
- 一键部署: 最后,脚本执行
docker-compose up -d --build
。--build
: 强制 Docker Compose 重新构建镜像(因为代码和 Dockerfile 都是新生成的)。-d
: 在后台分离模式下运行容器。
- 输出结果: 脚本会输出部署是否成功,以及如何访问应用和管理服务。
现在,你只需要配置好脚本顶部的仓库 URL,然后运行这个脚本,就可以实现从代码克隆到服务部署的全过程了!
相关文章:
一键化部署
好的,我明白了。你希望脚本变得更简洁,主要负责: 代码克隆:从 GitHub 克隆你的后端和前端项目,并在克隆前确保目标目录为空。文件复制:将你预先准备好的 Dockerfile (后端和前端各一个)、前端的 nginx.con…...
Win 系统 conda 如何配置镜像源
通过命令添加镜像源(推荐) 以 清华源 为例,依次执行以下命令: # 添加主镜像源 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main # 添加免费开源镜像源 conda config --add channels http…...

Devicenet主转Profinet网关助力改造焊接机器人系统智能升级
某汽车零部件焊接车间原有6台焊接机器人(采用Devicenet协议)需与新增的西门子S7-1200 PLC(Profinet协议)组网。若更换所有机器人控制器或上位机系统,成本过高且停产周期长。 《解决方案》 工程师选择稳联技术转换网关…...

《STL--list的使用及其底层实现》
引言: 上次我们学习了容器vector的使用及其底层实现,今天我们再来学习一个容器list, 这里的list可以参考我们之前实现的单链表,但是这里的list是双向循环带头链表,下面我们就开始list的学习了。 一:list的…...
whisper相关的开源项目 (asr)
基于 Whisper(OpenAI 的开源语音识别模型)的开源项目有很多,涵盖了不同应用场景和优化方向。以下是一些值得关注的项目: 1. 核心工具 & 增强版 Whisper OpenAI Whisper 由 OpenAI 开源的通用语音识别模型,支持多语…...

python的pip怎么配置的国内镜像
以下是配置pip国内镜像源的详细方法: 常用国内镜像源列表 清华大学:https://pypi.tuna.tsinghua.edu.cn/simple阿里云:https://mirrors.aliyun.com/pypi/simple中科大:https://pypi.mirrors.ustc.edu.cn/simple华为云࿱…...

PCB 通孔是电容性的,但不一定是电容器
哼?……这是什么意思?…… 多年来,流行的观点是 PCB 通孔本质上是电容性的,因此可以用集总电容器进行建模。虽然当信号的上升时间大于或等于过孔不连续性延迟的 3 倍时,这可能是正确的,但我将向您展示为什…...
领域驱动设计与COLA框架:从理论到实践的落地之路
目录 引言 DDD核心概念 什么是领域驱动设计 DDD的核心概念 1. 统一语言(Ubiquitous Language) 2. 限界上下文(Bounded Context) 3. 实体(Entity)与值对象(Value Object) 4. 聚…...

公有云AWS基础架构与核心服务:从概念到实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 (初学者技术专栏) 一、基础概念 定义:AWS(Amazon Web Services)是亚马逊提供的云计算服务&a…...

Python60日基础学习打卡D35
import torch import torch.nn as nn import torch.optim as optim from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.preprocessing import MinMaxScaler import time import matplotlib.pyplot as plt# 设置GPU设…...
Python经典算法实战
在编程的世界里,算法是解决问题的灵魂,而Python以其简洁优雅的语法成为实现算法的理想语言。无论你是初学者还是有一定经验的开发者,《Python经典算法实战》都能带你深入算法的殿堂,从理论到实践,一步步构建起扎实的编…...
spring+tomcat 用户每次发请求,tomcat 站在线程的角度是如何处理用户请求的,spinrg的bean 是共享的吗
对于 springtomcat 用户每次发请求,tomcat 站在线程的角度是如何处理的 比如 bio nio apr 等情况 tomcat 配置文件中 maxThreads 的数量是相对于谁来说的? 以及 spring Controller 中的全局变量:各种bean 对于线程来说是共享的吗? 一、Tomca…...

目标检测 RT-DETR(2023)详细解读
文章目录 主干网络:Encoder:不确定性最小Query选择Decoder网络: 将DETR扩展到实时场景,提高了模型的检测速度。网络架构分为三部分组成:主干网络、混合编码器、带有辅助预测头的变换器编码器。具体来说,先利…...

微信小程序 隐私协议弹窗授权
开发微信小程序的第一步往往是隐私协议授权,尤其是在涉及用户隐私数据时,必须确保用户明确知晓并同意相关隐私政策。我们才可以开发后续的小程序内容。友友们在按照文档开发时可能会遇到一些问题,我把所有的授权方法和可能遇到的问题都整理出…...
题目 3325: 蓝桥杯2025年第十六届省赛真题-2025 图形
题目 3325: 蓝桥杯2025年第十六届省赛真题-2025 图形 时间限制: 2s 内存限制: 192MB 提交: 494 解决: 206 题目描述 小蓝要画一个 2025 图形。图形的形状为一个 h w 的矩形,其中 h 表示图形的高,w 表示图形的宽。当 h 5,w 10 时,图形如下所…...

金众诚业财一体化解决方案如何提升项目盈利能力?
在工程项目管理领域,复杂的全生命周期管理、成本控制的精准性以及业务与财务的高效协同,是决定项目盈利能力的核心要素。随着数字化转型的深入,传统的项目管理方式已难以满足企业对效率、透明度和盈利能力的需求。基于金蝶云星空平台打造的金…...
bitbar环境搭建(ruby 2.4 + rails 5.0.2)
此博客为武汉大学WA学院网络安全课程,理论课大作业Web环境搭建。 博主搭了2天!!!血泪教训是还是不能太相信ppt上的教程。 一开始尝试了ppt上的教程,然后又转而寻找网络资源 cs155源代码和docker配置,做到…...
从零起步搭建基于华为云构建碳排放设备管理系统的产品设计
目录 🌿 华为云 IoT:轻松上手碳排放设备管理系统搭建 🌍 逐步搭建搭建规划 🚀 一、系统蓝图:5大核心模块,循序渐进 1️⃣ 设备管理与数据采集层 2️⃣ 数据传输与协议转换层 3️⃣ 数据处理与分析层…...

LabVIEW中EtherCAT从站拓扑离线创建及信息查询
该 VI 主要用于演示如何离线创建 EtherCAT 从站拓扑结构,并查询从站相关信息。EtherCAT(以太网控制自动化技术)是基于以太网的实时工业通信协议,凭借其高速、高效的特性在自动化领域广泛应用。与其他常见工业通讯协议相比…...
SpringBoot-11-基于注解和XML方式的SpringBoot应用场景对比
文章目录 1 基于注解的方式1.1 @Mapper1.2 @select1.3 @insert1.4 @update1.5 @delete2 基于XML的方式2.1 namespace2.2 resultMap2.3 select2.4 insert2.5 update2.6 delete3 service和controller3.1 service3.2 controller4 注解和xml的选择如果SQL简单且项目规模较小,推荐使…...

Flutter 3.32 新特性
2天前,Flutter发布了最新版本3.32,我们来一起看下29到32有哪些变化。 简介 欢迎来到Flutter 3.32!此版本包含了旨在加速开发和增强应用程序的功能。准备好在网络上进行热加载,令人惊叹的原生保真Cupertino,以及与Fir…...
前端面试热门知识点总结
URL从输入到页面展示的过程 版本1 1.用户在浏览器的地址栏输入访问的URL地址。浏览器会先根据这个URL查看浏览器缓存-系统缓存-路由器缓存,若缓存中有,直接跳到第6步操作,若没有,则按照下面的步骤进行操作。 2.浏览器根据输入的UR…...

windows和mac安装虚拟机-详细教程
简介 虚拟机:Virtual Machine,虚拟化技术的一种,通过软件模拟的、具有完整硬件功能的、运行在一个完全隔离的环境中的计算机。 在学习linux系统的时候,需要安装虚拟机,在虚拟机上来运行操作系统,因为我使…...
【Hive 开发进阶】窗口函数深度解析:OVER/NTILE/RANK 实战案例与行转列高级技巧
一、窗口函数 OVER 详解 窗口函数用于在分组内进行数据排名、聚合计算等操作,语法格式: 函数名() over([partition by 分组字段] [order by 排序字段] [window子句])案例:员工信息与部门平均工资 create table emp (id int,dept string,sa…...
在STM32上配置图像处理库
在STM32上配置并使用简单的图像滤波库(以实现均值滤波为例,不依赖复杂的大型图像处理库,方便理解和在资源有限的STM32上运行)为例,给出代码示例,使用STM32CubeIDE开发环境和HAL库,假设已经初始化好了相关GPIO和DMA(如果有图像数据传输需求),并且图像数据存储在一个二…...

【C++】vector容器实现
目录 一、vector的成员变量 二、vector手动实现 (1)构造 (2)析构 (3)尾插 (4)扩容 (5)[ ]运算符重载 5.1 迭代器的实现: (6&…...
RocketMQ 深度解析:消息中间件核心原理与实践指南
一、RocketMQ 概述 1.1 什么是 RocketMQ RocketMQ 是阿里巴巴开源的一款分布式消息中间件,后捐赠给 Apache 基金会成为顶级项目。它具有低延迟、高并发、高可用、高可靠等特点,广泛应用于订单交易、消息推送、流计算、IoT 等场景。 1.2 核心特性 高吞…...

使用Docker Compose部署Dify
目录 1. 克隆项目代码2. 准备配置文件3. 配置环境变量4. 启动服务5. 验证部署6. 访问服务注意事项 1. 克隆项目代码 首先,克隆Dify项目的1.4.0版本: git clone https://github.com/langgenius/dify.git --branch 1.4.02. 准备配置文件 进入docker目录…...
基于 Vue3 与 exceljs 实现自定义导出 Excel 模板
在开发中,我们需要常常为用户提供更多的数据录入方式,Excel 模板导出与导入是一个常见的功能点。本文将介绍如何使用 Vue3、exceljs 和 file-saver 实现一个自定义导出 Excel 模板,并在特定列添加下拉框选择的数据验证功能。 技术选型 excelj…...

杰发科技AC7840——CSE硬件加密模块使用(1)
1. 简介 2. 功能概述 3. 简单的代码分析 测试第二个代码例程 初始化随机数 这里的CSE_CMD_RND在FuncID中体现了 CSE_SECRET_KEY在17个用户KEY中体现 最后的读取RNG值,可以看出计算结果在PRAM中。 总的来看 和示例说明一样,CSE 初次使用,添加…...