mirror of
https://github.com/actions-runner-controller/actions-runner-controller.git
synced 2026-10-03 00:24:41 +02:00
Improve performance of controllers
This commit is contained in:
@@ -24,36 +24,37 @@ import (
|
||||
|
||||
// AutoscalingListenerSpec defines the desired state of AutoscalingListener
|
||||
type AutoscalingListenerSpec struct {
|
||||
// Required
|
||||
// +optional
|
||||
GitHubConfigURL string `json:"githubConfigUrl,omitempty"`
|
||||
|
||||
// Required
|
||||
// +optional
|
||||
GitHubConfigSecret string `json:"githubConfigSecret,omitempty"`
|
||||
|
||||
// Required
|
||||
// +optional
|
||||
// +kubebuilder:validation:Minimum=1
|
||||
RunnerScaleSetID int `json:"runnerScaleSetId,omitempty"`
|
||||
|
||||
// Required
|
||||
// +optional
|
||||
AutoscalingRunnerSetNamespace string `json:"autoscalingRunnerSetNamespace,omitempty"`
|
||||
|
||||
// Required
|
||||
// +optional
|
||||
AutoscalingRunnerSetName string `json:"autoscalingRunnerSetName,omitempty"`
|
||||
|
||||
// Required
|
||||
// +optional
|
||||
EphemeralRunnerSetName string `json:"ephemeralRunnerSetName,omitempty"`
|
||||
|
||||
// Required
|
||||
// +kubebuilder:validation:Minimum:=0
|
||||
MaxRunners int `json:"maxRunners,omitempty"`
|
||||
// +kubebuilder:validation:Minimum=0
|
||||
// +optional
|
||||
MaxRunners int `json:"maxRunners"`
|
||||
|
||||
// Required
|
||||
// +kubebuilder:validation:Minimum:=0
|
||||
MinRunners int `json:"minRunners,omitempty"`
|
||||
// +kubebuilder:validation:Minimum=0
|
||||
// +optional
|
||||
MinRunners int `json:"minRunners"`
|
||||
|
||||
// Required
|
||||
// +optional
|
||||
Image string `json:"image,omitempty"`
|
||||
|
||||
// Required
|
||||
// +optional
|
||||
ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"`
|
||||
|
||||
// +optional
|
||||
@@ -99,17 +100,22 @@ type AutoscalingListenerStatus struct{}
|
||||
|
||||
// AutoscalingListener is the Schema for the autoscalinglisteners API
|
||||
type AutoscalingListener struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// +optional
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec AutoscalingListenerSpec `json:"spec,omitempty"`
|
||||
// +optional
|
||||
Spec AutoscalingListenerSpec `json:"spec,omitempty"`
|
||||
// +optional
|
||||
Status AutoscalingListenerStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// AutoscalingListenerList is a list of AutoscalingListener resources
|
||||
// +kubebuilder:object:root=true
|
||||
// AutoscalingListenerList contains a list of AutoscalingListener
|
||||
type AutoscalingListenerList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// +optional
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []AutoscalingListener `json:"items"`
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/actions/actions-runner-controller/hash"
|
||||
"github.com/actions/actions-runner-controller/vault"
|
||||
@@ -37,22 +38,28 @@ import (
|
||||
// +kubebuilder:printcolumn:JSONPath=".spec.minRunners",name=Minimum Runners,type=integer
|
||||
// +kubebuilder:printcolumn:JSONPath=".spec.maxRunners",name=Maximum Runners,type=integer
|
||||
// +kubebuilder:printcolumn:JSONPath=".status.phase",name=Phase,type=string
|
||||
// +kubebuilder:printcolumn:JSONPath=".status.pendingEphemeralRunners",name=Pending Runners,type=integer
|
||||
// +kubebuilder:printcolumn:JSONPath=".status.runningEphemeralRunners",name=Running Runners,type=integer
|
||||
// +kubebuilder:printcolumn:JSONPath=".status.failedEphemeralRunners",name=Failed Runners,type=integer
|
||||
|
||||
// AutoscalingRunnerSet is the Schema for the autoscalingrunnersets API
|
||||
type AutoscalingRunnerSet struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// +optional
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec AutoscalingRunnerSetSpec `json:"spec,omitempty"`
|
||||
// +optional
|
||||
Spec AutoscalingRunnerSetSpec `json:"spec,omitempty"`
|
||||
// +optional
|
||||
Status AutoscalingRunnerSetStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// AutoscalingRunnerSetSpec defines the desired state of AutoscalingRunnerSet
|
||||
type AutoscalingRunnerSetSpec struct {
|
||||
// Required
|
||||
// +optional
|
||||
GitHubConfigUrl string `json:"githubConfigUrl,omitempty"`
|
||||
|
||||
// Required
|
||||
// +optional
|
||||
GitHubConfigSecret string `json:"githubConfigSecret,omitempty"`
|
||||
|
||||
// +optional
|
||||
@@ -73,7 +80,7 @@ type AutoscalingRunnerSetSpec struct {
|
||||
// +optional
|
||||
VaultConfig *VaultConfig `json:"vaultConfig,omitempty"`
|
||||
|
||||
// Required
|
||||
// +optional
|
||||
Template corev1.PodTemplateSpec `json:"template,omitempty"`
|
||||
|
||||
// +optional
|
||||
@@ -107,16 +114,16 @@ type AutoscalingRunnerSetSpec struct {
|
||||
EphemeralRunnerConfigSecretMetadata *ResourceMeta `json:"ephemeralRunnerConfigSecretMetadata,omitempty"`
|
||||
|
||||
// +optional
|
||||
// +kubebuilder:validation:Minimum:=0
|
||||
// +kubebuilder:validation:Minimum=0
|
||||
MaxRunners *int `json:"maxRunners,omitempty"`
|
||||
|
||||
// +optional
|
||||
// +kubebuilder:validation:Minimum:=0
|
||||
// +kubebuilder:validation:Minimum=0
|
||||
MinRunners *int `json:"minRunners,omitempty"`
|
||||
}
|
||||
|
||||
type TLSConfig struct {
|
||||
// Required
|
||||
// +required
|
||||
CertificateFrom *TLSCertificateSource `json:"certificateFrom,omitempty"`
|
||||
}
|
||||
|
||||
@@ -153,7 +160,7 @@ func (c *TLSConfig) ToCertPool(keyFetcher func(name, key string) ([]byte, error)
|
||||
}
|
||||
|
||||
type TLSCertificateSource struct {
|
||||
// Required
|
||||
// +required
|
||||
ConfigMapKeyRef *corev1.ConfigMapKeySelector `json:"configMapKeyRef,omitempty"`
|
||||
}
|
||||
|
||||
@@ -168,15 +175,33 @@ type ProxyConfig struct {
|
||||
NoProxy []string `json:"noProxy,omitempty"`
|
||||
}
|
||||
|
||||
var parsedProxyURLCache sync.Map
|
||||
|
||||
func parseProxyURLCached(rawURL string) (url.URL, error) {
|
||||
if cached, ok := parsedProxyURLCache.Load(rawURL); ok {
|
||||
if parsed, ok := cached.(url.URL); ok {
|
||||
return parsed, nil
|
||||
}
|
||||
}
|
||||
|
||||
parsed, err := url.Parse(rawURL)
|
||||
if err != nil {
|
||||
return url.URL{}, err
|
||||
}
|
||||
|
||||
parsedProxyURLCache.Store(rawURL, *parsed)
|
||||
return *parsed, nil
|
||||
}
|
||||
|
||||
func (c *ProxyConfig) ToHTTPProxyConfig(secretFetcher func(string) (*corev1.Secret, error)) (*httpproxy.Config, error) {
|
||||
config := &httpproxy.Config{
|
||||
NoProxy: strings.Join(c.NoProxy, ","),
|
||||
}
|
||||
|
||||
if c.HTTP != nil {
|
||||
u, err := url.Parse(c.HTTP.Url)
|
||||
u, err := parseProxyURLCached(c.HTTP.URL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse proxy http url %q: %w", c.HTTP.Url, err)
|
||||
return nil, fmt.Errorf("failed to parse proxy http url %q: %w", c.HTTP.URL, err)
|
||||
}
|
||||
|
||||
if c.HTTP.CredentialSecretRef != "" {
|
||||
@@ -199,9 +224,9 @@ func (c *ProxyConfig) ToHTTPProxyConfig(secretFetcher func(string) (*corev1.Secr
|
||||
}
|
||||
|
||||
if c.HTTPS != nil {
|
||||
u, err := url.Parse(c.HTTPS.Url)
|
||||
u, err := parseProxyURLCached(c.HTTPS.URL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse proxy https url %q: %w", c.HTTPS.Url, err)
|
||||
return nil, fmt.Errorf("failed to parse proxy https url %q: %w", c.HTTPS.URL, err)
|
||||
}
|
||||
|
||||
if c.HTTPS.CredentialSecretRef != "" {
|
||||
@@ -254,8 +279,8 @@ func (c *ProxyConfig) ProxyFunc(secretFetcher func(string) (*corev1.Secret, erro
|
||||
}
|
||||
|
||||
type ProxyServerConfig struct {
|
||||
// Required
|
||||
Url string `json:"url,omitempty"`
|
||||
// +required
|
||||
URL string `json:"url,omitempty"`
|
||||
|
||||
// +optional
|
||||
CredentialSecretRef string `json:"credentialSecretRef,omitempty"`
|
||||
@@ -309,8 +334,24 @@ type HistogramMetric struct {
|
||||
|
||||
// AutoscalingRunnerSetStatus defines the observed state of AutoscalingRunnerSet
|
||||
type AutoscalingRunnerSetStatus struct {
|
||||
// +optional
|
||||
// +kubebuilder:validation:Minimum=0
|
||||
CurrentRunners int `json:"currentRunners"`
|
||||
|
||||
// +optional
|
||||
Phase AutoscalingRunnerSetPhase `json:"phase"`
|
||||
|
||||
// EphemeralRunner counts separated by the stage ephemeral runners are in, taken from the EphemeralRunnerSet
|
||||
|
||||
// +optional
|
||||
// +kubebuilder:validation:Minimum=0
|
||||
PendingEphemeralRunners int `json:"pendingEphemeralRunners"`
|
||||
// +optional
|
||||
// +kubebuilder:validation:Minimum=0
|
||||
RunningEphemeralRunners int `json:"runningEphemeralRunners"`
|
||||
// +optional
|
||||
// +kubebuilder:validation:Minimum=0
|
||||
FailedEphemeralRunners int `json:"failedEphemeralRunners"`
|
||||
}
|
||||
|
||||
type AutoscalingRunnerSetPhase string
|
||||
@@ -323,20 +364,6 @@ const (
|
||||
AutoscalingRunnerSetPhaseOutdated AutoscalingRunnerSetPhase = "Outdated"
|
||||
)
|
||||
|
||||
func (ars *AutoscalingRunnerSet) Hash() string {
|
||||
type data struct {
|
||||
Spec *AutoscalingRunnerSetSpec
|
||||
Labels map[string]string
|
||||
}
|
||||
|
||||
d := &data{
|
||||
Spec: ars.Spec.DeepCopy(),
|
||||
Labels: ars.Labels,
|
||||
}
|
||||
|
||||
return hash.ComputeTemplateHash(d)
|
||||
}
|
||||
|
||||
func (ars *AutoscalingRunnerSet) ListenerSpecHash() string {
|
||||
arsSpec := ars.Spec.DeepCopy()
|
||||
spec := arsSpec
|
||||
|
||||
@@ -28,6 +28,7 @@ const EphemeralRunnerContainerName = "runner"
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:selectablefield:JSONPath=.status.phase
|
||||
// +kubebuilder:printcolumn:JSONPath=".spec.githubConfigUrl",name="GitHub Config URL",type=string
|
||||
// +kubebuilder:printcolumn:JSONPath=".status.runnerId",name=RunnerId,type=number
|
||||
// +kubebuilder:printcolumn:JSONPath=".status.phase",name=Phase,type=string
|
||||
@@ -41,10 +42,13 @@ const EphemeralRunnerContainerName = "runner"
|
||||
|
||||
// EphemeralRunner is the Schema for the ephemeralrunners API
|
||||
type EphemeralRunner struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// +optional
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec EphemeralRunnerSpec `json:"spec,omitempty"`
|
||||
// +optional
|
||||
Spec EphemeralRunnerSpec `json:"spec,omitempty"`
|
||||
// +optional
|
||||
Status EphemeralRunnerStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
@@ -102,17 +106,17 @@ func (er *EphemeralRunner) VaultProxy() *ProxyConfig {
|
||||
|
||||
// EphemeralRunnerSpec defines the desired state of EphemeralRunner
|
||||
type EphemeralRunnerSpec struct {
|
||||
// +required
|
||||
// +optional
|
||||
GitHubConfigURL string `json:"githubConfigUrl,omitempty"`
|
||||
|
||||
// +required
|
||||
// +optional
|
||||
GitHubConfigSecret string `json:"githubConfigSecret,omitempty"`
|
||||
|
||||
// +optional
|
||||
GitHubServerTLS *TLSConfig `json:"githubServerTLS,omitempty"`
|
||||
|
||||
// +required
|
||||
RunnerScaleSetID int `json:"runnerScaleSetId,omitempty"`
|
||||
// +optional
|
||||
RunnerScaleSetID int `json:"runnerScaleSetId"`
|
||||
|
||||
// +optional
|
||||
Proxy *ProxyConfig `json:"proxy,omitempty"`
|
||||
@@ -126,6 +130,7 @@ type EphemeralRunnerSpec struct {
|
||||
// +optional
|
||||
EphemeralRunnerConfigSecretMetadata *ResourceMeta `json:"ephemeralRunnerConfigSecretMetadata,omitempty"`
|
||||
|
||||
// +optional
|
||||
corev1.PodTemplateSpec `json:",inline"`
|
||||
}
|
||||
|
||||
|
||||
@@ -23,10 +23,13 @@ import (
|
||||
// EphemeralRunnerSetSpec defines the desired state of EphemeralRunnerSet
|
||||
type EphemeralRunnerSetSpec struct {
|
||||
// Replicas is the number of desired EphemeralRunner resources in the k8s namespace.
|
||||
// +optional
|
||||
Replicas int `json:"replicas,omitempty"`
|
||||
// PatchID is the unique identifier for the patch issued by the listener app
|
||||
// +optional
|
||||
PatchID int `json:"patchID"`
|
||||
// EphemeralRunnerSpec is the spec of the ephemeral runner
|
||||
// +optional
|
||||
EphemeralRunnerSpec EphemeralRunnerSpec `json:"ephemeralRunnerSpec,omitempty"`
|
||||
// EphemeralRunnerMetadata is the metadata to be applied to all ephemeral runners created by this set.
|
||||
// If the EphemeralRunnerMetadata is updated, the update applies to new ephemeral runners created after the update,
|
||||
@@ -37,6 +40,27 @@ type EphemeralRunnerSetSpec struct {
|
||||
|
||||
// EphemeralRunnerSetStatus defines the observed state of EphemeralRunnerSet
|
||||
type EphemeralRunnerSetStatus struct {
|
||||
// CurrentReplicas is the number of currently running EphemeralRunner resources being managed by this EphemeralRunnerSet.
|
||||
// +kubebuilder:validation:Minimum=0
|
||||
// +optional
|
||||
CurrentReplicas int `json:"currentReplicas"`
|
||||
// +optional
|
||||
// +kubebuilder:validation:Minimum=0
|
||||
PendingEphemeralRunners int `json:"pendingEphemeralRunners"`
|
||||
// +optional
|
||||
// +kubebuilder:validation:Minimum=0
|
||||
RunningEphemeralRunners int `json:"runningEphemeralRunners"`
|
||||
// +optional
|
||||
// +kubebuilder:validation:Minimum=0
|
||||
FailedEphemeralRunners int `json:"failedEphemeralRunners"`
|
||||
// ReservedReplicas is the controller's checkpointed scale decision for the current patch.
|
||||
// It may be higher than CurrentaReplicas while the listener has not yet patched the desired count after runners complete.
|
||||
// +optional
|
||||
// +kubebuilder:validation:Minimum=0
|
||||
ReservedReplicas int `json:"reservedReplicas,omitempty"`
|
||||
// ReservedPatchID is the patch ID associated with ReservedReplicas.
|
||||
// +optional
|
||||
ReservedPatchID int `json:"reservedPatchID,omitempty"`
|
||||
// +optional
|
||||
Phase EphemeralRunnerSetPhase `json:"phase"`
|
||||
}
|
||||
@@ -58,10 +82,13 @@ const (
|
||||
|
||||
// EphemeralRunnerSet is the Schema for the ephemeralrunnersets API
|
||||
type EphemeralRunnerSet struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// +optional
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec EphemeralRunnerSetSpec `json:"spec,omitempty"`
|
||||
// +optional
|
||||
Spec EphemeralRunnerSetSpec `json:"spec,omitempty"`
|
||||
// +optional
|
||||
Status EphemeralRunnerSetStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
|
||||
@@ -14,11 +14,11 @@ import (
|
||||
func TestProxyConfig_ToSecret(t *testing.T) {
|
||||
config := &v1alpha1.ProxyConfig{
|
||||
HTTP: &v1alpha1.ProxyServerConfig{
|
||||
Url: "http://proxy.example.com:8080",
|
||||
URL: "http://proxy.example.com:8080",
|
||||
CredentialSecretRef: "my-secret",
|
||||
},
|
||||
HTTPS: &v1alpha1.ProxyServerConfig{
|
||||
Url: "https://proxy.example.com:8080",
|
||||
URL: "https://proxy.example.com:8080",
|
||||
CredentialSecretRef: "my-secret",
|
||||
},
|
||||
NoProxy: []string{
|
||||
@@ -48,11 +48,11 @@ func TestProxyConfig_ToSecret(t *testing.T) {
|
||||
func TestProxyConfig_ProxyFunc(t *testing.T) {
|
||||
config := &v1alpha1.ProxyConfig{
|
||||
HTTP: &v1alpha1.ProxyServerConfig{
|
||||
Url: "http://proxy.example.com:8080",
|
||||
URL: "http://proxy.example.com:8080",
|
||||
CredentialSecretRef: "my-secret",
|
||||
},
|
||||
HTTPS: &v1alpha1.ProxyServerConfig{
|
||||
Url: "https://proxy.example.com:8080",
|
||||
URL: "https://proxy.example.com:8080",
|
||||
CredentialSecretRef: "my-secret",
|
||||
},
|
||||
NoProxy: []string{
|
||||
|
||||
Reference in New Issue
Block a user