ARC 03 从Github Action job 到 runner pod

Github Action job 分配到集群

背景

job 是 Github Action 的基本单位,每个 job 单独分配一个 runner。workflow 由一个或者多个 job 组成。如果用户触发runs-on字段为arc-runner-set的 job,那么 Github Action 服务器将 job 分配给 listener pod。

源码

handleMessage函数主要处理2类处理服务器消息。第一类是状态为started的 job: job 已经由服务器分配给 runner 执行。HandleJobStarted函数 job 信息局部更新给EphemeralRunner资源。

func (l *Listener) handleMessage(ctx context.Context, handler Handler, msg *actions.RunnerScaleSetMessage) error {parsedMsg, err := l.parseMessage(ctx, msg) // 解析消息l.lastMessageID = msg.MessageIdif err := l.deleteLastMessage(ctx); err != nil { // 请求服务器删去消息return fmt.Errorf("failed to delete message: %w", err)}for _, jobStarted := range parsedMsg.jobsStarted {if err := handler.HandleJobStarted(ctx, jobStarted); err != nil {return fmt.Errorf("failed to handle job started: %w", err)}l.metrics.PublishJobStarted(jobStarted)}desiredRunners, err := handler.HandleDesiredRunnerCount(ctx, parsedMsg.statistics.TotalAssignedJobs, len(parsedMsg.jobsCompleted))l.metrics.PublishDesiredRunners(desiredRunners)return nil
}

第二类是状态为AssignedCompleted的 job。前者是还未结束的任务,后者是已经结束的任务。
HandleDesiredRunnerCount函数首先调用setDesiredWorkerState函数计算集群的 runner 数量。

// count = parsedMsg.statistics.TotalAssignedJobs 表示未结束的 job 数量
// jobsCompleted = len(parsedMsg.jobsCompleted) 表示已经运行结束的 job 数量
func (w *Worker) setDesiredWorkerState(count, jobsCompleted int) int {// 根据用户在 runner scale set chart 的 values.yaml 文件配置的 minRunenrs 和 maxRunners 以及分配的 job 数量综合确定集群的 runner 数量。targetRunnerCount := min(w.config.MinRunners+count, w.config.MaxRunners)w.patchSeq++ // 批次序号+1desiredPatchID := w.patchSeqif count == 0 && jobsCompleted == 0 { // 本批次既没有运行的 job,也没有结束的 jobtargetRunnerCount = max(w.lastPatch, targetRunnerCount)if targetRunnerCount == w.config.MinRunners {// 运行至此,本批次没有活跃 job,上批次也没有活跃 job。集群处于空闲状态desiredPatchID = 0 // 将 desiredPatchID 设为 0 用于触发缩容}}w.lastPatch = targetRunnerCountreturn desiredPatchID
}

之后HandleDesiredRunnerCount函数将批次序号和 runner 数局部更新给EphemeralRunnerSet资源。

patch, err := json.Marshal(&v1alpha1.EphemeralRunnerSet{Spec: v1alpha1.EphemeralRunnerSetSpec{Replicas: w.lastPatch, // targetRunnerCountPatchID:  patchID, // desiredPatchID},},)

EphemeralRunnerSet控制器根据批次序号和 runner 数更改 runner 资源。主要逻辑如下:

    // total 是集群中运行的 runner pod 的数量,与 Github Action 服务器无关total := ephemeralRunnerState.scaleTotal()if ephemeralRunnerSet.Spec.PatchID == 0 || ephemeralRunnerSet.Spec.PatchID != ephemeralRunnerState.latestPatchID {defer func() {// 主动删除已经结束的`EphemeralRunner`资源if err := r.cleanupFinishedEphemeralRunners(ctx, ephemeralRunnerState.finished, log); err != nil {log.Error(err, "failed to cleanup finished ephemeral runners")}}()log.Info("Scaling comparison", "current", total, "desired", ephemeralRunnerSet.Spec.Replicas)switch {// 集群中 runner 数量小于 job 数量,扩容case total < ephemeralRunnerSet.Spec.Replicas: // Handle scale upcount := ephemeralRunnerSet.Spec.Replicas - totallog.Info("Creating new ephemeral runners (scale up)", "count", count)if err := r.createEphemeralRunners(ctx, ephemeralRunnerSet, count, log); err != nil {log.Error(err, "failed to make ephemeral runner")return ctrl.Result{}, err}// 集群中 runner 数量大于 job 数量,说明 Github Action 服务器已经认为某些 job 结束,但是 job 对应的 runner pod 还未到结束状态。等待 runner pod 自行结束。case ephemeralRunnerSet.Spec.PatchID > 0 && total >= ephemeralRunnerSet.Spec.Replicas:// PatchID == 0 是 setDesiredWorkerState 函数的缩容标记,避免集群空闲时仍然有 runner pod 在运行case ephemeralRunnerSet.Spec.PatchID == 0 && total > ephemeralRunnerSet.Spec.Replicas:count := total - ephemeralRunnerSet.Spec.Replicasif err := r.deleteIdleEphemeralRunners(ctx,ephemeralRunnerSet,ephemeralRunnerState.pending,ephemeralRunnerState.running,count,log,); err != nil {log.Error(err, "failed to delete idle runners")return ctrl.Result{}, err}}}

createEphemeralRunners函数创建EphemeralRunner资源。资源结构如下:

return &v1alpha1.EphemeralRunner{TypeMeta: metav1.TypeMeta{},ObjectMeta: metav1.ObjectMeta{GenerateName: ephemeralRunnerSet.Name + "-runner-", // k8s 自动为EphemeralRunner 资源名称创建随机后缀,因为一个 EphemeralRunnerSet 对应多个 EphemeralRunner 资源Namespace:    ephemeralRunnerSet.Namespace,Labels:       labels,Annotations:  annotations,OwnerReferences: []metav1.OwnerReference{{APIVersion:         ephemeralRunnerSet.GetObjectKind().GroupVersionKind().GroupVersion().String(),Kind:               ephemeralRunnerSet.GetObjectKind().GroupVersionKind().Kind,UID:                ephemeralRunnerSet.GetUID(),Name:               ephemeralRunnerSet.GetName(),Controller:         boolPtr(true),BlockOwnerDeletion: boolPtr(true),},},},Spec: ephemeralRunnerSet.Spec.EphemeralRunnerSpec,}

EphemeralRunner控制器根据EphemeralRunner资源创建 runner pod。步骤如下:

  1. 添加 finalizer 字段。finalizer表示在集群中注销本资源。runner-registration-finalizer表示在 Github Action 服务器注销本资源。
const (ephemeralRunnerFinalizerName        = "ephemeralrunner.actions.github.com/finalizer"ephemeralRunnerActionsFinalizerName = "ephemeralrunner.actions.github.com/runner-registration-finalizer"
)
  1. 向 Github Action 服务器注册自身。返回 RunnerId 表示注册成功。
type RunnerScaleSetJitRunnerSetting struct {Name       string `json:"name"`WorkFolder string `json:"workFolder"`
}
// jit(Just-in-Time) config:服务器返回的注册信息
// jitSettings 的类型是 RunnerScaleSetJitRunnerSetting。包含 runner 名称以及工作目录。
// RunnerScaleSetId: runner 所属 runner scale set 的注册Id
jitConfig, err := actionsClient.GenerateJitRunnerConfig(ctx, jitSettings, ephemeralRunner.Spec.RunnerScaleSetId)// 更新 EphemeralRunner 资源
err = patchSubResource(ctx, r.Status(), ephemeralRunner, func(obj *v1alpha1.EphemeralRunner) {obj.Status.RunnerId = jitConfig.Runner.Id // runner idobj.Status.RunnerName = jitConfig.Runner.Name // runner 名称obj.Status.RunnerJITConfig = jitConfig.EncodedJITConfig // 配置 secret})
  1. 将 RunnerJITConfig 注册为 secret, runner pod 将通过 config 与 Github Action 服务器连接。
    return &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name:      ephemeralRunner.Name,Namespace: ephemeralRunner.Namespace,},Data: map[string][]byte{jitTokenKey: []byte(ephemeralRunner.Status.RunnerJITConfig),},}
  1. 创建 runner pod。runner pod 的镜像是ghcr.io/actions/actions-runner。它将与 Github Action 服务器建立连接。服务器分配 job 给 runner pod,服务器将 job 的任务内容交给 runner pod 执行。执行完成后,runner pod 结束。
c.Env = append(c.Env,corev1.EnvVar{Name: EnvVarRunnerJITConfig,ValueFrom: &corev1.EnvVarSource{SecretKeyRef: &corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: secret.Name,},Key: jitTokenKey, // 将 RunnerJITConfig secret 挂载给 runner container。},},},
)
  1. 监控 runner container 的状态。

总结

本文讲了 Github Action job 到 runner pod 的执行流程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/89299.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/89299.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ubuntu 22.04 anaconda comfyui安装

背景&#xff1a; 戴尔R740服务器&#xff0c;安装了proxmox操作系统&#xff0c;配置了显卡直通。创建了一个ubuntu 22.04 VM虚拟机实例&#xff0c;并安装了显卡驱动与cuda等相关配置&#xff1a; 接下来准备搭建一套comfyui的环境&#xff0c;前段时间B站&#xff0c;抖音各…

每日面试题04:volatile字段的原理

在之前面试题02ConcurrentHashMap的底层原理中提到了volatile修饰符&#xff0c;在多线程编程的世界里&#xff0c;数据同步是一道绕不开的坎。当多个线程同时操作共享变量时&#xff0c;“看不见对方的修改”或“代码顺序错乱”往往会导致程序行为异常。而 volatile作为 Java …

【云原生网络】Istio基础篇

文章目录概述基础知识技术架构概述数据平面核心组件网络代理Envoy控制平面核心组件xDS协议Pilot组件其他概述参考博客&#x1f60a;点此到文末惊喜↩︎ 概述 基础知识 背景知识 服务网格&#xff08;Service Mesh&#xff09;&#xff1a;独立于应用程序的基础设施层&#x…

PySpark Standalone 集群

一、PySpark Standalone 集群概述PySpark Standalone 集群是 Apache Spark 的一种部署模式&#xff0c;它不依赖于其他资源管理系统&#xff08;如 YARN 或 Mesos&#xff09;&#xff0c;而是使用 Spark 自身的集群管理器。这种模式适合快速部署和测试&#xff0c;尤其在开发和…

图像质量评价(Image Quality Assessment,IQA)

文章目录图像质量评价&#xff08;Image Quality Assessment&#xff0c;IQA&#xff09;一、评估方式&#xff1a;主观评估 客观评估1.1、主观评估方式1.2、客观评估方式&#xff1a;全参考 半参考 无参考&#xff08;1&#xff09;全参考的方法对比&#xff08;Full-Refer…

【跟我学YOLO】(2)YOLO12 环境配置与基本应用

欢迎关注『跟我学 YOLO』系列 【跟我学YOLO】&#xff08;1&#xff09;YOLO12&#xff1a;以注意力为中心的物体检测 【跟我学YOLO】&#xff08;2&#xff09;YOLO12 环境配置与基本应用 【跟我学YOLO】&#xff08;3&#xff09;YOLO12 用于诊断视网膜病变 【跟我学YOLO】&a…

Python爬虫实战:研究openpyxl库相关技术

1. 引言 在当今数字化时代,互联网上蕴含着海量有价值的数据。如何高效地获取这些数据并进行分析处理,成为数据科学领域的重要研究方向。网络爬虫作为一种自动化的数据采集工具,可以帮助我们从网页中提取所需的信息。而 openpyxl 作为 Python 中处理 Excel 文件的优秀库,能…

Redis学习其一

文章目录1.NoSQL概述1.1概述1.2Nosql的四大分类2.Redis入门2.1概述2.2基础知识2.2.1基础命令/语法2.2.2Redis为什么单线程还这么快2.3性能测试3.五大数据类型3.1Redis-key3.2String(字符串)3.3List(列表)3.4Set(集合)3.5Hash&#xff08;哈希&#xff09;3.6Zset&#xff08;有…

高性能架构模式——高性能缓存架构

目录 一、引入前提二、缓存架构的设计要点2.1、缓存穿透2.1.1、缓存穿透第一种情况:存储数据不存在2.1.2、缓存穿透第二种情况:缓存数据生成耗费大量时间或者资源2.2、缓存雪崩2.2.1、解决缓存雪崩的第一种方法:更新锁机制2.2.2、解决缓存雪崩的第二种方法:后台更新机制2.3…

ubuntu+windows双系统恢复

文章目录前言一、恢复windows1.直接在grub命令行输入exit退出2.手动查找windows引导文件先ls列出所有磁盘和分区查找各个分区是否包含引导文件设置引导分区以及引导文件路径启动windows二、在windows系统下删除Ubuntu残留引导文件三、准备ubuntu系统引导盘四、安装ubuntu系统五…

使用Dify构建HR智能助理,深度集成大模型应用,赋能HR招聘管理全流程,dify相关工作流全开源。

HR智能助理系统 &#x1f4cb; 项目概述 HR智能助理系统是一个基于AI技术的人力资源管理平台&#xff0c;旨在通过智能化工具提升招聘效率&#xff0c;优化候选人评估流程&#xff0c;并提供专业的面试方案生成服务。 &#x1f3af; 核心价值 提升招聘效率60%&#xff1a;自动化…

PowerBI实现仅在需要图表时显示图表

PowerBI实现仅在需要图表时显示图表实现效果点击维度前&#xff1a;点击维度后&#xff1a;实现步骤第一步&#xff0c;先创建一个矩阵表和一个柱形图第二步&#xff0c;添加一个新卡片图第三步&#xff0c;创建文本度量值Text "⭠ 选择一个地区"第四步&#xff0c;创…

信息收集知识总结

信息收集 在信息收集中&#xff0c;需要收集的信息&#xff1a;目标主机的DNS信息、目标IP地址、子域名、旁站和C段、CMS类型、敏感目录、端口信息、操作系统版本、网站架构、漏洞信息、服务器与中间件信息、邮箱、人员、地址等。 域名信息收集 拿到公司名或者一个域名&…

工作第一步建立连接——ssh

照本宣科 SSH&#xff08;Secure Shell&#xff0c;安全外壳协议&#xff09;是一种用于在不安全网络上进行安全远程登录和实现其他安全网络服务的协议.功能主要是远程登陆和文件传输&#xff08;使用scp&#xff09; 为了建立 SSH 远程连接&#xff0c;需要两个组件&#xf…

Markdown变身Word,解锁格式转换新姿势

目录一、引言二、在线转换工具使用法2.1 工具推荐2.2 操作步骤2.3 优缺点分析三、文本编辑器的内置功能或插件3.1 适用编辑器列举3.2 以 Visual Studio Code 为例的操作流程3.3 优势说明四、使用专门的转换软件4.1 Pandoc 软件介绍4.2 安装步骤4.3 命令行转换操作五、编程脚本实…

MR 处于 WIP 状态的WIP是什么

WIP是什么 在MR&#xff08;Merge Request 或代码合并请求&#xff09;中&#xff0c;WIP 是"Work In Progress" 的缩写&#xff0c;意思是“正在进行中”或“在制品”。当一个MR 被标记为WIP&#xff0c;通常表示它尚未准备好被合并&#xff0c;可能还在开发中&…

机器学习-线性回归模型和梯度算法

1. 线性回归模型1.1 线性回归模型线性回归模型&#xff1a;将数据拟合成一条直线。作用&#xff1a;预测数字作为输出。例子&#xff1a;房子的大小与房价的估计&#xff08;图表&#xff09;&#xff08;数据表&#xff09;1.2 训练集训练集&#xff1a;用于训练模型的数据集训…

时序预测 | Matlab代码实现VMD-TCN-GRU-MATT变分模态分解时间卷积门控循环单元多头注意力多变量时序预测

预测效果代码功能 代码主要功能 该代码实现了一个变分模态分解时间卷积门控循环单元多头注意力多变量时间序列预测模型&#xff0c;核心功能为&#xff1a; 使用VMD&#xff08;变分模态分解&#xff09;将原始信号分解为多个IMF分量对每个IMF分量构建TCN-GRU-MATT混合神经网络…

HTML5 离线存储

HTML5 离线存储&#xff08;通常指 Application Cache&#xff09;是早期用于实现 Web 应用离线访问的技术&#xff0c;但由于其设计缺陷已被废弃。现代 Web 开发中&#xff0c;取而代之的是更强大的 Service Worker Cache API 方案&#xff08;属于 Progressive Web Apps 技术…

JavaScript 性能优化实战:深入性能瓶颈,精炼优化技巧与最佳实践

前言 现代前端开发&#xff0c;不仅要“能跑”&#xff0c;更要“跑得快”。在用户体验为王的时代&#xff0c;JavaScript 性能优化已经成为前端工程师的必修课。 为什么要关注 JavaScript 性能 加载缓慢 → 用户流失卡顿滞后 → 交互体验崩溃资源浪费 → 设备电量与内存被吞…