diff --git a/.onedev-buildspec.yml b/.onedev-buildspec.yml index 60ab570..a560b1c 100644 --- a/.onedev-buildspec.yml +++ b/.onedev-buildspec.yml @@ -1,135 +1,68 @@ -version: 8 # OneDev Build Spec Version +version: 8 jobs: - # --- 后端 Spring Boot 应用作业 --- - - name: "Backend CI/CD" - executor: "docker-executor" + - name: Build and Deploy mqtt_power on myagent + agentMatcher: name_is("myagent") # 确保 "myagent" 是您 OneDev 中 agent 的确切名称 + # 如果 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: - - 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 \ No newline at end of file + - type: "BRANCH_UPDATE" # 当分支有代码推送时触发 + params: + branches: "main,master" # 监听的分支,请根据您的实际主分支名称修改 + # paths: # 可选:仅当特定路径下的文件发生变化时才触发 + # includes: + # - "springboot-init-main/**" + # - "charging_web_app/**" + # - "docker-compose.yml" + # - ".onedev-buildspec.yml" \ No newline at end of file diff --git a/LogBook.md b/LogBook.md index e29ea8d..bfe3b87 100644 --- a/LogBook.md +++ b/LogBook.md @@ -28,4 +28,20 @@ * `docker-compose.yml`:已修改,支持数据库自动初始化脚本挂载。 * `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),以及触发器分支的正确性。 + --- \ No newline at end of file