【CI/CD】基于 Gitea 与 Act Runner 的 CI/CD 流程搭建
编辑前言
在过去很长一段时间,我的 CI/CD 流程是围绕 Gogs + Jenkins 构建的。这套方案初期运行还算稳定,但随着服务器上部署的服务日益增多,有限的硬件配置开始捉襟见肘。此时,Jenkins 这类基于 Java 的内存消耗大户,便让我越看越不顺眼了。况且,抛开 Jenkins 不谈,Gogs 本身因为单一维护者的原因,功能迭代异常缓慢,许多我期待已久的特性迟迟未能更新,顺带着也让体验逐渐落得下乘。
为寻求替代方案,我曾尝试过 Gogs + Drone 的组合,但其使用体验同样未能完全满足我的需求。更重要的是,无论是 Jenkins 还是 Drone,其部分交付流程都强依赖于 Web UI 的手动配置。这种将配置与项目代码割裂开来的方式,不仅繁琐,也背离了我所期望的“CI/CD as Code”理念——即尽可能的将所有流程在项目内完成声明式。
GitHub + Actions 确实是我心目中的理想解决方案。可惜 GitHub 对私有仓库使用 Actions 一直采取收费策略,而且我也不是很愿意将代码完全托管于第三方平台(谁知道他们会不会偷偷拿去训练),所以一直作罢。
最近因为服务器配置的问题,我又开始研究市面上的 CI/CD 工具。好消息是,这次我发现 Gitea 支持 Action了,其语法和运行机制,完全基于 Github 开发,于是我迫不及待的开始将 Gogs + Jenkins 的组合 往 Gitea + Runner 的组合迁移,期间免不了一顿折腾和踩坑,特此记录。
机制
对于不了解 Github Actions 机制的朋友,这里简单介绍下 GitHub Actions 的的核心架构。这个架构的核心在于 控制器 和 执行器 的解耦。
GitHub 作为控制器:负责监听仓库事件、解析 Workflow 配置文件,并将作业任务进行调度和分发。
Runner 作为执行器:它是作业的实际执行器,Runner 都只负责接收调度指令,在隔离的环境中完成具体的构建、测试或部署任务。
这样的好处是显而易见的
安全:执行器和代码存储完全分离。Runner 的任何异常,甚至是崩溃,都不会对代码仓库的完整性和可用性产生任何影响。
灵活:可以根据任务需求,在不同操作系统或硬件架构上部署 Runner,方便水平扩展。
安装
背景
我有一台 4c8g 的主力服务器,还有数台 2c4g、4c8g 的 "不稳定服务器",这些服务器要么是经常变动,要么是可靠性没有保障。我的想法是,将 「Gitea」 和「主Runner」 都用 Docker 安装在主力服务器上,同时酌情在 "不稳定服务器" 上安装其他 Runner,在需要的时候使用。
docker-compose.yaml
version: "3.5"
services:
gitea:
image: gitea/gitea:latest
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
- TZ=Asia/Shanghai
restart: always
networks:
- nginx # 我用来进行方向代理的,不需要可以删除
- mysql # 我采用 Mysql 作为数据库,习惯于内网连接,不需要可以删除
- gitea
volumes:
- /home/gitea:/data
# ports:
# - "9999:3000" # 我用了 nginx 进行了反向代理,所以不需要映射端口,有需要的启用
runner:
image: gitea/act_runner:latest
container_name: runner
restart: always
depends_on:
- gitea
volumes:
- /home/runner/data:/data
- /home/runner/cache:/root/.cache # 持久化缓存目录,方便项目重启的时候不丢失缓存
- /home/runner/config.yaml:/config.yaml # Runner 配置模板,见下文补充说明
- /var/run/docker.sock:/var/run/docker.sock # 用来让 Runner 获得本机的 Docker 管理权限
networks:
- gitea
environment:
- GITEA_INSTANCE_URL=http://gitea:3000/
- GITEA_RUNNER_REGISTRATION_TOKEN=xxxxxxxxx # 第一次运行,这里先随便填,需要初始化后生成
- CONFIG_FILE=/config.yaml # 配置文件路径
- GITEA_RUNNER_NAME=docker-runner # 本 Runner 的名称标识
- GITEA_RUNNER_LABELS=docker # 本 Runner 的标签
networks:
nginx:
external: true
mysql:
external: true
gitea:
name: gitea
运行
构建容器
docker-compose up -d
访问 gitea WebUI,(如果不进行反向代理,就在docker-compose.yaml 里的启用 ports 的部分),进行初始化配置
查看 Runner Token (头像 - 管理后台 - Actions - Runner)
修改 docker-compose.yaml 中的
GITEA_RUNNER_REGISTRATION_TOKEN=xxxxxxxxx
,然后重启项目docker-compose down docker-compose up -d
一切正常的话,会在这个获取 Token 的界面看到连接到的 Runner
Gitea
配置
Gitea 的有些配置是无法在「管理后台」面板里设置的,需要通过手动修改配置文件的方式来实现。
以我上面的配置为例,Gitea 配置文件路径为: /home/gitea/gitea/conf/app.ini
, 其中我比较关注的有
修改默认分支
[repository] DEFAULT_BRANCH = master # 修改默认的分支名,默认没有此项配置需要手动添加,(缺省的情况下,默认分支为 main)
修改 Token 失效周期
现代的 Git 凭证管理机制 GCM,会通过向 Gitea 获取 Token 的形式来获得仓库访问授权,但是这个 Token 默认情况下只有 30min,导致长时间不操作仓库以后,第一次推送或者拉取会提示授权失败。可以通过下面的配置把这个失效周期拉长。
[oauth2] JWT_SECRET = xxxxxxxxx ACCESS_TOKEN_EXPIRATION_TIME=15552000 ; 单位: 秒,15552000 = 180天
修改默认使用 Action 的位置
当你在 workflow 使用第三方 action 时,默认是从 github 拉取的,如果你想默认从你自己的仓库(gitea)拉取,新建下面的配置
;从gitea实例拉取action ;[actions] ;DEFAULT_ACTIONS_URL = self
... jobs: build: runs-on: docker steps: - name: Pull repository uses: actions/checkout@v3 # 不设置 actions 配置的时候,默认是从 https://github.com/actions/checkout@v3 拉取 # 设置了 actions 配置后,会从自己的 Gitea 实例拉取 ...
自定义模板
Gitea 中有很多可以自定义的模板,具体可以见: 自定义 Gitea 配置。
以我上面的 docker-compose.yaml 为例,在 /home/gitea/gitea
文件夹新建 options
,在 options
文件夹里可以放置自定义的 gitignores
、readme
等等。
比如我要修改 Python 的默认 gitignore,则新建一个文件 /home/gitea/gitea/options/gitignore/Python
, 里面写我要写的 gitignore 内容
# 文件位置: /home/gitea/gitea/options/gitignore/Python
__pycache__/
#...
.idea/ # 启用针对 Pycharm 的 gitignore
#...
Runner
关于 Runner 也有一些配置可以修改,首先需要先生成一个默认模板。
docker run --entrypoint="" --rm -it docker.io/gitea/act_runner:latest act_runner generate-config > config.yaml
然后挑几个我常用的配置项讲解一下,其他的配置项在 config.yaml
中都注释的很清楚。
log:
level: info
runner:
capacity: 2 # 并发数
timeout: 3h # Runner 执行 Job 的超时时间
shutdown_timeout: 0s # 当 Runner 关闭的时候,如果有正在执行的 Job,Runner 等待 Job 运行多久后才关闭
fetch_timeout: 5s # 拉取代码的超时时间
fetch_interval: 2s # 拉取代码的间隔
github_mirror: 'https://ghfast.top/https://github.com' # 修改拉取 github 仓库时的镜像
cache:
enabled: true # 启用缓存
dir: "" # 当此项为空时,默认的缓存文件夹路径为 /root/.cache/actcache.
container:
network: "gitea" # 创建 docker 时使用的 docker 网络(与gitea保持在同一个网络,否则可能拉取不到代码仓库)
# privileged: false # 启动任务容器时是否使用特权模式
# force_pull: true # 即使镜像已经存在,也会强制重新拉取
# force_rebuild: false # 即使镜像已经存在,也会强制重新建立
workflow
这个讲起来太长了,基本要从 Github Actions 语法开始讲起,又要注意 Gitea 中与 Github Actions 语法的一些小的区别,对 Github Actions 有了解的朋友,可以只看区别的部分: Gitea Actions 与 Github Actions 的异同。
放一个我常用的,单容器构建+运行+健康检查+企业微信通知结果的 Demo 吧。
name: Build Docker Image and Run Container
on:
push:
branches:
- main
jobs:
build:
runs-on: docker
container:
image: catthehacker/ubuntu:act-22.04
timeout-minutes: 30
steps:
- name: Start build notification
uses: chf007/action-wechat-work@master
env:
WECHAT_WORK_BOT_WEBHOOK: ${{ vars.WECOM_ROBOT_URL }}
with:
msgtype: markdown
content: |
<font color="info">🎯 ${{ gitea.repository }} 开始构建</font>
> 构建分支: ${{ gitea.ref_name }}
> 提交用户: ${{ gitea.actor }}
- name: Pull repository
uses: actions/checkout@v3
- name: Build and run image
id: build_step
uses: hicane0/action-docker-build-single@v1
- name: Prepare notification data
id: notify_step
if: always()
run: |
if [ "${{ steps.build_step.outcome }}" = "success" ]; then
echo "title=<font color=\"info\">✅ ${{ gitea.repository }} 构建成功</font>" >> $GITEA_OUTPUT
else
echo "title=<font color=\"warning\">❌ ${{ gitea.repository }} 构建失败</font>" >> $GITEA_OUTPUT
fi
echo "action_url=${{ gitea.event.repository.html_url }}/actions/runs/${{ gitea.run_id }}" >> $GITEA_OUTPUT
- name: Send build result
if: always()
uses: chf007/action-wechat-work@master
env:
WECHAT_WORK_BOT_WEBHOOK: ${{ vars.WECOM_ROBOT_URL }}
with:
msgtype: markdown
content: |
${{ steps.notify_step.outputs.title }}
> 构建分支: ${{ gitea.ref_name }}
> 提交用户: ${{ gitea.actor }}
> 构建耗时: ${{ steps.build_step.outputs.duration }}
> 详细日志: [${{ gitea.job }}](${{ steps.notify_step.outputs.action_url }})
- 0
- 0
-
赞助
微信
-
分享