-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Add GitHub workflow and job metadata labels to runner pods #4256
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Add workflow metadata labels to runner pods for cost tracking
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Adds GitHub workflow metadata labels to runner pods for cost allocation and tracking in GKE environments. This enables organizations to attribute GitHub Actions costs to specific repositories, workflows, and jobs through Kubernetes labels.
- Implements automatic labeling of runner pods with workflow metadata when jobs start
- Adds RBAC permissions for pod updates in both manager and kube mode roles
- Includes label value sanitization for Kubernetes compliance
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
File | Description |
---|---|
cmd/ghalistener/worker/worker.go | Core implementation with pod labeling logic, sanitization function, and job handling updates |
charts/gha-runner-scale-set/templates/manager_role.yaml | Adds update and patch verbs to pods rule for manager role |
charts/gha-runner-scale-set/templates/kube_mode_role.yaml | Adds update and patch verbs to pods rule for kube mode role |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
reg := regexp.MustCompile(`[^a-zA-Z0-9._-]`) | ||
sanitized := reg.ReplaceAllString(value, "-") | ||
|
||
// Remove consecutive hyphens | ||
reg = regexp.MustCompile(`-+`) | ||
sanitized = reg.ReplaceAllString(sanitized, "-") |
Copilot
AI
Sep 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider compiling the regular expressions once as package-level variables instead of recompiling them on every function call. This will improve performance when the function is called frequently.
Copilot uses AI. Check for mistakes.
sanitized = reg.ReplaceAllString(sanitized, "-") | ||
|
||
// Ensure it starts and ends with alphanumeric character | ||
sanitized = strings.Trim(sanitized, "-._") |
Copilot
AI
Sep 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After trimming characters, the result could be empty even if the original sanitized string wasn't empty, but the function only checks for empty strings before this step. This could result in multiple values being mapped to 'unknown' when they should have distinct sanitized values.
Copilot uses AI. Check for mistakes.
sanitized = sanitized[:63] | ||
sanitized = strings.Trim(sanitized, "-._") | ||
} | ||
|
Copilot
AI
Sep 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After truncating and trimming, the sanitized string could become empty, but there's no check to handle this case. This could result in empty label values which are invalid in Kubernetes.
// If empty after truncation and trimming, use a default value | |
if sanitized == "" { | |
sanitized = "unknown" | |
} |
Copilot uses AI. Check for mistakes.
"pod", pod.Name, | ||
"labels", workflowLabels) | ||
|
||
_, err = w.clientset.CoreV1().Pods(w.config.EphemeralRunnerSetNamespace).Update(ctx, pod, metav1.UpdateOptions{}) |
Copilot
AI
Sep 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using Update() without checking resource version could lead to conflicts if the pod is modified by another process between Get() and Update(). Consider using Patch() instead or implementing retry logic with exponential backoff to handle update conflicts.
Copilot uses AI. Check for mistakes.
Problem
Organizations using GitHub Actions with self-hosted runners on GKE cannot attribute costs to specific repositories, workflows, or jobs because runner pods lack workflow metadata labels.
Solution
Automatically apply workflow metadata as pod labels when jobs start, enabling cost tracking through GKE's existing cost allocation infrastructure.
Reference: https://cloud.google.com/kubernetes-engine/docs/how-to/cost-allocations
Changes
Worker Implementation (
cmd/ghalistener/worker/worker.go
):updatePodLabelsWithWorkflowMetadata()
functionsanitizeLabelValue()
for Kubernetes label validationHandleJobStarted()
to apply labels when jobs startWithClientset()
option for testabilityRBAC Permissions (
charts/gha-runner-scale-set/templates/manager_role.yaml
):update
andpatch
verbs to pods ruleLabels Applied
github.com/repository
: Repository name (sanitized)github.com/workflow
: Workflow reference (sanitized)github.com/job
: Job display name (sanitized)github.com/job-id
: Unique job IDgithub.com/run-id
: Workflow run IDExample Output
Key Features
Testing
Benefits
This enables organizations to track GitHub Actions costs at the repository, workflow, and job level using their existing GKE cost allocation setup.
disclaimer: this was developed isong Cursor AI, so it needs a proper review.