ci/cd
This commit is contained in:
@@ -1,135 +1,68 @@
|
|||||||
version: 8 # OneDev Build Spec Version
|
version: 8
|
||||||
jobs:
|
jobs:
|
||||||
# --- 后端 Spring Boot 应用作业 ---
|
- name: Build and Deploy mqtt_power on myagent
|
||||||
- name: "Backend CI/CD"
|
agentMatcher: name_is("myagent") # 确保 "myagent" 是您 OneDev 中 agent 的确切名称
|
||||||
executor: "docker-executor"
|
# 如果 myagent 是通过标签选择的,请使用类似 agentMatcher: has_tag("your-agent-tag") 的形式
|
||||||
|
steps:
|
||||||
|
- checkout # OneDev 会自动检出与触发事件相关的代码
|
||||||
|
- group: "Prepare Environment and Build"
|
||||||
|
steps:
|
||||||
|
- shell: "sh" # 或者 powershell -Command,取决于您的 agent 环境
|
||||||
|
# 如果 agent 是 Windows,并且您希望使用 PowerShell,请将 shell 改为 "powershell"
|
||||||
|
# 并在下面的 commands 中使用 PowerShell 语法
|
||||||
|
commands: |
|
||||||
|
echo "Running on agent: $ONEDEV_AGENT_NAME"
|
||||||
|
echo "Workspace: $ONEDEV_WORKSPACE"
|
||||||
|
|
||||||
|
echo "Generating .env file for Docker Compose..."
|
||||||
|
# 使用 get_job_secret 函数从 OneDev Job Secrets 获取值
|
||||||
|
# 确保在 OneDev 项目的 Job Secrets 中定义了这些 secret
|
||||||
|
echo "MYSQL_ROOT_PASSWORD=${get_job_secret('DB_ROOT_PASSWORD')}" > .env
|
||||||
|
echo "MYSQL_DATABASE=${get_job_secret('DB_NAME')}" >> .env
|
||||||
|
echo "MYSQL_USER=${get_job_secret('DB_USER')}" >> .env
|
||||||
|
echo "MYSQL_PASSWORD=${get_job_secret('DB_PASSWORD')}" >> .env
|
||||||
|
|
||||||
|
echo "SPRING_DATASOURCE_URL=jdbc:mysql://mysql-db:3306/${get_job_secret('DB_NAME')}?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false" >> .env
|
||||||
|
echo "SPRING_DATASOURCE_USERNAME=${get_job_secret('DB_USER')}" >> .env
|
||||||
|
echo "SPRING_DATASOURCE_PASSWORD=${get_job_secret('DB_PASSWORD')}" >> .env
|
||||||
|
|
||||||
|
echo "SPRING_MQTT_BROKER_HOST=emqx-broker" >> .env # docker-compose 服务名
|
||||||
|
echo "SPRING_MQTT_BROKER_PORT=1883" >> .env
|
||||||
|
echo "SPRING_MQTT_USERNAME=${get_job_secret('MQTT_USER')}" >> .env
|
||||||
|
echo "SPRING_MQTT_PASSWORD=${get_job_secret('MQTT_PASSWORD')}" >> .env
|
||||||
|
# 使用 $ONEDEV_BUILD_NUMBER 保证客户端 ID 唯一性
|
||||||
|
echo "SPRING_MQTT_CLIENT_ID_BACKEND=springboot-mqtt-client-backend-$ONEDEV_BUILD_NUMBER" >> .env
|
||||||
|
echo "SPRING_MQTT_LOG_CLIENT_ID=springboot-mqtt-log-client-$ONEDEV_BUILD_NUMBER" >> .env
|
||||||
|
|
||||||
|
echo ".env file generated."
|
||||||
|
# cat .env # 可选: 在构建日志中打印 .env 内容以供调试
|
||||||
|
|
||||||
|
echo "Ensuring docker-compose.yml is present..."
|
||||||
|
if [ ! -f docker-compose.yml ]; then
|
||||||
|
echo "ERROR: docker-compose.yml not found in workspace root ($ONEDEV_WORKSPACE/docker-compose.yml)!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Stopping existing services (if any)..."
|
||||||
|
docker-compose -f docker-compose.yml down --remove-orphans || echo "No services were running or an error occurred during down, continuing..."
|
||||||
|
|
||||||
|
echo "Building Docker images locally for springboot-app and nextjs-app..."
|
||||||
|
# 确保 docker-compose.yml 中的 build context 指向正确
|
||||||
|
# 例如: springboot-init-main 和 charging_web_app
|
||||||
|
docker-compose -f docker-compose.yml build --no-cache springboot-app nextjs-app
|
||||||
|
|
||||||
|
echo "Starting all services via Docker Compose..."
|
||||||
|
docker-compose -f docker-compose.yml up -d
|
||||||
|
|
||||||
|
echo "Deployment process finished."
|
||||||
|
docker-compose -f docker-compose.yml ps # 显示正在运行的服务状态
|
||||||
triggers:
|
triggers:
|
||||||
- type: "branch-push"
|
- type: "BRANCH_UPDATE" # 当分支有代码推送时触发
|
||||||
branches: "main"
|
params:
|
||||||
paths: "springboot-init-main/**"
|
branches: "main,master" # 监听的分支,请根据您的实际主分支名称修改
|
||||||
steps:
|
# paths: # 可选:仅当特定路径下的文件发生变化时才触发
|
||||||
- checkout
|
# includes:
|
||||||
- group: "Build Backend JAR"
|
# - "springboot-init-main/**"
|
||||||
steps:
|
# - "charging_web_app/**"
|
||||||
- image: "maven:3.8-openjdk-8"
|
# - "docker-compose.yml"
|
||||||
shell: "sh"
|
# - ".onedev-buildspec.yml"
|
||||||
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
|
|
||||||
16
LogBook.md
16
LogBook.md
@@ -28,4 +28,20 @@
|
|||||||
* `docker-compose.yml`:已修改,支持数据库自动初始化脚本挂载。
|
* `docker-compose.yml`:已修改,支持数据库自动初始化脚本挂载。
|
||||||
* `deploy.sh`:已被删除 (原 Gitea + 脚本方案的产物)。
|
* `deploy.sh`:已被删除 (原 Gitea + 脚本方案的产物)。
|
||||||
|
|
||||||
|
## 2024-08-13
|
||||||
|
|
||||||
|
* **调整 CI/CD 方案至 OneDev (本地构建)**:
|
||||||
|
* 用户反馈 OneDev builds 页面无内容,怀疑配置文件问题。
|
||||||
|
* 分析现有 `.onedev-buildspec.yml` 包含多个冲突的 Job 定义 (部分推送外部 registry,部分本地构建,部分通过 SSH 部署)。
|
||||||
|
* **决策**: 简化 `.onedev-buildspec.yml` 为单个 Job (`Build and Deploy mqtt_power on myagent`)。
|
||||||
|
* **新 Job 逻辑**:
|
||||||
|
1. 在用户指定的 OneDev Agent (`myagent`) 上运行。
|
||||||
|
2. 由 `main` 或 `master` 分支的代码推送触发。
|
||||||
|
3. 检出代码。
|
||||||
|
4. 从 OneDev Job Secrets 生成 `.env` 文件,包含数据库和 MQTT 连接信息。
|
||||||
|
5. 使用项目根目录的 `docker-compose.yml` 在 Agent 本地构建后端 (`springboot-app`) 和前端 (`nextjs-app`) Docker 镜像。
|
||||||
|
6. 使用 `docker-compose up -d` 启动所有服务 (MySQL, EMQX, 后端应用, 前端应用)。
|
||||||
|
* **操作**: 完全重写了 `.onedev-buildspec.yml` 以实现上述逻辑。
|
||||||
|
* 强调了用户需要检查 Agent 名称匹配、OneDev Job Secrets 配置、`docker-compose.yml` 的构建上下文和镜像名、Agent 环境(Docker, Docker Compose, sh/bash shell),以及触发器分支的正确性。
|
||||||
|
|
||||||
---
|
---
|
||||||
Reference in New Issue
Block a user