mqtt消息记录优化,控制台页面样式优化
This commit is contained in:
134
.onedev-buildspec.yml
Normal file
134
.onedev-buildspec.yml
Normal file
@@ -0,0 +1,134 @@
|
||||
jobs:
|
||||
# --- 后端 Spring Boot 应用作业 ---
|
||||
- name: "Backend CI/CD"
|
||||
executor: "docker-executor"
|
||||
triggers:
|
||||
- type: "branch-push"
|
||||
branches: "main"
|
||||
paths: "springboot-init-main/**"
|
||||
steps:
|
||||
- checkout
|
||||
- group: "Build Backend JAR"
|
||||
steps:
|
||||
- image: "maven:3.8-openjdk-8"
|
||||
shell: "sh"
|
||||
commands: |
|
||||
echo "Building Spring Boot JAR..."
|
||||
cd springboot-init-main
|
||||
mvn clean package -DskipTests -B
|
||||
- group: "Publish Backend Docker Image"
|
||||
steps:
|
||||
- shell: "sh"
|
||||
commands: |
|
||||
echo "Logging in to Docker Registry..."
|
||||
echo $env.get(\'DOCKER_PASSWORD\') | docker login -u $env.get(\'DOCKER_USER\') --password-stdin $env.get(\'DOCKER_REGISTRY\', \'docker.io\')
|
||||
|
||||
echo "Building and Pushing Backend Docker Image..."
|
||||
cd springboot-init-main
|
||||
IMAGE_NAME="${env.get(\'DOCKER_REGISTRY\', \'docker.io\')}/your-docker-repo/mqtt-springboot-app"
|
||||
docker build -t ${IMAGE_NAME}:latest -t ${IMAGE_NAME}:$(echo \"@file:job.commitHash@\" | cut -c1-8) .
|
||||
docker push ${IMAGE_NAME}:latest
|
||||
docker push ${IMAGE_NAME}:$(echo \"@file:job.commitHash@\" | cut -c1-8)
|
||||
|
||||
echo "Logging out from Docker Registry..."
|
||||
docker logout $env.get(\'DOCKER_REGISTRY\', \'docker.io\')
|
||||
|
||||
# --- 前端 Next.js 应用作业 ---
|
||||
- name: "Frontend CI/CD"
|
||||
executor: "docker-executor"
|
||||
triggers:
|
||||
- type: "branch-push"
|
||||
branches: "main"
|
||||
paths: "charging_web_app/**"
|
||||
steps:
|
||||
- checkout
|
||||
- group: "Build Frontend App"
|
||||
steps:
|
||||
- image: "node:18-alpine"
|
||||
shell: "sh"
|
||||
commands: |
|
||||
echo "Building Next.js App..."
|
||||
cd charging_web_app
|
||||
npm ci
|
||||
npm run build
|
||||
- group: "Publish Frontend Docker Image"
|
||||
steps:
|
||||
- shell: "sh"
|
||||
commands: |
|
||||
echo "Logging in to Docker Registry..."
|
||||
echo $env.get(\'DOCKER_PASSWORD\') | docker login -u $env.get(\'DOCKER_USER\') --password-stdin $env.get(\'DOCKER_REGISTRY\', \'docker.io\')
|
||||
|
||||
echo "Building and Pushing Frontend Docker Image..."
|
||||
cd charging_web_app
|
||||
IMAGE_NAME="${env.get(\'DOCKER_REGISTRY\', \'docker.io\')}/your-docker-repo/mqtt-nextjs-app"
|
||||
docker build -t ${IMAGE_NAME}:latest -t ${IMAGE_NAME}:$(echo \"@file:job.commitHash@\" | cut -c1-8) .
|
||||
docker push ${IMAGE_NAME}:latest
|
||||
docker push ${IMAGE_NAME}:$(echo \"@file:job.commitHash@\" | cut -c1-8)
|
||||
|
||||
echo "Logging out from Docker Registry..."
|
||||
docker logout $env.get(\'DOCKER_REGISTRY\', \'docker.io\')
|
||||
|
||||
# --- 统一应用部署作业 ---
|
||||
# 这个作业会在任一应用(后端或前端)成功构建并推送镜像后触发
|
||||
# 或者也可以配置为仅在特定条件下手动触发,或依赖于两个镜像都构建完成
|
||||
- name: "Deploy All Services"
|
||||
executor: "docker-executor" # 或一个配置了 SSH client 的 Shell executor
|
||||
# 触发器:这里用了一个手动触发的例子,或者可以依赖于前两个job的完成
|
||||
# triggers:
|
||||
# - type: "manual"
|
||||
# 或者更复杂的依赖触发,例如当 backend 和 frontend 的镜像都推送到特定tag后
|
||||
# 此处简化,假设在 backend 和 frontend CI/CD job 成功后可以手动触发或自动链式触发 (OneDev支持Job依赖)
|
||||
# 如果希望在每次后端或前端更新后都自动部署,可以将此部署逻辑合并到各自的CI/CD作业末尾,
|
||||
# 但要注意并发部署可能导致的问题,以及只更新变化部分的需求。
|
||||
# 为简单起见,这里假设这是一个独立的部署步骤,手动或通过上游作业触发。
|
||||
# 如果要自动触发,可以设置 dependsOn: ["Backend CI/CD", "Frontend CI/CD"] 并调整触发逻辑
|
||||
steps:
|
||||
- checkout # 获取最新的 docker-compose.yml (如果它在仓库中)
|
||||
- group: "Deploy Services to Server"
|
||||
steps:
|
||||
- shell: "sh"
|
||||
# Secrets needed: SERVER_SSH_KEY, SERVER_HOST, SERVER_SSH_USER, DEPLOY_PATH
|
||||
# Secrets for .env file: MYSQL_ROOT_PASSWORD_SECRET, MYSQL_DATABASE_SECRET, MYSQL_USER_SECRET, MYSQL_PASSWORD_SECRET
|
||||
commands: |
|
||||
echo "Preparing deployment to Server..."
|
||||
echo "Creating .env file for docker-compose..."
|
||||
# 从 OneDev Job Secrets 生成 .env 文件内容
|
||||
# 注意:这里的 $env.get 语法和可用性取决于 OneDev Executor 环境
|
||||
# 确保 OneDev Secrets 名称与此处使用的 get() 中的名称一致
|
||||
# 确保 shell 对多行字符串和特殊字符的处理是正确的
|
||||
ENV_CONTENT=""
|
||||
ENV_CONTENT="${ENV_CONTENT}MYSQL_ROOT_PASSWORD=\"${env.get('MYSQL_ROOT_PASSWORD_SECRET')}\"\n"
|
||||
ENV_CONTENT="${ENV_CONTENT}MYSQL_DATABASE=\"${env.get('MYSQL_DATABASE_SECRET')}\"\n"
|
||||
ENV_CONTENT="${ENV_CONTENT}MYSQL_USER=\"${env.get('MYSQL_USER_SECRET')}\"\n"
|
||||
ENV_CONTENT="${ENV_CONTENT}MYSQL_PASSWORD=\"${env.get('MYSQL_PASSWORD_SECRET')}\"\n"
|
||||
# 添加其他 docker-compose.yml 中需要的环境变量,例如 EMQX 相关的 (如果需要密码)
|
||||
# ENV_CONTENT="${ENV_CONTENT}EMQX_ADMIN_PASSWORD=\"${env.get('EMQX_ADMIN_PASSWORD_SECRET')}\"\n"
|
||||
|
||||
echo "Connecting to server and deploying..."
|
||||
# 将 SSH 私钥写入临时文件
|
||||
mkdir -p ~/.ssh
|
||||
echo "$env.get(\'SERVER_SSH_KEY\')" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
|
||||
# 1. 将生成的 .env 文件内容发送到服务器的部署目录
|
||||
# 2. 将仓库中的 docker-compose.yml (如果已检出) 发送到服务器或确保服务器上有最新版本
|
||||
# 3. 执行 docker-compose 命令
|
||||
# 注意: scp 和 ssh 命令中的路径和用户需要正确配置
|
||||
# DEPLOY_PATH 是服务器上的 /opt/deploy/mqtt-charging-system
|
||||
# @workspace@ 是 OneDev executor 中的工作目录,包含了检出的代码
|
||||
|
||||
# 创建一个包含 .env 内容的临时文件以便 scp
|
||||
echo -e "${ENV_CONTENT}" > env_for_server.env
|
||||
|
||||
# 复制 .env 文件和 docker-compose.yml 到服务器
|
||||
# 假设 docker-compose.yml 在仓库根目录
|
||||
scp -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa env_for_server.env $env.get(\'SERVER_SSH_USER\')@$env.get(\'SERVER_HOST\'):$env.get(\'DEPLOY_PATH\')/.env
|
||||
scp -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa @workspace@/docker-compose.yml $env.get(\'SERVER_SSH_USER\')@$env.get(\'SERVER_HOST\'):$env.get(\'DEPLOY_PATH\')/docker-compose.yml
|
||||
|
||||
# 在服务器上执行 docker-compose 命令
|
||||
ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa $env.get(\'SERVER_SSH_USER\')@$env.get(\'SERVER_HOST\') \
|
||||
"cd $env.get(\'DEPLOY_PATH\') && docker-compose down --remove-orphans && docker-compose pull && docker-compose up -d"
|
||||
|
||||
echo "Deployment process initiated on server."
|
||||
# 清理 executor 中的临时 .env 文件
|
||||
rm env_for_server.env
|
||||
312
DEPLOYMENT_GUIDE.md
Normal file
312
DEPLOYMENT_GUIDE.md
Normal file
@@ -0,0 +1,312 @@
|
||||
# CI/CD 部署指南 (OneDev + Docker)
|
||||
|
||||
## 1. 简介
|
||||
|
||||
本文档旨在指导如何为 `mqtt-charging-system` 项目(包含 `springboot-init-main` 后端和 `charging_web_app` 前端)配置一套基于 OneDev 和 Docker 的持续集成与持续部署 (CI/CD) 流程。实现目标是当代码提交到 OneDev 管理的 Git 仓库的特定分支(如 `main`)后,自动触发构建、 Docker 镜像打包与推送,并最终自动部署到线上服务器。
|
||||
|
||||
**采用技术栈:**
|
||||
|
||||
* **一体化 DevOps 平台 (代码仓库, CI/CD)**: OneDev
|
||||
* **容器化**: Docker & Docker Compose
|
||||
* **部署目标**: 运行 Docker 的 Linux 服务器
|
||||
|
||||
## 2. 先决条件
|
||||
|
||||
在开始配置 CI/CD 流程之前,请确保以下条件已满足:
|
||||
|
||||
* **OneDev 服务器**:
|
||||
* 已成功搭建并运行 OneDev 服务。您可以从 [https://onedev.io/](https://onedev.io/) 下载并按照官方文档进行安装(通常作为 Docker 容器或直接运行 JAR 包)。
|
||||
* 项目代码已在 OneDev 中创建或导入。
|
||||
* **线上应用服务器**:
|
||||
* 一台或多台 Linux 服务器,用于运行前端和后端应用容器。
|
||||
* 服务器已安装 Docker Engine 和 Docker Compose。
|
||||
* 服务器具有 SSH 访问权限,并为 CI/CD 工具准备了 SSH 用户(推荐使用密钥认证)。OneDev 的执行器 (Executor) 将通过此用户连接服务器。
|
||||
* 服务器防火墙已配置,允许访问应用所需端口(例如后端 7529,前端 3000)以及可能的反向代理端口(如 80, 443)。
|
||||
* **Docker 镜像仓库**:
|
||||
* 一个 Docker Registry 用于存储构建好的应用镜像。可以是:
|
||||
* Docker Hub (公共或私有)
|
||||
* OneDev 自带的容器镜像仓库 (如果 OneDev 版本支持并已启用,或者通过插件)
|
||||
* Harbor, Quay.io 等私有化部署的 Registry
|
||||
* 云服务商提供的 Registry (如阿里云 ACR, AWS ECR, Google GCR)
|
||||
* 准备好访问该 Registry 的凭证 (用户名和密码/Access Token)。这些凭证将作为 Secrets 配置在 OneDev 中。
|
||||
* **域名 (可选但推荐)**: 为您的 OneDev 服务器和应用准备域名,并配置好 DNS 解析。
|
||||
* **对 Docker 和 Linux 基本命令有了解**。
|
||||
|
||||
## 3. CI/CD 流程概览
|
||||
|
||||
1. **代码提交**: 开发者将代码改动推送到 OneDev 仓库的指定分支 (例如 `main`)。
|
||||
2. **构建触发**: OneDev 自动检测到代码变更,并根据项目根目录下的 `.onedev-buildspec.yml` 文件中定义的触发器 (Triggers) 和作业 (Jobs) 启动构建流程。
|
||||
3. **作业执行**: OneDev 的执行器 (Executor) 根据构建规范执行定义的作业步骤:
|
||||
* **代码检出**: 执行器自动检出指定提交的代码。
|
||||
* **应用构建**:
|
||||
* **后端 (`springboot-init-main`)**: 使用 Maven 构建工具 (如 `mvn package`) 打包成 JAR 文件。
|
||||
* **前端 (`charging_web_app`)**: 使用 Node.js 和 npm/yarn (如 `npm run build`) 构建生产版本的静态文件和 Next.js 服务。
|
||||
* **Docker 镜像构建与推送**:
|
||||
* 使用项目中的 `Dockerfile` 构建 Docker 镜像。
|
||||
* 构建成功后,将镜像标记版本号并推送到指定的 Docker 镜像仓库。
|
||||
* **应用部署**:
|
||||
* 通过 SSH 连接到线上应用服务器。
|
||||
* 在服务器上执行预设脚本(通常是 Docker Compose 命令)来拉取新镜像并重启服务。
|
||||
4. **完成与反馈**: 构建完成后,OneDev 界面会显示构建状态、日志和产物。可以配置通知。
|
||||
|
||||
## 4. 详细步骤
|
||||
|
||||
### 步骤 4.1: 服务器环境准备
|
||||
|
||||
(此部分与之前 Gitea+Drone CI 指南中的服务器准备基本一致,请确保应用服务器满足 Docker, Docker Compose 和 SSH 的要求。OneDev 服务器自身的安装请参考官方文档。)
|
||||
|
||||
1. **选择并配置 Linux 服务器 (应用服务器)**:
|
||||
* 建议使用主流 Linux 发行版,如 Ubuntu, CentOS。
|
||||
* 确保服务器资源充足(CPU, 内存, 磁盘空间)。
|
||||
* **内存建议 (测试环境,OneDev 和应用分开部署或合并部署,不考虑高并发)**:
|
||||
* **OneDev 服务器**: OneDev 自身运行(特别是包含 Elasticsearch 用于搜索)可能需要 **2GB-4GB RAM** 或更多,具体取决于仓库数量、用户数和活动情况。请参考 OneDev 官方的资源建议。
|
||||
* **应用服务器 (仅运行后端和前端应用容器)**: **2GB RAM** 通常足够。
|
||||
* **单服务器部署 (OneDev Server, 执行器, 后端应用, 前端应用均在同一台机器)**: 由于 OneDev 自身和构建过程的资源消耗,推荐至少 **4GB-8GB RAM**。具体数值高度依赖 OneDev 的负载和构建任务的复杂度。对于纯测试且OneDev负载不高的情况,4GB可能是底限。
|
||||
* 如果服务器内存确实有限,需要严格控制各进程的内存使用,并可能遇到性能瓶颈或OOM问题。
|
||||
2. **安装 Docker Engine (应用服务器)**: (同前)
|
||||
3. **安装 Docker Compose (应用服务器)**: (同前)
|
||||
4. **配置 SSH (应用服务器)**:
|
||||
* 确保 SSH 服务正在运行。
|
||||
* 为 OneDev 执行器创建一个专用的 SSH 用户,或使用现有用户。
|
||||
* **强烈推荐使用 SSH 密钥对进行认证**。私钥将作为 Secret 配置在 OneDev 中,用于部署作业。
|
||||
* 在可以安全操作的地方生成 SSH 密钥对。
|
||||
* 将公钥 (`~/.ssh/id_rsa.pub`) 内容添加到应用服务器上对应用户的 `~/.ssh/authorized_keys` 文件中。
|
||||
* 确保 `.ssh` 目录权限为 `700`,`authorized_keys` 文件权限为 `600`。
|
||||
5. **防火墙配置 (应用服务器)**: (同前)
|
||||
|
||||
### 步骤 4.2: OneDev 服务器安装与配置 (简述)
|
||||
|
||||
* **安装 OneDev**: 请遵循 OneDev 官方网站 ([https://onedev.io/](https://onedev.io/)) 的最新安装指南。常见的安装方式包括:
|
||||
* **Docker 容器**: 这是推荐且较简单的方式。官方会提供 `docker run` 命令或 `docker-compose.yml` 示例。
|
||||
* **直接运行 JAR**: 下载 `server-bootstrap.jar` 并运行。
|
||||
* **初始配置**: 安装完成后,首次访问 OneDev 服务会引导进行管理员账户创建和基本配置。
|
||||
* **项目创建/导入**: 在 OneDev 中创建您的 `mqtt-charging-system` 项目,或从其他 Git 源导入。
|
||||
* **执行器 (Executor) 配置**: OneDev 需要配置执行器来运行构建作业。默认情况下可能有一个内置的 Docker Executor,但您也可以配置远程服务器作为 Shell Executor (通过 SSH) 或 Kubernetes Executor。对于 Docker 构建和 SSH 部署,确保执行器有能力运行 Docker 命令和 SSH 命令。
|
||||
* 如果 OneDev 服务器自身资源充足且安装了 Docker,可以使用其内置的 Docker Executor。
|
||||
* 如果希望在专门的构建机或应用服务器上执行某些部署步骤,可能需要配置 Server Shell Executor 或 Agent Shell Executor,并确保这些执行环境安装了必要的工具 (如 `docker-compose`, `ssh client`)。
|
||||
|
||||
### 步骤 4.3: 项目 Docker化
|
||||
|
||||
(此部分与之前指南中的 Dockerfile 内容保持不变,因为 Dockerfile 本身与 CI/CD 工具无关。)
|
||||
|
||||
* **`springboot-init-main/Dockerfile`**: (同前)
|
||||
* **`charging_web_app/Dockerfile`**: (同前)
|
||||
|
||||
### 步骤 4.4: OneDev 构建规范配置 (`.onedev-buildspec.yml`)
|
||||
|
||||
在您的 OneDev 项目 (`mqtt-charging-system`) 的根目录下创建 `.onedev-buildspec.yml` 文件 (或者通过 OneDev UI 配置构建规范)。
|
||||
|
||||
```yaml
|
||||
# .onedev-buildspec.yml
|
||||
|
||||
# 定义构建作业 (Jobs)
|
||||
jobs:
|
||||
# --- 后端 Spring Boot 应用作业 ---
|
||||
- name: "Backend CI/CD"
|
||||
# 执行器选择:指定一个有能力运行 Maven 和 Docker 命令的执行器
|
||||
# 这通常是一个配置了 Docker-in-Docker 或可以访问 Docker socket 的 Docker Executor
|
||||
# 或者是一个安装了 Maven 和 Docker 的 Shell Executor
|
||||
executor: "docker-executor" # 替换为你在 OneDev 中配置的执行器名称
|
||||
# 触发器:当 main 分支有代码提交,且 springboot-init-main 目录下文件发生变化时触发
|
||||
triggers:
|
||||
- type: "branch-push"
|
||||
branches: "main"
|
||||
paths: "springboot-init-main/**"
|
||||
# 构建步骤 (Steps)
|
||||
steps:
|
||||
# 1. 检出代码 (通常是隐式的,或由 OneDev 自动处理第一步)
|
||||
- checkout # OneDev 内置的检出步骤
|
||||
|
||||
# 2. 构建 Spring Boot JAR
|
||||
- group: "Build Backend JAR"
|
||||
steps:
|
||||
- image: "maven:3.8-openjdk-8" # 使用 Maven Docker 镜像执行命令
|
||||
shell: "sh"
|
||||
commands: |
|
||||
echo "Building Spring Boot JAR..."
|
||||
cd springboot-init-main
|
||||
mvn clean package -DskipTests -B
|
||||
|
||||
# 3. 构建并推送后端 Docker 镜像
|
||||
- group: "Publish Backend Docker Image"
|
||||
steps:
|
||||
# 使用 OneDev 内置的 Docker Build & Push 命令 (或手动 docker 命令)
|
||||
# 假设 executor 有 docker cli
|
||||
- shell: "sh"
|
||||
# 需要将 Docker Hub 凭证配置为 Job Secrets: DOCKER_USER, DOCKER_PASSWORD
|
||||
# 以及 Docker 仓库地址: DOCKER_REGISTRY (可选, 默认 docker.io)
|
||||
commands: |
|
||||
echo "Logging in to Docker Registry..."
|
||||
echo $env.get(\'DOCKER_PASSWORD\') | docker login -u $env.get(\'DOCKER_USER\') --password-stdin $env.get(\'DOCKER_REGISTRY\', \'docker.io\')
|
||||
|
||||
echo "Building and Pushing Backend Docker Image..."
|
||||
cd springboot-init-main
|
||||
IMAGE_NAME="${env.get(\'DOCKER_REGISTRY\', \'docker.io\')}/your-docker-repo/mqtt-springboot-app"
|
||||
# 使用 @file:job.commitHash 获取当前提交的短哈希
|
||||
docker build -t ${IMAGE_NAME}:latest -t ${IMAGE_NAME}:$(echo \"@file:job.commitHash@\" | cut -c1-8) .
|
||||
docker push ${IMAGE_NAME}:latest
|
||||
docker push ${IMAGE_NAME}:$(echo \"@file:job.commitHash@\" | cut -c1-8)
|
||||
|
||||
echo "Logging out from Docker Registry..."
|
||||
docker logout $env.get(\'DOCKER_REGISTRY\', \'docker.io\')
|
||||
# OneDev 提供了更集成的 Docker 构建步骤,可以研究使用以简化脚本
|
||||
# - build-docker-image: ... (参考 OneDev 文档)
|
||||
# - push-docker-image: ... (参考 OneDev 文档)
|
||||
|
||||
# 4. 部署后端到服务器
|
||||
- group: "Deploy Backend to Server"
|
||||
steps:
|
||||
- shell: "sh"
|
||||
# 需要将 SSH 私钥配置为 Job Secret: SERVER_SSH_KEY
|
||||
# 以及服务器地址: SERVER_HOST, SSH用户: SERVER_SSH_USER
|
||||
# 服务器部署路径: BACKEND_DEPLOY_PATH (例如 /opt/deploy/mqtt-charging-system/backend)
|
||||
commands: |
|
||||
echo "Deploying Backend to Server..."
|
||||
mkdir -p ~/.ssh
|
||||
echo "$env.get(\'SERVER_SSH_KEY\')" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh -o StrictHostKeyChecking=no $env.get(\'SERVER_SSH_USER\')@$env.get(\'SERVER_HOST\') \
|
||||
"cd $env.get(\'BACKEND_DEPLOY_PATH\') && docker-compose pull backend-app && docker-compose up -d --remove-orphans backend-app"
|
||||
echo "Backend deployment completed."
|
||||
|
||||
# --- 前端 Next.js 应用作业 ---
|
||||
- name: "Frontend CI/CD"
|
||||
executor: "docker-executor" # 替换为合适的执行器
|
||||
triggers:
|
||||
- type: "branch-push"
|
||||
branches: "main"
|
||||
paths: "charging_web_app/**"
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
# 2. 构建 Next.js 应用
|
||||
- group: "Build Frontend App"
|
||||
steps:
|
||||
- image: "node:18-alpine"
|
||||
shell: "sh"
|
||||
commands: |
|
||||
echo "Building Next.js App..."
|
||||
cd charging_web_app
|
||||
npm ci
|
||||
npm run build
|
||||
|
||||
# 3. 构建并推送前端 Docker 镜像
|
||||
- group: "Publish Frontend Docker Image"
|
||||
steps:
|
||||
- shell: "sh"
|
||||
commands: |
|
||||
echo "Logging in to Docker Registry..."
|
||||
echo $env.get(\'DOCKER_PASSWORD\') | docker login -u $env.get(\'DOCKER_USER\') --password-stdin $env.get(\'DOCKER_REGISTRY\', \'docker.io\')
|
||||
|
||||
echo "Building and Pushing Frontend Docker Image..."
|
||||
cd charging_web_app
|
||||
IMAGE_NAME="${env.get(\'DOCKER_REGISTRY\', \'docker.io\')}/your-docker-repo/mqtt-nextjs-app"
|
||||
docker build -t ${IMAGE_NAME}:latest -t ${IMAGE_NAME}:$(echo \"@file:job.commitHash@\" | cut -c1-8) .
|
||||
docker push ${IMAGE_NAME}:latest
|
||||
docker push ${IMAGE_NAME}:$(echo \"@file:job.commitHash@\" | cut -c1-8)
|
||||
|
||||
echo "Logging out from Docker Registry..."
|
||||
docker logout $env.get(\'DOCKER_REGISTRY\', \'docker.io\')
|
||||
|
||||
# 4. 部署前端到服务器
|
||||
- group: "Deploy Frontend to Server"
|
||||
steps:
|
||||
- shell: "sh"
|
||||
commands: |
|
||||
echo "Deploying Frontend to Server..."
|
||||
mkdir -p ~/.ssh
|
||||
echo "$env.get(\'SERVER_SSH_KEY\')" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh -o StrictHostKeyChecking=no $env.get(\'SERVER_SSH_USER\')@$env.get(\'SERVER_HOST\') \
|
||||
"cd $env.get(\'FRONTEND_DEPLOY_PATH\') && docker-compose pull frontend-app && docker-compose up -d --remove-orphans frontend-app"
|
||||
echo "Frontend deployment completed."
|
||||
|
||||
# 可以定义参数 (Parameters) 和属性 (Properties) 以供作业使用
|
||||
# parameters:
|
||||
# properties:
|
||||
```
|
||||
* **重要说明**:
|
||||
* 上述 `.onedev-buildspec.yml` 是一个示例,具体语法和可用步骤请务必参考您正在使用的 OneDev 版本的官方文档。
|
||||
* `executor`: 指定运行此作业的 OneDev 执行器。您需要在 OneDev 中预先配置好执行器 (例如 Docker Executor, Shell Executor)。
|
||||
* `triggers`: 定义了何时触发此作业。
|
||||
* `steps`: 定义了作业的具体操作。OneDev 有很多内置的步骤类型 (如 `checkout`, `setup-jdk`, `run-docker-command`, `build-docker-image`, `ssh-command-step` 等),使用内置步骤通常比手写 shell 脚本更简洁和安全。**强烈建议查阅 OneDev 文档,使用其推荐的步骤来操作 Docker 和 SSH。**
|
||||
* **Secrets/Variables**:
|
||||
* `$env.get('SECRET_NAME')` 或 `$get('job_secret_name')` (具体语法看OneDev版本) 用于从 OneDev 作业 Secrets 中获取敏感信息 (如 `DOCKER_USER`, `DOCKER_PASSWORD`, `SERVER_SSH_KEY`)。
|
||||
* `your-docker-repo` 需要替换为您的 Docker 仓库名/组织名。
|
||||
* `SERVER_HOST`, `SERVER_SSH_USER`, `BACKEND_DEPLOY_PATH`, `FRONTEND_DEPLOY_PATH` 等也应该是作为 Job Secrets 或 Parameters 传入。
|
||||
* `@file:job.commitHash@` 是 OneDev 提供的一个变量,用于获取当前构建的 Git 提交哈希。
|
||||
* **错误处理与健壮性**: 实际脚本中应添加错误检查和更完善的日志。
|
||||
* **OneDev 内置步骤**: 对于 Docker 构建/推送和 SSH 命令执行,OneDev 提供了专门的步骤类型,使用它们会比直接写 `shell` 命令更方便,并能更好地处理凭证和输出。例如,有专门的 `Push to Docker Registry` 步骤,可以直接配置仓库、凭证等。
|
||||
|
||||
### 步骤 4.5: 服务器部署配置 (Docker Compose)
|
||||
|
||||
在您的应用服务器上,创建一个部署根目录(例如 `/opt/deploy/mqtt-charging-system/`),并在该目录下放置一个统一的 `docker-compose.yml` 文件。这个文件将管理所有服务,包括数据库、MQTT Broker 以及您的后端和前端应用。
|
||||
|
||||
* **统一的 `docker-compose.yml` (示例路径: `/opt/deploy/mqtt-charging-system/docker-compose.yml`)**:
|
||||
* 该文件的内容已在本指南前文(或作为单独文件)提供。它应包含 `mysql-db`, `emqx`, `backend-app`, 和 `frontend-app` 服务。
|
||||
* 确保 `backend-app` 和 `frontend-app` 服务中的 `image` 指向您在 CI/CD 流程中构建和推送到 Docker Registry 的镜像地址。
|
||||
* 通过 `environment` 部分为 `backend-app` 注入数据库连接信息(如 `DB_HOST: mysql-db`, `DB_USER`, `DB_PASSWORD`, `DB_NAME`)和 MQTT Broker 信息 (`MQTT_BROKER_URL: tcp://emqx:1883`),使其连接到 Compose 网络内的相应服务。
|
||||
* MySQL 和 EMQX 的敏感配置(如密码)应通过环境变量从外部(例如服务器上的 `.env` 文件或 CI 工具注入的环境变量)设置,而不是硬编码在 `docker-compose.yml` 的默认值中。
|
||||
|
||||
### 步骤 4.6: OneDev Secrets 管理
|
||||
|
||||
OneDev 提供了强大的 Secrets 管理功能,用于安全地存储 CI/CD 流程中所需的敏感信息。
|
||||
|
||||
1. 打开 OneDev 上的 `mqtt-charging-system` 项目。
|
||||
2. 导航到项目 `设置` (Settings) -> `构建设置` (Build Settings) -> `作业密秘` (Job Secrets)。
|
||||
3. 点击 `添加密秘` (Add Secret) 来创建以下 Secrets (名称需与 `.onedev-buildspec.yml` 中引用的名称一致):
|
||||
* `DOCKER_USER`: 你的 Docker 镜像仓库的用户名。
|
||||
* `DOCKER_PASSWORD`: 你的 Docker 镜像仓库的密码或 Access Token (标记为密码类型)。
|
||||
* `SERVER_SSH_KEY`: 部署服务器的 SSH 私钥内容 (标记为文件类型或多行文本)。
|
||||
* `SERVER_HOST`: 部署服务器的 IP 地址或主机名。
|
||||
* `SERVER_SSH_USER`: 用于 SSH 连接的用户名。
|
||||
* `DEPLOY_PATH`: 应用在服务器上的统一部署路径 (例如 `/opt/deploy/mqtt-charging-system`).
|
||||
* `DOCKER_REGISTRY` (可选): 如果不是 Docker Hub,则为您的 Docker 仓库地址 (例如 `gitea.yourdomain.com:5000`)。
|
||||
* **新增Secrets (用于 `docker-compose.yml` 中的数据库和Broker)**:
|
||||
* `MYSQL_ROOT_PASSWORD_SECRET`: MySQL root用户的密码。
|
||||
* `MYSQL_DATABASE_SECRET`: 数据库名称 (例如 `mqtt_power`)。
|
||||
* `MYSQL_USER_SECRET`: 应用连接数据库的用户名 (例如 `appuser`)。
|
||||
* `MYSQL_PASSWORD_SECRET`: 应用连接数据库的密码。
|
||||
* (如果 EMQX 需要认证,则添加相应 Secrets)
|
||||
4. **授权**: 确保这些 Secrets 仅被授权给需要它们的构建作业或分支访问。
|
||||
|
||||
**注意**: 在 `.onedev-buildspec.yml` 的部署脚本中,您需要一种方式将这些 Secrets (如 `MYSQL_ROOT_PASSWORD_SECRET`) 传递给部署服务器,以便 `docker-compose up` 命令可以访问它们作为环境变量。这可以通过以下几种方式实现:
|
||||
* **通过 SSH 动态创建 `.env` 文件**: 在 SSH 部署脚本中,从 OneDev Secrets 读取值,并在部署目录动态生成一个 `.env` 文件,`docker-compose` 会自动加载它。
|
||||
* **直接在 `docker-compose up` 命令前导出环境变量**: `export MYSQL_ROOT_PASSWORD=$env.get('MYSQL_ROOT_PASSWORD_SECRET'); docker-compose up -d` (这种方式环境变量仅对当前 SSH 会话的该命令有效,需要小心处理引号和转义)。
|
||||
* OneDev 可能有更高级的方法来处理部署时的环境变量注入,请查阅其文档。
|
||||
|
||||
### 步骤 4.7: (移除/简化 Gitea Webhook 配置)
|
||||
|
||||
由于 OneDev 是一体化平台,它会自动监控其管理的 Git 仓库的变更。当符合 `.onedev-buildspec.yml` 中定义的 `triggers` 条件时,构建会自动触发。因此,不需要像 Gitea+Drone CI 那样手动配置外部 Webhook。
|
||||
|
||||
## 5. 部署触发与监控
|
||||
|
||||
* **触发**: 当所有配置完成后,向 OneDev 项目的 `main` 分支(或其他在构建规范中配置的分支)推送代码提交,并且提交包含了相应目录 (`springboot-init-main/**` 或 `charging_web_app/**`) 的文件变更,将自动触发 OneDev 中定义的相应 CI/CD 作业。
|
||||
* **监控**:
|
||||
* 在 OneDev 界面,您可以进入项目的 `构建` (Builds) 标签页,实时查看构建列表、每个构建的详细步骤、日志、状态以及最终结果。
|
||||
* OneDev 允许配置构建完成后的通知 (例如 Email, Webhook 到其他系统等)。
|
||||
* 在应用服务器上,使用 `docker ps` 和 `docker logs` 进行容器监控。
|
||||
|
||||
## 6. 回滚策略 (简述)
|
||||
|
||||
(与之前类似,OneDev 也支持通过标签重新运行旧的构建,或手动部署旧的 Docker 镜像版本。)
|
||||
|
||||
* **手动回滚**:
|
||||
* 使用 OneDev 构建产出的 Docker 镜像标签 (例如基于 commit hash 的标签) 在服务器上手动通过 `docker-compose.yml` 指向旧版本并重启服务。
|
||||
* 在 OneDev 的构建历史中,找到上一个成功的部署构建,检查其使用的 commit,并可能基于该 commit 创建一个新的部署或重新运行(如果构建规范支持参数化部署特定版本)。
|
||||
* **自动化回滚 (高级)**: 可以在 `.onedev-buildspec.yml` 中设计更复杂的逻辑,例如部署后运行健康检查,如果失败则自动触发另一个作业来部署上一个稳定版本。
|
||||
|
||||
## 7. 注意事项与常见问题
|
||||
|
||||
* **Secrets 安全**: 严格管理 OneDev 中的 Job Secrets。特别注意部署到服务器时,如何安全地传递和使用 `docker-compose.yml` 所需的环境变量(如数据库密码)。
|
||||
* **`.onedev-buildspec.yml` 语法**: YAML 语法对缩进敏感。强烈建议使用 OneDev UI 内置的编辑器来编写或校验构建规范,它通常会提供语法高亮和提示。
|
||||
* **OneDev 执行器 (Executor)**: 正确配置和选择执行器至关重要。确保执行器有执行作业步骤所需的环境和权限 (如 Docker, Maven, Node.js, SSH客户端)。
|
||||
* **OneDev 文档**: **OneDev 功能迭代较快,本文档中的构建规范示例可能不是最新的或最优的。请务必参考您正在使用的 OneDev 版本的官方文档,特别是关于 CI/CD 步骤、变量和 Secrets 的部分。**
|
||||
* **路径与上下文**: 注意 OneDev 作业中执行命令时的工作目录。
|
||||
* **统一的 `docker-compose.yml`**: 确保所有服务定义正确,网络配置允许服务间通信,卷的挂载用于持久化数据。
|
||||
* **环境变量注入**: 仔细规划如何在部署时将 OneDev Job Secrets 安全地传递给 `docker-compose.yml` 使用的环境变量。避免在版本控制中存储包含敏感默认值的 `.env` 文件。
|
||||
* **(其他注意事项与之前类似,如 Dockerfile 优化, 权限, 网络, 资源消耗, 首次手动部署验证, 日志调试, 版本控制, 依赖缓存, Monorepo 策略, 数据库迁移等,这些普适性的CI/CD原则依然适用。)**
|
||||
|
||||
---
|
||||
|
||||
本文档提供了使用 OneDev 配置 CI/CD 的基础框架。根据实际需求和 OneDev 的具体版本功能,您可能需要调整和扩展这些步骤。
|
||||
124
docker-compose.yml
Normal file
124
docker-compose.yml
Normal file
@@ -0,0 +1,124 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# MySQL Database Service
|
||||
mysql-db:
|
||||
image: mysql:8.0
|
||||
container_name: mqtt_mysql_db
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-supersecretpassword} # 请通过环境变量或OneDev Secrets在生产中设置此密码
|
||||
MYSQL_DATABASE: ${MYSQL_DATABASE:-mqtt_power}
|
||||
MYSQL_USER: ${MYSQL_USER:-appuser}
|
||||
MYSQL_PASSWORD: ${MYSQL_PASSWORD:-apppassword} # 请通过环境变量或OneDev Secrets在生产中设置此密码
|
||||
ports:
|
||||
# 仅在需要从外部直接访问数据库时暴露端口 (例如用于调试或外部工具)
|
||||
# 对于应用容器,它们将通过Docker内部网络连接
|
||||
- "33061:3306" # 示例:将容器的3306映射到主机的33061
|
||||
volumes:
|
||||
- mysql_data:/var/lib/mysql
|
||||
# 如果有初始化脚本,可以挂载:
|
||||
# - ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
networks:
|
||||
- app-network
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost", "-u$$MYSQL_USER", "-p$$MYSQL_PASSWORD"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
# EMQX MQTT Broker Service
|
||||
emqx:
|
||||
image: emqx/emqx:5.6.0 # 使用较新的 EMQX 5 版本
|
||||
container_name: mqtt_emqx_broker
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "1883:1883" # MQTT default port
|
||||
- "8083:8083" # MQTT over WebSocket
|
||||
- "8084:8084" # MQTT over SSL/TLS WebSocket
|
||||
- "8883:8883" # MQTT over SSL/TLS
|
||||
- "18083:18083" # EMQX Dashboard / HTTP API
|
||||
volumes:
|
||||
- emqx_data:/opt/emqx/data
|
||||
- emqx_log:/opt/emqx/log
|
||||
# 如果有自定义配置,可以挂载 emqx.conf 或 mounted_plugins 等
|
||||
# - ./emqx_conf/emqx.conf:/opt/emqx/etc/emqx.conf
|
||||
networks:
|
||||
- app-network
|
||||
healthcheck:
|
||||
test: ["CMD", "/opt/emqx/bin/emqx_ctl", "status"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
environment:
|
||||
EMQX_NODE_NAME: "emqx@node1.emqx.io" # 可以自定义节点名
|
||||
EMQX_LISTENER__TCP__EXTERNAL: "1883"
|
||||
EMQX_LISTENER__WS__EXTERNAL: "8083"
|
||||
EMQX_DASHBOARD__LISTENER__HTTP: "18083"
|
||||
# 更多 EMQX 配置可以通过环境变量设置,参考 EMQX 文档
|
||||
|
||||
# Backend Spring Boot Application Service
|
||||
backend-app:
|
||||
image: your-docker-registry/mqtt-springboot-app:latest # 将在 CI/CD 中构建和推送
|
||||
container_name: mqtt_springboot_app_prod
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
mysql-db: # 确保数据库先启动并健康
|
||||
condition: service_healthy
|
||||
emqx: # 确保 MQTT Broker 先启动并健康
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "7529:7529"
|
||||
environment:
|
||||
# Spring Boot Profile
|
||||
SPRING_PROFILES_ACTIVE: prod # 或者其他生产环境profile
|
||||
# Database connection (连接到此 compose 文件中的 mysql-db 服务)
|
||||
DB_HOST: mysql-db
|
||||
DB_PORT: 3306
|
||||
DB_NAME: ${MYSQL_DATABASE:-mqtt_power}
|
||||
DB_USER: ${MYSQL_USER:-appuser}
|
||||
DB_PASSWORD: ${MYSQL_PASSWORD:-apppassword} # 确保与 mysql-db 中 MYSQL_PASSWORD 一致
|
||||
# MQTT Broker connection (连接到此 compose 文件中的 emqx 服务)
|
||||
MQTT_BROKER_URL: tcp://emqx:1883
|
||||
# MQTT_USERNAME: # 如果 EMQX 设置了认证
|
||||
# MQTT_PASSWORD: # 如果 EMQX 设置了认证
|
||||
# 其他后端应用所需的环境变量
|
||||
# ...
|
||||
networks:
|
||||
- app-network
|
||||
# 如果需要,可以添加 healthcheck
|
||||
# healthcheck:
|
||||
# test: ["CMD", "curl", "-f", "http://localhost:7529/api/actuator/health"] # 假设有 actuator health 端点
|
||||
# interval: 30s
|
||||
# timeout: 10s
|
||||
# retries: 3
|
||||
|
||||
# Frontend Next.js Application Service
|
||||
frontend-app:
|
||||
image: your-docker-registry/mqtt-nextjs-app:latest # 将在 CI/CD 中构建和推送
|
||||
container_name: mqtt_nextjs_app_prod
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
# API 地址,指向后端服务的容器名和端口 (如果前端直接调用API)
|
||||
# 如果 Next.js 使用了 next.config.js/mjs 中的 rewrites 代理 /api 到后端,则这里可能不需要
|
||||
# NEXT_PUBLIC_API_URL: http://backend-app:7529/api
|
||||
# 如果前端需要连接 MQTT Broker (例如通过 WebSocket)
|
||||
NEXT_PUBLIC_MQTT_WS_URL: ws://emqx:8083/mqtt # 指向 EMQX 的 WebSocket 端口
|
||||
# 其他前端应用所需的环境变量
|
||||
# ...
|
||||
networks:
|
||||
- app-network
|
||||
depends_on: # 可选,如果前端启动时需要后端已启动
|
||||
- backend-app
|
||||
# - emqx # 如果前端直接依赖 MQTT Broker
|
||||
|
||||
volumes:
|
||||
mysql_data: # 持久化 MySQL 数据
|
||||
emqx_data: # 持久化 EMQX 数据
|
||||
emqx_log: # 持久化 EMQX 日志
|
||||
|
||||
networks:
|
||||
app-network:
|
||||
driver: bridge
|
||||
@@ -4,9 +4,9 @@ spring:
|
||||
# DataSource Config
|
||||
datasource:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://yuyun-us1.stormrain.cn:3306/mqtt_power?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
|
||||
username: root
|
||||
password: mysql_a4MQ4P
|
||||
url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:mqtt_power}?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
|
||||
username: ${DB_USER:root}
|
||||
password: ${DB_PASSWORD:your_default_db_password} # STRONG PASSWORD RECOMMENDED, to be overridden by env var
|
||||
mvc:
|
||||
pathmatch:
|
||||
matching-strategy: ANT_PATH_MATCHER
|
||||
@@ -51,9 +51,9 @@ logging:
|
||||
# MQTT Configurations
|
||||
# ===================================================================
|
||||
mqtt:
|
||||
broker-url: tcp://broker.emqx.io:1883
|
||||
username: # Public broker, no credentials specified for connection
|
||||
password: # Public broker, no credentials specified for connection
|
||||
broker-url: ${MQTT_BROKER_URL:tcp://broker.emqx.io:1883} # To be overridden by env var for local dockerized emqx
|
||||
username: ${MQTT_USERNAME:} # Public broker or to be set by env var
|
||||
password: ${MQTT_PASSWORD:} # Public broker or to be set by env var
|
||||
client-id-prefix: backend-yupi-mqtt-power- # Unique client ID prefix for our project
|
||||
default-qos: 1 # Default Quality of Service (0, 1, 2)
|
||||
connection-timeout: 30 # Connection timeout in seconds
|
||||
|
||||
Reference in New Issue
Block a user