201 lines
16 KiB
Markdown
201 lines
16 KiB
Markdown
# 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 <path_to_agent_data_on_host>:/opt/onedev/agent <onedev_agent_image> <OneDev Server URL> <Agent Token>
|
||
```
|
||
* **关键参数解释**:
|
||
* `--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 <path_to_agent_data_on_host>:/opt/onedev/agent` (或 OneDev 推荐的其他挂载点): 用于持久化 Agent 的配置和工作数据。例如,您可以设置为 `-v /opt/onedev_agent_data:/opt/onedev/agent`。
|
||
* `<onedev_agent_image>`: OneDev 官方提供的 Agent Docker 镜像,例如 `1dev/agent` 或 `onedev/agent` (请参考 OneDev 界面的准确镜像名称)。
|
||
* `<OneDev Server URL>` 和 `<Agent Token>`: 由您的 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 \
|
||
<onedev_agent_image> <OneDev Server URL> <Agent Token>
|
||
```
|
||
* `--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 \
|
||
<onedev_agent_image> <OneDev Server URL> <Agent Token>
|
||
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.<SecretName>@` 的 `<SecretName>` 部分完全一致**。
|
||
* `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 <service_name>` (在 Agent 的工作区项目目录下) 或 `docker logs <container_name_or_id>` 查看各服务日志。
|
||
* 尝试访问您的前端和后端应用。
|
||
|
||
## 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 提供了强大的可视化管理和流水线定义能力,可以显著简化部署流程的管理和监控。 |