协调共享运行器上的 GitHub 工作流程
在 GitHub Actions 中管理多个工作流程可能具有挑战性,尤其是当您需要它们在同一个自托管运行器上运行时。在不同工作流程有单独的 YAML 文件(例如 codeql.yml 和 snyk-zap.yml)的情况下,确保它们在特定组的同一运行器上运行可能会很棘手。
目标是为两个工作流程使用相同的运行程序,而无需显式命名运行程序,从而避免与其他工作流程发生冲突。本指南将探索可能的解决方案,以有效实现此同步,同时在单独的 YAML 文件中维护工作流程。
命令 | 描述 |
---|---|
jq | 一个轻量级且灵活的命令行 JSON 处理器,用于解析 Bash 脚本中的 JSON 输出。 |
head -n 1 | 输出结果的第一行,此处用于选择第一个可用的跑步者 ID。 |
curl | 用于通过 URL 传输数据的命令行工具,用于在 Bash 脚本中与 GitHub 的 API 进行交互。 |
os.getenv() | 检索Python中的环境变量,用于获取GitHub令牌和存储库名称。 |
requests.get() | 向指定 URL 发送 GET 请求,用于从 Python 脚本中的 GitHub API 获取可用的运行器。 |
os.path.exists() | 检查指定路径是否存在,用于确定运行者 ID 文件是否已存在于 Python 脚本中。 |
with open() | Python中文件操作的上下文管理器,用于读取运行者ID并将其写入文件。 |
与共享运行器协调工作流程
提供的脚本管理 GitHub 工作流程的运行程序分配。 Bash 脚本首先检查运行者 ID 是否已存储在临时文件中。如果没有,则使用 curl 查询 GitHub 的 API 以获取可用的运行者以及 jq 解析 JSON 响应,选择第一个空闲运行器并保存其 ID。 Python 脚本通过利用 requests.get() 从 GitHub 的 API 获取跑步者信息的方法。然后,该脚本检查跑步者 ID 是否已使用以下命令存储: os.path.exists() 如果没有则保存它。
这两个脚本都确保一旦分配了运行程序,就可以通过引用存储的运行程序 ID 将其重新用于后续作业。在 Python 脚本中, os.getenv() 检索 GitHub 令牌和存储库的环境变量,以及 with open() 用于安全地处理文件操作。这些脚本有助于协调多个工作流程,确保它们在同一个运行程序上运行,而无需对运行程序名称进行硬编码,从而使它们能够灵活高效地管理工作流程执行。
为 GitHub Actions 实施共享运行器策略
使用 Bash 脚本和 GitHub Actions 确保工作流程在同一运行器上运行
# A script to manage runner assignment
#!/bin/bash
# Check if a runner is already assigned
RUNNER_ID=$(cat /tmp/runner_id)
if [ -z "$RUNNER_ID" ]; then
# No runner assigned yet, pick one and save its ID
RUNNER_ID=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
https://api.github.com/repos/$GITHUB_REPOSITORY/actions/runners |
jq -r '.runners[] | select(.status=="online" and .busy==false) | .id' | head -n 1)
echo $RUNNER_ID > /tmp/runner_id
fi
echo "Using runner $RUNNER_ID"
# Proceed with the workflow using the assigned runner
确保单独的 YAML 文件中运行程序的使用保持一致
使用 Python 和 GitHub Actions 协调工作流程执行
import requests
import os
# GitHub API token and repository
GITHUB_TOKEN = os.getenv('GITHUB_TOKEN')
REPO = os.getenv('GITHUB_REPOSITORY')
# Function to get an available runner
def get_runner():
url = f"https://api.github.com/repos/{REPO}/actions/runners"
headers = {'Authorization': f'token {GITHUB_TOKEN}'}
response = requests.get(url, headers=headers)
runners = response.json()['runners']
for runner in runners:
if runner['status'] == 'online' and not runner['busy']:
return runner['id']
return None
# Check if a runner is already assigned
if not os.path.exists('/tmp/runner_id'):
runner_id = get_runner()
with open('/tmp/runner_id', 'w') as f:
f.write(str(runner_id))
else:
with open('/tmp/runner_id', 'r') as f:
runner_id = f.read()
print(f"Using runner {runner_id}")
GitHub Actions 中的高效运行者管理
在工作流需要在同一个自托管运行器上运行的场景中,一个关键的考虑因素是确保运行器可用性并最大限度地减少冲突。如前面的脚本所示,使用共享运行器策略可确保将运行器分配给作业后,后续作业将使用相同的运行器。这对于维护状态或利用缓存资源至关重要的复杂 CI/CD 管道尤其有用。
另一个需要考虑的方面是优化跑步者的利用率。通过根据可用性动态选择和分配跑步者,组织可以更好地管理其资源。实施此类策略不仅可以提高效率,还可以减少工作流在队列中等待可用运行程序的时间。这种方法可以扩展到其他 CI/CD 工具和平台,使其成为满足各种自动化需求的多功能解决方案。
关于协调共享运行器上的工作流程的常见问题
- 如何确保始终使用特定的运行程序?
- 使用 runs-on 在 YAML 文件中输入密钥以指定运行程序组或确切的运行程序名称。
- 我可以动态地将运行者分配给工作流程吗?
- 是的,通过使用脚本查询可用的跑步者并动态分配它们。
- 在繁忙的环境中如何处理跑步者冲突?
- 实施排队机制或确定工作流程的优先级,以有效管理跑步者分配。
- 如果没有跑步者可用怎么办?
- 工作流程将排队,直到运行程序可用。优化跑步者的使用以最大限度地减少等待时间。
- 我可以将这些脚本与其他 CI/CD 平台一起使用吗?
- 是的,该逻辑可以适用于具有 API 访问运行器管理功能的其他平台。
- 如何维护工作流程之间的状态?
- 确保相同的运行程序用于相关作业,并尽可能利用缓存机制。
- 这些脚本需要什么权限?
- 确保您的 GitHub 令牌具有必要的范围,例如 repo 和 workflow。
- 我可以在同一个运行器上同时运行多个工作流程吗?
- 通常情况下,不会。每个运行程序一次执行一项作业。使用多个运行器来实现并发。
- 如何监控跑步者的使用情况和表现?
- 使用 GitHub 的内置监控工具或外部服务来跟踪跑步者活动和表现。
结论:
管理 GitHub 工作流程以在同一自托管运行器上运行对于效率和一致性至关重要。所讨论的 Bash 和 Python 脚本通过动态分配运行器并确保后续作业使用相同的运行器来提供强大的解决方案。这种方法可以最大限度地减少冲突并优化资源利用率,使其成为复杂 CI/CD 管道的有效策略。通过实施这些方法,组织可以简化工作流程执行并减少等待时间,最终提高生产力并保持顺利的开发流程。