mirror of
https://github.com/actions-runner-controller/actions-runner-controller.git
synced 2026-09-30 14:47:11 +02:00
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
123 lines
4.5 KiB
Go
123 lines
4.5 KiB
Go
package actionsgithubcom
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1"
|
|
corev1 "k8s.io/api/core/v1"
|
|
"k8s.io/apimachinery/pkg/api/resource"
|
|
)
|
|
|
|
// benchmarkEphemeralRunnerSet builds a runner set roughly the size of a real
|
|
// ARC deployment: a runner container, a dind sidecar, an init container,
|
|
// resource limits, volumes and a dozen environment variables.
|
|
func benchmarkEphemeralRunnerSet() *v1alpha1.EphemeralRunnerSet {
|
|
env := make([]corev1.EnvVar, 0, 12)
|
|
for i := range 12 {
|
|
env = append(env, corev1.EnvVar{Name: fmt.Sprintf("VAR_%d", i), Value: fmt.Sprintf("value-%d", i)})
|
|
}
|
|
q := resource.MustParse
|
|
|
|
return &v1alpha1.EphemeralRunnerSet{
|
|
Spec: v1alpha1.EphemeralRunnerSetSpec{
|
|
Replicas: 10,
|
|
PatchID: 7,
|
|
EphemeralRunnerSpec: v1alpha1.EphemeralRunnerSpec{
|
|
GitHubConfigURL: "https://github.com/octo-org",
|
|
GitHubConfigSecret: "gh-config",
|
|
RunnerScaleSetID: 42,
|
|
PodTemplateSpec: corev1.PodTemplateSpec{
|
|
Spec: corev1.PodSpec{
|
|
ServiceAccountName: "runner-sa",
|
|
RestartPolicy: corev1.RestartPolicyNever,
|
|
NodeSelector: map[string]string{"kubernetes.io/os": "linux", "node.kubernetes.io/pool": "runners"},
|
|
Tolerations: []corev1.Toleration{{
|
|
Key: "dedicated", Operator: corev1.TolerationOpEqual,
|
|
Value: "runners", Effect: corev1.TaintEffectNoSchedule,
|
|
}},
|
|
Volumes: []corev1.Volume{
|
|
{Name: "work", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}},
|
|
{Name: "dind-sock", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}},
|
|
},
|
|
InitContainers: []corev1.Container{{
|
|
Name: "init-dind", Image: "docker:dind",
|
|
Command: []string{"cp"},
|
|
Args: []string{"-r", "/usr/local/bin/.", "/dind"},
|
|
VolumeMounts: []corev1.VolumeMount{{Name: "dind-sock", MountPath: "/dind"}},
|
|
}},
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: "runner",
|
|
Image: "ghcr.io/actions/actions-runner:2.337.0",
|
|
Command: []string{"/home/runner/run.sh"},
|
|
Env: env,
|
|
VolumeMounts: []corev1.VolumeMount{
|
|
{Name: "work", MountPath: "/home/runner/_work"},
|
|
{Name: "dind-sock", MountPath: "/var/run"},
|
|
},
|
|
Resources: corev1.ResourceRequirements{
|
|
Requests: corev1.ResourceList{corev1.ResourceCPU: q("500m"), corev1.ResourceMemory: q("1Gi")},
|
|
Limits: corev1.ResourceList{corev1.ResourceCPU: q("2"), corev1.ResourceMemory: q("4Gi")},
|
|
},
|
|
},
|
|
{
|
|
Name: "dind", Image: "docker:dind", Env: env[:6],
|
|
VolumeMounts: []corev1.VolumeMount{{Name: "dind-sock", MountPath: "/var/run"}},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// BenchmarkEphemeralRunnerSetActionableSpecChanged measures the drift check that
|
|
// runs on every AutoscalingRunnerSet reconcile. Reconciles are driven by
|
|
// EphemeralRunnerSet status churn via Owns(), so this executes constantly and
|
|
// its allocation count feeds directly into controller GC pressure.
|
|
//
|
|
// For reference on the machine this was written on: Semantic.DeepEqual is around
|
|
// 65us/241 allocs, versus 332us/405 allocs for cmp.Equal. If this regresses by an
|
|
// order of magnitude, something switched the comparison back to a reflection
|
|
// heavy implementation.
|
|
func BenchmarkEphemeralRunnerSetActionableSpecChanged(b *testing.B) {
|
|
b.Run("no drift", func(b *testing.B) {
|
|
current, desired := benchmarkEphemeralRunnerSet(), benchmarkEphemeralRunnerSet()
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for range b.N {
|
|
if ephemeralRunnerSetActionableSpecChanged(current, desired) {
|
|
b.Fatal("expected no drift")
|
|
}
|
|
}
|
|
})
|
|
|
|
b.Run("drift", func(b *testing.B) {
|
|
current, desired := benchmarkEphemeralRunnerSet(), benchmarkEphemeralRunnerSet()
|
|
desired.Spec.EphemeralRunnerSpec.PodTemplateSpec.Spec.Containers[0].Image = "ghcr.io/actions/actions-runner:2.338.0"
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for range b.N {
|
|
if !ephemeralRunnerSetActionableSpecChanged(current, desired) {
|
|
b.Fatal("expected drift")
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkListenerPodSpecRequiresRecreation measures the listener pod drift
|
|
// check, which also runs on every AutoscalingListener reconcile.
|
|
func BenchmarkListenerPodSpecRequiresRecreation(b *testing.B) {
|
|
desired := desiredListenerPod()
|
|
live := livePodFromDesired(desired)
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for range b.N {
|
|
if listenerPodSpecRequiresRecreation(live, desired) {
|
|
b.Fatal("expected no recreation")
|
|
}
|
|
}
|
|
}
|