大家好,我是张晋涛。
本周 Docker 就发布 10 周年了,为了庆祝这个里程碑,我将会发布一系列文章,涉及 Docker,CI/CD, 容器等各个方面。
这篇文章我将介绍如何降低 GitHub Actions 上的消费,以及一些建议
根据 G2 的统计报告, GitHub Actions 是最易用的 CI/CD 工具,越来越多的人都喜欢它。
由于 GitHub Actions 是 GitHub 原生的 CI/CD 工具,在 marketplace 有上万个 Actions 可直接使用,且对于公共仓库是免费的,所以越来越多的项目也将其使用的 CI 工具切换成了 GitHub Actions。
我也很喜欢 GitHub Actions,并且几乎在我所有托管在 GitHub 上的仓库中使用它。
但是最近我在一个项目中,触发了 GitHub Actions 配额的限制。这让我花费了一些时间去关注它的费用。
https://twitter.com/zhangjintao9020/status/1616077513125691399?s=20&t=we9o9FxhgSEOXzY39czbJg
为什么会耗尽配额
最近我发现了一个有趣的项目: upptime/upptime: ⬆️ Free uptime monitor and status page powered by GitHub
我想要尝试用它将自己的开发的一些服务监控起来,做一个 status page,但这会涉及到一些 API 的配置,我并不想将它公开,所以我将该仓库 fork 到了一个私有仓库中。 经过简单的配置后,它就正常工作了。
由于我想要得到更多数据,所以我调整了其中中 CI 调度配置。让这些任务执行的更加频繁。
workflowSchedule:
graphs: "0 * * * *"
responseTime: "0 * * * *"
staticSite: "0 * * * *"
summary: "0 * * * *"
updateTemplate: "0 * * * *"
updates: "0 * * * *"
uptime: "*/5 * * * *"
根据 GitHub Actions 的费用文档,GitHub Actions 对于公开仓库是免费的,但是对私有仓库是有配额限制的。
GitHub Actions usage is free for standard GitHub-hosted runners in public repositories, and for Self-hosted runners. For private repositories, each GitHub account receives a certain amount of free minutes and storage for use with GitHub-hosted runners, depending on the product used with the account. Any usage beyond the included amounts is controlled by spending limits.
很快我就收到了 GitHub 的额度提醒邮件,提醒我配额即将用完。
这让我开始思考如何解决它。
使用 GitHub Actions 的成本
将仓库设置为公开显然是最简单的办法,但我在上文中说明了不能设置成公开仓库的原因。只能去找其他的解决办法。
显然为 GitHub Actions 付费也是一个很直接的解决办法。
在决定为它付费之前,我想要预估一下成本。 GitHub 提供了一个 Pricing Calculator,可以方便的预估花费。
由于我修改了 CI 的调度配置,最频繁运行的任务每 5 分钟会运行一次。
我使用 Meercode 采集了这个仓库中 GitHub Actions 的运行数据,它默认提供了一些 dashboard,比较方便:
同时也允许用户自己进行自定义,我创建了自己的 dashboard,如果你对 Meercode 感兴趣,请在评论中告诉我。
从上面的图中可以看到,每次任务耗时不超过 0.5min,每小时会有不超过 12 个任务。使用价格计算器进行计算,大概 每月花费是 $35
,每年 $420
。
节约成本的办法
由于我的这个仓库中是运行 uptime 的 CI,它消耗的资源很少,但是任务比较频繁,所以我想知道如果我使用 Self-hosted runner 是否可以节约成本。
我对比了几家云服务提供商的价格(规避广告嫌疑,这里就不列了)
其中 1C1G 的实例最低是 $5/month
。
我选择了其中一家最低规格的实例,并且有 1TB 流量。
我分别尝试了使用它的 Kubernetes 服务,和 compute instance ,它们都可以工作的很好。
使用 compute instance
在 Linux compute instance 中部署 GitHub Actions runner 简单,只需要在项目 https://github.com/<Your name>/<Project name>/settings/actions/runners/new
添加即可。
在该页面有完整的部署步骤,按步骤执行即可。
我的执行过程如下:
moelove@polished-bush-99d8-1926a1:~$ mkdir actions-runner && cd actions-runner
moelove@polished-bush-99d8-1926a1:~/actions-runner$ curl -o actions-runner-linux-x64-2.301.1.tar.gz -L https://github.com/actions/runner/releases/download/v2.301.1/actions-runner-linux-x64-2.301.1.tar.gz
moelove@polished-bush-99d8-1926a1:~/actions-runner$ echo "3ee9c3b83de642f919912e0594ee2601835518827da785d034c1163f8efdf907 actions-runner-linux-x64-2.301.1.tar.gz" | shasum -a 256 -c
actions-runner-linux-x64-2.301.1.tar.gz: OK
moelove@polished-bush-99d8-1926a1:~/actions-runner$ tar xzf ./actions-runner-linux-x64-2.301.1.tar.gz
moelove@polished-bush-99d8-1926a1:~/actions-runner$ ./config.sh --url https://github.com/MoeLove/monitoring --token $TOKEN
--------------------------------------------------------------------------------
| ____ _ _ _ _ _ _ _ _ |
| / ___(_) |_| | | |_ _| |__ / \ ___| |_(_) ___ _ __ ___ |
| | | _| | __| |_| | | | | '_ \ / _ \ / __| __| |/ _ \| '_ \/ __| |
| | |_| | | |_| _ | |_| | |_) | / ___ \ (__| |_| | (_) | | | \__ \ |
| \____|_|\__|_| |_|\__,_|_.__/ /_/ \_\___|\__|_|\___/|_| |_|___/ |
| |
| Self-hosted runner registration |
| |
--------------------------------------------------------------------------------
执行完成后,会在当前目录下增加一些文件。执行 ./env.sh
即可启动 GitHub Actions runner 。
moelove@polished-bush-99d8-1926a1:~/actions-runner$ ls
_diag _work actions-runner-linux-x64-2.301.1.tar.gz bin config.sh env.sh externals run-helper.cmd.template run-helper.sh run-helper.sh.template run.sh safe_sleep.sh svc.sh
如果想要稳定的在后台运行,可以执行 ./svc.sh install
将 runner 安装为 systemd 的 service,通过 systemd 管理它的生命周期。
使用 Kubernetes
我选择的这个服务对于 Kubernetes 的 control plane 不收费,仅对 Worker Node 收费,使用 Kubernetes 的好处在于我可以在该集群中进行自动扩缩容,并且可以轻松的运行创建多个 runner 给不同的项目使用。
由于 GitHub 官方尚未真正提供在 Kubernetes 上部署 Self-hosted runner, 我使用了 Actions Runner Controller (ARC) 项目,
该项目允许通过 Runner
自定义资源,快速的部署 Self-hosted runner。
部署过程在文档 https://github.com/actions/actions-runner-controller/blob/master/docs/quickstart.md 中已经描述的很清楚了,以下是我的部署过程。
# deploy cert-manager
(MoeLove) ➜ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.11.0/cert-manager.yaml
# deploy ARC
(MoeLove) ➜ helm repo add actions-runner-controller https://actions-runner-controller.github.io/actions-runner-controller
(MoeLove) ➜ helm upgrade --install --namespace actions-runner-system --create-namespace\
--set=authSecret.create=true\
--set=authSecret.github_token="REPLACE_YOUR_TOKEN_HERE"\
--wait actions-runner-controller actions-runner-controller/actions-runner-controller
# create runner
(MoeLove) ➜ cat <<EOF | kubectl apply -f -
apiVersion: actions.summerwind.dev/v1alpha1
kind: RunnerDeployment
metadata:
name: moelove-runner
spec:
replicas: 1
template:
spec:
repository: MoeLove/monitoring
EOF
安装后达成了如下效果:
Self-hosted vs GitHub-managed
上面的内容我介绍了我是如何使用 Meercode 度量 CI 的关键指标,以及估算 GitHub Actions 成本的。 根据我实际的低资源消耗,高耗时的场景,我选择了 Self-hosted 的模式。
那么什么时候选择 GitHub-managed runner 更合适呢?GitHub-managed 有什么优势呢?
GitHub-managed runner 有如下优势:
- 支持多种操作系统:GitHub-managed runner 除了提供 Linux 系统外,还支持 macOS 和 Windows ,但是大多数云供应商是不提供 macOS 环境的。(我曾经为了特定场景将一些 Mac mini 作为服务器放在了机房中)
- VM 级别的隔离性:根据 GitHub Actions 的文档,GitHub Actions 的 runner 在执行 job 的时候,是通过创建 VM 来运行所有任务的,这带来了一定的安全性和隔离性的保证。如果是 Self-hosted runner,当通过二进制运行的时候,任务将共享主机环境,如果是通过 ARC 运行,则是通过 Pod 带来隔离。这都会产生一定的安全问题。Alex创建了actuated https://actuated.dev/ 通过使用MicroVMs技术,带来轻量且安全的解决方案; cirun.io 是通过直接使用 cloud provider 创建实例。
- 低维护成本:事实上在任何大型系统中,维护成本都是非常昂贵的。如果只是个人使用,或者仅仅有几个项目在使用 Self-hosted runner 时,维护成本相对可控。一旦规模变大,将会带来很多复杂性。显然 GitHub-managed runner 是由 GitHub 进行维护的。
此外,还有两个做 Self-hosted runner 服务的产品:
它们降低了 runner 的维护和管理成本,提供了更安全的隔离性,以及基于 Arm 环境的支持。cirun 还提供了 GPU runner 的支持。
如果有上述的需求,也可以考虑这些服务。
总结
总的来说,想要节约 GitHub Actions 的成本,需要如下步骤
- 可视化/可观测性:通过实际数据来预估成本;
- 比较多个厂商/解决方案:不同的厂商在不同的场景或者产品中提供了不同的定价,可以根据自己的实际情况进行选择;
- 安全性和维护成本也需要考虑在内;
欢迎订阅我的文章公众号【MoeLove】