16 KiB
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) 进行安装。
- 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 流程概览
- 代码提交: 开发者将代码改动推送到 OneDev 内置 Git 仓库的
master分支 (或其他配置的触发分支)。 - OneDev 流水线触发: OneDev 检测到其内置仓库的变更,根据
.onedev-buildspec.yml中的定义触发相应的流水线。 - Agent 执行作业: OneDev Server 将流水线中的作业分配给匹配的 Agent (运行在部署服务器上)。
- 流水线执行 (
.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命令停止旧服务,并基于新的镜像和配置启动所有服务。
- 监控与日志: 开发者可以在 OneDev 的 Web 界面上实时监控流水线执行状态、查看各步骤的详细日志。
4. 详细步骤
步骤 4.1: OneDev 服务器安装与配置
- 安装 OneDev:
- 访问 OneDev 官方文档 (https://onedev.io/docs/installation),选择适合您环境的安装方法 (例如 Docker 运行,或直接部署 WAR 包)。
- 强烈建议使用 Docker 运行 OneDev Server,方便管理和升级。官方文档提供了 Docker 命令示例。
- 确保 OneDev 数据持久化配置正确。
- 初始化 OneDev: 首次访问 OneDev URL,按照向导完成管理员账户设置和基本配置。
步骤 4.2: OneDev Agent 安装与配置 (在部署服务器上)
OneDev Agent 负责执行流水线中定义的作业。您可以选择直接在部署服务器上运行 Agent (通过 java -jar agent.jar ...),或者更推荐的方式是 通过 Docker 容器运行 Agent。您已确认使用 Docker 容器运行 Agent。
-
登录 OneDev: 使用管理员账户登录您的 OneDev 服务器。
-
导航到 Agents 管理页面: 通常在
Administration->Agents(或者新版可能是Administration->Job Executors)。 -
连接新 Agent/Executor 指引: OneDev 界面会提供如何连接新 Agent/Executor 的指引。选择 "Connect an agent by running agent docker container" (或类似描述)。
-
运行 Agent Docker 容器 (在部署服务器上):
- OneDev 会提供一个
docker run命令示例,类似如下 (请从您的 OneDev 界面复制准确命令,它会包含特定的服务器 URL 和 Agent 令牌):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-composeCLI (或者较新版本的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(带连字符)。
- OneDev 官方的 Agent 镜像通常已包含
- OneDev 会提供一个
-
为 Agent 添加标签:
- Agent Docker 容器启动并成功连接到 OneDev Server 后,它会出现在 OneDev 的 Agents/Executors 列表中。
- 点击该 Agent/Executor,进入其配置页面,添加一个标签,例如
agent-for-mqtt-power。这个标签将用于.onedev-buildspec.yml中的agentMatcher,以确保作业在此 Agent 上运行。
-
确保宿主机 Docker 环境: Agent 容器通过 DooD 控制宿主机的 Docker,所以确保部署服务器(宿主机)上已正确安装和配置了 Docker Engine 和 Docker Compose (如果
docker-compose.yml依赖于宿主机上的docker-composeCLI 版本特性)。 -
持久化运行 Agent Docker 容器 (推荐):
- 为了确保 Agent 在服务器重启后也能自动运行,建议使用 Docker 的重启策略或通过
systemd管理 Agent Docker 容器的启动。 - 使用 Docker 重启策略:
在
docker run命令中添加--restart unless-stopped或--restart always。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):[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。
- 示例 (
- 为了确保 Agent 在服务器重启后也能自动运行,建议使用 Docker 的重启策略或通过
步骤 4.3: 在 OneDev 中创建项目并配置 Secrets
- 创建项目:
- 登录 OneDev,点击
+ New Project。 - 填写项目名称 (例如
mqtt-charging-system)。 - 代码库:
- 选择
Create an empty repository(如果您想在 OneDev 中开始一个全新的项目,并将master作为默认分支) 或Import from an existing repository(如果您想将现有的 Git 仓库——例如本地的或之前 Gitea 上的,其主分支为master——导入到 OneDev 中进行管理)。本项目将使用 OneDev 内置的 Git 服务。
- 选择
- (可选) 配置项目的默认分支为
master(如果通过导入创建且需要更改,或新建时指定)。
- 登录 OneDev,点击
- 配置项目 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: 将项目代码和配置文件推送到仓库
- 确保您的项目代码已克隆/推送到 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 连接信息通过环境变量配置。
- 将这些文件提交并推送到 OneDev 内置 Git 仓库的
master分支。
步骤 4.5: 触发与监控部署
- 触发构建:
- 当您向 OneDev 内置仓库的
master分支 (或其他在 OneDev 项目构建设置中配置的触发分支) 推送代码时,OneDev 应该会自动触发.onedev-buildspec.yml中定义的流水线。 - 您也可以在 OneDev 项目的
Builds页面手动触发特定分支 (如master) 的构建。
- 当您向 OneDev 内置仓库的
- 监控构建:
- 在 OneDev 项目的
Builds页面,您可以看到正在运行和已完成的构建列表。 - 点击特定的构建,可以查看其详细步骤、可视化流程、以及每个步骤的实时日志输出。
- 如果构建失败,日志中会包含错误信息,帮助您排查问题。
- 在 OneDev 项目的
- 验证部署: 构建成功完成后,在部署服务器上:
- 使用
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 提供了强大的可视化管理和流水线定义能力,可以显著简化部署流程的管理和监控。