# CI/CD 部署指南 (OneDev + Docker Compose) ## 1. 简介 本文档旨在指导如何为 `mqtt-charging-system` 项目(包含 `springboot-init-main` 后端和 `charging_web_app` 前端)配置一套基于 OneDev 和 Docker Compose 的持续集成与持续部署 (CI/CD) 流程。实现目标是当代码提交到 OneDev 内置 Git 仓库的特定分支后,自动触发 OneDev 流水线,该流水线负责在部署服务器上构建应用 Docker 镜像,并使用 Docker Compose 重启包括数据库、MQTT Broker 和应用在内的所有服务。 **采用技术栈:** * **CI/CD 平台与代码仓库**: OneDev (自建,包含内置 Git 服务) * **构建与部署脚本**: `.onedev-buildspec.yml` (OneDev 流水线定义) * **容器化**: Docker * **服务编排**: Docker Compose * **部署目标**: 运行 OneDev Agent 和 Docker 的 Linux 服务器 ## 2. 先决条件 在开始配置此部署流程之前,请确保以下条件已满足: * **OneDev 服务器**: * 已在一台服务器上成功安装并运行 OneDev 服务。参考 OneDev 官方文档 ([https://onedev.io/docs/installation](https://onedev.io/docs/installation)) 进行安装。 * OneDev 服务器应具有足够的资源(CPU、内存、磁盘)。 * **线上应用/部署服务器 (OneDev Agent 服务器)**: * 一台 Linux 服务器,用于运行 OneDev Agent、构建 Docker 镜像以及通过 Docker Compose 运行所有服务容器 (数据库、Broker、后端、前端)。此服务器可以是 OneDev 服务器本身(不推荐用于生产),也可以是独立的机器。 * 服务器已安装 Docker Engine, Docker Compose, 和 Git。 * 服务器防火墙已配置,允许访问应用所需端口(例如后端 7529,前端 3000,MQTT 1883, 18083 等),以及 OneDev Agent 与 OneDev Server 通信的端口。 * **对 Docker, Docker Compose, Git, YAML 和 OneDev 有基本了解**。 ## 3. CI/CD 流程概览 1. **代码提交**: 开发者将代码改动推送到 OneDev 内置 Git 仓库的 `master` 分支 (或其他配置的触发分支)。 2. **OneDev 流水线触发**: OneDev 检测到其内置仓库的变更,根据 `.onedev-buildspec.yml` 中的定义触发相应的流水线。 3. **Agent 执行作业**: OneDev Server 将流水线中的作业分配给匹配的 Agent (运行在部署服务器上)。 4. **流水线执行 (`.onedev-buildspec.yml`)**: * **检出代码**: Agent 从仓库拉取最新的代码。 * **构建应用 Docker 镜像**: Agent 在本地构建后端和前端应用的新 Docker 镜像 (例如 `mqtt-springboot-app:latest`, `mqtt-nextjs-app:latest`)。 * **准备 `.env` 文件**: Agent 从 OneDev 项目配置的 Secrets 中获取敏感数据 (如数据库密码),并生成 `.env` 文件。 * **重启服务**: Agent 使用项目中的 `docker-compose.yml` 和新生成的 `.env` 文件,通过 `docker-compose` 命令停止旧服务,并基于新的镜像和配置启动所有服务。 5. **监控与日志**: 开发者可以在 OneDev 的 Web 界面上实时监控流水线执行状态、查看各步骤的详细日志。 ## 4. 详细步骤 ### 步骤 4.1: OneDev 服务器安装与配置 1. **安装 OneDev**: * 访问 OneDev 官方文档 ([https://onedev.io/docs/installation](https://onedev.io/docs/installation)),选择适合您环境的安装方法 (例如 Docker 运行,或直接部署 WAR 包)。 * **强烈建议使用 Docker 运行 OneDev Server**,方便管理和升级。官方文档提供了 Docker 命令示例。 * 确保 OneDev 数据持久化配置正确。 2. **初始化 OneDev**: 首次访问 OneDev URL,按照向导完成管理员账户设置和基本配置。 ### 步骤 4.2: OneDev Agent 安装与配置 (在部署服务器上) OneDev Agent 负责执行流水线中定义的作业。您可以选择直接在部署服务器上运行 Agent (通过 `java -jar agent.jar ...`),或者更推荐的方式是 **通过 Docker 容器运行 Agent**。您已确认使用 Docker 容器运行 Agent。 1. **登录 OneDev**: 使用管理员账户登录您的 OneDev 服务器。 2. **导航到 Agents 管理页面**: 通常在 `Administration` -> `Agents` (或者新版可能是 `Administration` -> `Job Executors`)。 3. **连接新 Agent/Executor 指引**: OneDev 界面会提供如何连接新 Agent/Executor 的指引。选择 "Connect an agent by running agent docker container" (或类似描述)。 4. **运行 Agent Docker 容器 (在部署服务器上)**: * OneDev 会提供一个 `docker run` 命令示例,类似如下 (请从您的 OneDev 界面复制准确命令,它会包含特定的服务器 URL 和 Agent 令牌): ```bash docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v :/opt/onedev/agent ``` * **关键参数解释**: * `--rm`: 容器停止后自动删除 (可选,但常用于 Agent)。 * `-v /var/run/docker.sock:/var/run/docker.sock`: **非常重要 (Docker-out-of-Docker - DooD)**。这将宿主机的 Docker socket 挂载到 Agent 容器内部。这使得 Agent 容器可以控制宿主机的 Docker daemon 来执行 Docker 命令 (例如 `docker build`, `docker-compose up`)。我们当前的 `.onedev-buildspec.yml` 依赖此设置来在宿主机本地构建镜像和运行 Docker Compose。 * `-v :/opt/onedev/agent` (或 OneDev 推荐的其他挂载点): 用于持久化 Agent 的配置和工作数据。例如,您可以设置为 `-v /opt/onedev_agent_data:/opt/onedev/agent`。 * ``: OneDev 官方提供的 Agent Docker 镜像,例如 `1dev/agent` 或 `onedev/agent` (请参考 OneDev 界面的准确镜像名称)。 * `` 和 ``: 由您的 OneDev 服务器提供,用于 Agent 连接和认证。 * **Agent 容器所需的工具**: * OneDev 官方的 Agent 镜像通常已包含 `git`。 * 为了执行 `.onedev-buildspec.yml` 中的 `docker-compose` 命令,您需要确保 Agent 使用的 Docker 镜像**内部也包含 `docker-compose` CLI** (或者较新版本的 `docker compose` 插件)。如果官方 Agent 镜像不包含,您可能需要: * 在 `.onedev-buildspec.yml` 的 `executeShell` 步骤开始前,先在 Agent 容器内安装 `docker-compose`。 * 或者,构建一个自定义的 Agent Docker 镜像,该镜像基于 OneDev 官方 Agent 镜像,并额外安装 `docker-compose`。 * 或者,修改 `.onedev-buildspec.yml` 中的命令为 `docker compose` (注意空格),如果 Agent 容器的 Docker CLI 支持 Compose V2 插件。 * 我们当前的 `.onedev-buildspec.yml` 中的 `executeShell` 使用 `docker-compose` (带连字符)。 5. **为 Agent 添加标签**: * Agent Docker 容器启动并成功连接到 OneDev Server 后,它会出现在 OneDev 的 Agents/Executors 列表中。 * 点击该 Agent/Executor,进入其配置页面,添加一个标签,例如 `agent-for-mqtt-power`。这个标签将用于 `.onedev-buildspec.yml` 中的 `agentMatcher`,以确保作业在此 Agent 上运行。 6. **确保宿主机 Docker 环境**: Agent 容器通过 DooD 控制宿主机的 Docker,所以确保部署服务器(宿主机)上已正确安装和配置了 Docker Engine 和 Docker Compose (如果 `docker-compose.yml` 依赖于宿主机上的 `docker-compose` CLI 版本特性)。 7. **持久化运行 Agent Docker 容器 (推荐)**: * 为了确保 Agent 在服务器重启后也能自动运行,建议使用 Docker 的重启策略或通过 `systemd` 管理 Agent Docker 容器的启动。 * **使用 Docker 重启策略**: 在 `docker run` 命令中添加 `--restart unless-stopped` 或 `--restart always`。 ```bash docker run --restart unless-stopped --name onedev-agent-mqtt -d \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /opt/onedev_agent_data_mqtt:/opt/onedev/agent \ ``` * `--name onedev-agent-mqtt`: 为容器指定一个名称,方便管理。 * `-d`: 后台运行容器。 * **通过 systemd 管理 (更灵活,但略复杂)**: 您可以创建一个 systemd 服务单元来启动和管理这个 Agent Docker 容器。 * 示例 (`/etc/systemd/system/onedev-agent-docker.service`): ```ini [Unit] Description=OneDev Agent Docker Container Requires=docker.service After=docker.service [Service] Restart=always ExecStartPre=-/usr/bin/docker stop onedev-agent-mqtt ExecStartPre=-/usr/bin/docker rm onedev-agent-mqtt ExecStart=/usr/bin/docker run --name onedev-agent-mqtt \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /opt/onedev_agent_data_mqtt:/opt/onedev/agent \ ExecStop=/usr/bin/docker stop onedev-agent-mqtt [Install] WantedBy=multi-user.target ``` * **重要**: 替换占位符。确保路径和镜像是正确的。 * 然后 `sudo systemctl daemon-reload`, `sudo systemctl start onedev-agent-docker`, `sudo systemctl enable onedev-agent-docker`。 ### 步骤 4.3: 在 OneDev 中创建项目并配置 Secrets 1. **创建项目**: * 登录 OneDev,点击 `+ New Project`。 * 填写项目名称 (例如 `mqtt-charging-system`)。 * **代码库**: * 选择 `Create an empty repository` (如果您想在 OneDev 中开始一个全新的项目,并将 `master` 作为默认分支) 或 `Import from an existing repository` (如果您想将现有的 Git 仓库——例如本地的或之前 Gitea 上的,其主分支为 `master`——导入到 OneDev 中进行管理)。**本项目将使用 OneDev 内置的 Git 服务。** * (可选) 配置项目的默认分支为 `master` (如果通过导入创建且需要更改,或新建时指定)。 2. **配置项目 Secrets**: 这些 Secrets 将被 `.onedev-buildspec.yml` 用于生成 `.env` 文件。 * 进入项目 -> `Settings` -> `Secrets`。 * 点击 `New Secret`。 * 为每个需要的敏感信息创建一个 Secret。**确保 Secret 名称与 `.onedev-buildspec.yml` 中 `@secrets.@` 的 `` 部分完全一致**。 * `MYSQL_ROOT_PASSWORD`: 您的 MySQL root 密码。 * `MYSQL_DATABASE`: 数据库名称 (例如 `mqtt_power`)。 * `MYSQL_USER`: 应用连接数据库的用户名 (例如 `appuser`)。 * `MYSQL_PASSWORD`: 应用连接数据库的密码。 * (可选) `EMQX_ADMIN_PASSWORD`: 如果 EMQX 需要管理密码。 * 勾选 `Available to all branches` (除非您有特定分支的特殊需求,例如只允许 `master` 分支的构建访问生产密码)。 * 确保这些 Secrets **不允许在构建日志中显示**。 ### 步骤 4.4: 将项目代码和配置文件推送到仓库 1. 确保您的项目代码已克隆/推送到 OneDev 内置的 Git 仓库中,并且根目录包含以下文件: * **`.onedev-buildspec.yml`**: (已创建) 定义 CI/CD 流水线。 * **`docker-compose.yml`**: (已创建和修改) 定义所有服务,应用镜像使用本地构建名称。 * **`springboot-init-main/Dockerfile`**: (已创建) 用于构建后端镜像。 * **`charging_web_app/Dockerfile`**: (已创建) 用于构建前端镜像。 * **`springboot-init-main/src/main/resources/application.yml`**: (已修改) 数据库和 MQTT 连接信息通过环境变量配置。 2. 将这些文件提交并推送到 OneDev 内置 Git 仓库的 `master` 分支。 ### 步骤 4.5: 触发与监控部署 1. **触发构建**: * 当您向 OneDev 内置仓库的 `master` 分支 (或其他在 OneDev 项目构建设置中配置的触发分支) 推送代码时,OneDev 应该会自动触发 `.onedev-buildspec.yml` 中定义的流水线。 * 您也可以在 OneDev 项目的 `Builds` 页面手动触发特定分支 (如 `master`) 的构建。 2. **监控构建**: * 在 OneDev 项目的 `Builds` 页面,您可以看到正在运行和已完成的构建列表。 * 点击特定的构建,可以查看其详细步骤、可视化流程、以及每个步骤的实时日志输出。 * 如果构建失败,日志中会包含错误信息,帮助您排查问题。 3. **验证部署**: 构建成功完成后,在部署服务器上: * 使用 `docker ps -a` 查看所有容器的状态。 * 使用 `docker-compose logs -f ` (在 Agent 的工作区项目目录下) 或 `docker logs ` 查看各服务日志。 * 尝试访问您的前端和后端应用。 ## 5. `.onedev-buildspec.yml` 文件详解 (关键点) (已在之前创建,此处为回顾和说明) * **`version: 8`**: 指定 buildspec 的版本。 * **`jobs`**: 定义一个或多个作业。 * **`name`**: 作业的名称。 * **`agentMatcher`**: 指定运行此作业的 Agent 必须拥有的标签 (例如 `agent-for-mqtt-power`)。 * **`steps`**: 作业中执行的步骤。 * **`checkout`**: 检出代码到 Agent 的工作区。 * **`setupVariables`**: 定义变量,可以引用 Secrets (`@secrets.MySecret@`) 或其他 OneDev 内置变量 (`@commit_hash@` 等)。 * **`buildImage`**: OneDev 内置步骤,用于构建 Docker 镜像。 * `dockerfile`: Dockerfile 的路径。 * `imageName`, `imageTag`: 构建的镜像名称和标签。 * `buildPath`: Docker build context 路径。 * **`writeFile`**: 将内容写入 Agent 工作区的文件 (例如生成 `.env` 文件)。 * **`executeShell`**: 执行 shell 命令 (例如 `docker-compose up -d`)。 * **`dependencies`**: 定义作业之间的依赖关系 (例如,部署作业依赖于构建作业)。 * **`triggers`**: 定义触发作业的条件 (例如,特定路径的文件变更、其他作业成功等)。 ## 6. 回滚策略 * **重新运行旧的成功构建**: OneDev 保存了所有构建的历史记录。如果新部署出现问题,您可以找到上一个基于 `master` 分支的成功部署构建,并点击 "Rebuild" (或类似选项) 来重新运行该构建,从而回滚到之前的状态。 * **代码回滚并触发新构建**: 在 Git 中将 `master` 分支的代码回滚到某个稳定版本,然后推送到 OneDev,OneDev 将会基于旧代码重新构建和部署。 * **(如果镜像打了 commit hash 标签)**: 如果您的镜像标签包含 commit hash (例如 `@commit_hash@`变量),并且您知道某个稳定版本的 commit hash,理论上可以手动修改部署服务器上的 `docker-compose.yml` (或通过 OneDev 参数化构建传递镜像标签) 来指向旧镜像并重启,但这通常不如通过 OneDev 流水线管理方便。 ## 7. 注意事项与常见问题 * **Agent 资源与权限**: 确保 OneDev Agent 运行的用户有足够的权限(特别是 Docker 命令执行权限)和系统资源(CPU, 内存, 磁盘空间)来完成构建和部署任务。 * **Secrets 管理**: 严格管理 OneDev 中的 Secrets,不要在日志中暴露它们。 * **`.onedev-buildspec.yml` 语法**: YAML 格式对缩进敏感,编写时需注意。 * **Docker 构建上下文**: `buildImage` 步骤中的 `buildPath` 很重要,它决定了 Docker 构建时的上下文环境。 * **网络配置**: 确保 OneDev Server, OneDev Agent, 以及部署服务器上的 Docker 容器之间网络通畅。 * **首次构建**: 第一次触发构建时,请密切关注 OneDev 中的日志,以便快速定位和解决可能出现的配置问题。 * **日志**: OneDev 提供了非常详细的构建日志,是排查问题的首要工具。 --- 本文档提供了使用 OneDev (及其内置 Git 服务) 和 Docker Compose 配置 CI/CD 的框架。OneDev 提供了强大的可视化管理和流水线定义能力,可以显著简化部署流程的管理和监控。