diff --git a/docs/usage/registry-cache/configuration.md b/docs/usage/registry-cache/configuration.md index b056a966..47bbe431 100644 --- a/docs/usage/registry-cache/configuration.md +++ b/docs/usage/registry-cache/configuration.md @@ -96,6 +96,15 @@ The `providerConfig.caches[].secretReferenceName` is the name of the reference f > [!NOTE] > It is only possible to provide one set of credentials for one private upstream registry. +The `providerConfig.caches[].proxy.httpProxy` field contains settings for a proxy which is used by the registry cache. +The registry-cache extension sets this value as `HTTP_PROXY` ENV in the StatefulSet. + +The `providerConfig.caches[].proxy.httpsProxy` field contains settings for a proxy which is used by the registry cache. +The registry-cache extension sets this value as `HTTPS_PROXY` ENV in the StatefulSet. + +The `providerConfig.caches[].proxy.noProxy` field contains settings for a proxy which is used by the registry cache. +The registry-cache extension sets this value as `NO_PROXY` ENV in the StatefulSet. + ## Garbage Collection When the registry cache receives a request for an image that is not present in its local store, it fetches the image from the upstream, returns it to the client and stores the image in the local store. The registry cache runs a scheduler that deletes images when their time to live (ttl) expires. When adding an image to the local store, the registry cache also adds a time to live for the image. The ttl defaults to `168h` (7 days) and is configurable. The garbage collection can be disabled by setting the ttl to `0s`. Requesting an image from the registry cache does not extend the time to live of the image. Hence, an image is always garbage collected from the registry cache store when its ttl expires. diff --git a/hack/api-reference/registry.md b/hack/api-reference/registry.md index 0ea8d807..17bd118a 100644 --- a/hack/api-reference/registry.md +++ b/hack/api-reference/registry.md @@ -44,6 +44,61 @@ Defaults to 168h (7 days).

+

Proxy +

+

+(Appears on: +RegistryCache) +

+

+

Proxy contains settings for a proxy used in the registry cache.

+

+ + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+httpProxy
+ +string + +
+(Optional) +

HTTPProxy is used as HTTP_PROXY env in the StatefulSet.

+
+httpsProxy
+ +string + +
+(Optional) +

HTTPSProxy is used as HTTPS_PROXY env in the StatefulSet.

+
+noProxy
+ +string + +
+(Optional) +

NoProxy is used as NO_PROXY env in the StatefulSet.

+

RegistryCache

@@ -129,6 +184,20 @@ string

SecretReferenceName is the name of the reference for the Secret containing the upstream registry credentials.

+ + +proxy
+ + +Proxy + + + + +(Optional) +

Proxy contains settings for a proxy used in the registry cache.

+ +

RegistryCacheStatus diff --git a/pkg/apis/registry/types.go b/pkg/apis/registry/types.go index d469db59..5a285afa 100644 --- a/pkg/apis/registry/types.go +++ b/pkg/apis/registry/types.go @@ -38,6 +38,8 @@ type RegistryCache struct { GarbageCollection *GarbageCollection // SecretReferenceName is the name of the reference for the Secret containing the upstream registry credentials SecretReferenceName *string + // Proxy contains settings for a proxy used in the registry cache. + Proxy *Proxy } // Volume contains settings for the registry cache volume. @@ -58,6 +60,16 @@ type GarbageCollection struct { TTL metav1.Duration } +// Proxy contains settings for a proxy used in the registry cache. +type Proxy struct { + // HTTPProxy is used as HTTP_PROXY env in the StatefulSet. + HTTPProxy *string + // HTTPSProxy is used as HTTPS_PROXY env in the StatefulSet. + HTTPSProxy *string + // NoProxy is used as NO_PROXY env in the StatefulSet. + NoProxy *string +} + var ( // DefaultTTL is the default time to live of a blob in the cache. DefaultTTL = metav1.Duration{Duration: 7 * 24 * time.Hour} diff --git a/pkg/apis/registry/v1alpha3/types.go b/pkg/apis/registry/v1alpha3/types.go index 74792cef..6fd49761 100644 --- a/pkg/apis/registry/v1alpha3/types.go +++ b/pkg/apis/registry/v1alpha3/types.go @@ -43,6 +43,9 @@ type RegistryCache struct { // SecretReferenceName is the name of the reference for the Secret containing the upstream registry credentials. // +optional SecretReferenceName *string `json:"secretReferenceName,omitempty"` + // Proxy contains settings for a proxy used in the registry cache. + // +optional + Proxy *Proxy `json:"proxy,omitempty"` } // Volume contains settings for the registry cache volume. @@ -66,6 +69,19 @@ type GarbageCollection struct { TTL metav1.Duration `json:"ttl"` } +// Proxy contains settings for a proxy used in the registry cache. +type Proxy struct { + // HTTPProxy is used as HTTP_PROXY env in the StatefulSet. + // +optional + HTTPProxy *string `json:"httpProxy"` + // HTTPSProxy is used as HTTPS_PROXY env in the StatefulSet. + // +optional + HTTPSProxy *string `json:"httpsProxy"` + // NoProxy is used as NO_PROXY env in the StatefulSet. + // +optional + NoProxy *string `json:"noProxy"` +} + var ( // DefaultTTL is the default time to live of a blob in the cache. DefaultTTL = metav1.Duration{Duration: 7 * 24 * time.Hour} diff --git a/pkg/apis/registry/v1alpha3/zz_generated.conversion.go b/pkg/apis/registry/v1alpha3/zz_generated.conversion.go index 4801e3e6..e2120b39 100644 --- a/pkg/apis/registry/v1alpha3/zz_generated.conversion.go +++ b/pkg/apis/registry/v1alpha3/zz_generated.conversion.go @@ -34,6 +34,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*Proxy)(nil), (*registry.Proxy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha3_Proxy_To_registry_Proxy(a.(*Proxy), b.(*registry.Proxy), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*registry.Proxy)(nil), (*Proxy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_registry_Proxy_To_v1alpha3_Proxy(a.(*registry.Proxy), b.(*Proxy), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*RegistryCache)(nil), (*registry.RegistryCache)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha3_RegistryCache_To_registry_RegistryCache(a.(*RegistryCache), b.(*registry.RegistryCache), scope) }); err != nil { @@ -107,12 +117,37 @@ func Convert_registry_GarbageCollection_To_v1alpha3_GarbageCollection(in *regist return autoConvert_registry_GarbageCollection_To_v1alpha3_GarbageCollection(in, out, s) } +func autoConvert_v1alpha3_Proxy_To_registry_Proxy(in *Proxy, out *registry.Proxy, s conversion.Scope) error { + out.HTTPProxy = (*string)(unsafe.Pointer(in.HTTPProxy)) + out.HTTPSProxy = (*string)(unsafe.Pointer(in.HTTPSProxy)) + out.NoProxy = (*string)(unsafe.Pointer(in.NoProxy)) + return nil +} + +// Convert_v1alpha3_Proxy_To_registry_Proxy is an autogenerated conversion function. +func Convert_v1alpha3_Proxy_To_registry_Proxy(in *Proxy, out *registry.Proxy, s conversion.Scope) error { + return autoConvert_v1alpha3_Proxy_To_registry_Proxy(in, out, s) +} + +func autoConvert_registry_Proxy_To_v1alpha3_Proxy(in *registry.Proxy, out *Proxy, s conversion.Scope) error { + out.HTTPProxy = (*string)(unsafe.Pointer(in.HTTPProxy)) + out.HTTPSProxy = (*string)(unsafe.Pointer(in.HTTPSProxy)) + out.NoProxy = (*string)(unsafe.Pointer(in.NoProxy)) + return nil +} + +// Convert_registry_Proxy_To_v1alpha3_Proxy is an autogenerated conversion function. +func Convert_registry_Proxy_To_v1alpha3_Proxy(in *registry.Proxy, out *Proxy, s conversion.Scope) error { + return autoConvert_registry_Proxy_To_v1alpha3_Proxy(in, out, s) +} + func autoConvert_v1alpha3_RegistryCache_To_registry_RegistryCache(in *RegistryCache, out *registry.RegistryCache, s conversion.Scope) error { out.Upstream = in.Upstream out.RemoteURL = (*string)(unsafe.Pointer(in.RemoteURL)) out.Volume = (*registry.Volume)(unsafe.Pointer(in.Volume)) out.GarbageCollection = (*registry.GarbageCollection)(unsafe.Pointer(in.GarbageCollection)) out.SecretReferenceName = (*string)(unsafe.Pointer(in.SecretReferenceName)) + out.Proxy = (*registry.Proxy)(unsafe.Pointer(in.Proxy)) return nil } @@ -127,6 +162,7 @@ func autoConvert_registry_RegistryCache_To_v1alpha3_RegistryCache(in *registry.R out.Volume = (*Volume)(unsafe.Pointer(in.Volume)) out.GarbageCollection = (*GarbageCollection)(unsafe.Pointer(in.GarbageCollection)) out.SecretReferenceName = (*string)(unsafe.Pointer(in.SecretReferenceName)) + out.Proxy = (*Proxy)(unsafe.Pointer(in.Proxy)) return nil } diff --git a/pkg/apis/registry/v1alpha3/zz_generated.deepcopy.go b/pkg/apis/registry/v1alpha3/zz_generated.deepcopy.go index 204e5317..ee70e874 100644 --- a/pkg/apis/registry/v1alpha3/zz_generated.deepcopy.go +++ b/pkg/apis/registry/v1alpha3/zz_generated.deepcopy.go @@ -29,6 +29,37 @@ func (in *GarbageCollection) DeepCopy() *GarbageCollection { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Proxy) DeepCopyInto(out *Proxy) { + *out = *in + if in.HTTPProxy != nil { + in, out := &in.HTTPProxy, &out.HTTPProxy + *out = new(string) + **out = **in + } + if in.HTTPSProxy != nil { + in, out := &in.HTTPSProxy, &out.HTTPSProxy + *out = new(string) + **out = **in + } + if in.NoProxy != nil { + in, out := &in.NoProxy, &out.NoProxy + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Proxy. +func (in *Proxy) DeepCopy() *Proxy { + if in == nil { + return nil + } + out := new(Proxy) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RegistryCache) DeepCopyInto(out *RegistryCache) { *out = *in @@ -52,6 +83,11 @@ func (in *RegistryCache) DeepCopyInto(out *RegistryCache) { *out = new(string) **out = **in } + if in.Proxy != nil { + in, out := &in.Proxy, &out.Proxy + *out = new(Proxy) + (*in).DeepCopyInto(*out) + } return } diff --git a/pkg/apis/registry/zz_generated.deepcopy.go b/pkg/apis/registry/zz_generated.deepcopy.go index 0e57aa7d..de6da303 100644 --- a/pkg/apis/registry/zz_generated.deepcopy.go +++ b/pkg/apis/registry/zz_generated.deepcopy.go @@ -29,6 +29,37 @@ func (in *GarbageCollection) DeepCopy() *GarbageCollection { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Proxy) DeepCopyInto(out *Proxy) { + *out = *in + if in.HTTPProxy != nil { + in, out := &in.HTTPProxy, &out.HTTPProxy + *out = new(string) + **out = **in + } + if in.HTTPSProxy != nil { + in, out := &in.HTTPSProxy, &out.HTTPSProxy + *out = new(string) + **out = **in + } + if in.NoProxy != nil { + in, out := &in.NoProxy, &out.NoProxy + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Proxy. +func (in *Proxy) DeepCopy() *Proxy { + if in == nil { + return nil + } + out := new(Proxy) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RegistryCache) DeepCopyInto(out *RegistryCache) { *out = *in @@ -52,6 +83,11 @@ func (in *RegistryCache) DeepCopyInto(out *RegistryCache) { *out = new(string) **out = **in } + if in.Proxy != nil { + in, out := &in.Proxy, &out.Proxy + *out = new(Proxy) + (*in).DeepCopyInto(*out) + } return } diff --git a/pkg/component/registrycaches/registry_caches.go b/pkg/component/registrycaches/registry_caches.go index e85dd498..05fa0ab6 100644 --- a/pkg/component/registrycaches/registry_caches.go +++ b/pkg/component/registrycaches/registry_caches.go @@ -380,6 +380,27 @@ func (r *registryCaches) computeResourcesDataForRegistryCache(ctx context.Contex }, } + if cache.Proxy != nil { + if cache.Proxy.HTTPProxy != nil { + statefulSet.Spec.Template.Spec.Containers[0].Env = append(statefulSet.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{ + Name: "HTTP_PROXY", + Value: *cache.Proxy.HTTPProxy, + }) + } + if cache.Proxy.HTTPSProxy != nil { + statefulSet.Spec.Template.Spec.Containers[0].Env = append(statefulSet.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{ + Name: "HTTPS_PROXY", + Value: *cache.Proxy.HTTPSProxy, + }) + } + if cache.Proxy.NoProxy != nil { + statefulSet.Spec.Template.Spec.Containers[0].Env = append(statefulSet.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{ + Name: "NO_PROXY", + Value: *cache.Proxy.NoProxy, + }) + } + } + var vpa *vpaautoscalingv1.VerticalPodAutoscaler if r.values.VPAEnabled { updateMode := vpaautoscalingv1.UpdateModeAuto diff --git a/pkg/component/registrycaches/registry_caches_test.go b/pkg/component/registrycaches/registry_caches_test.go index ff71a01a..4125ef2f 100644 --- a/pkg/component/registrycaches/registry_caches_test.go +++ b/pkg/component/registrycaches/registry_caches_test.go @@ -198,7 +198,7 @@ status: ` } - statefulSetYAMLFor = func(name, upstream, size, configSecretName string, storageClassName *string) string { + statefulSetYAMLFor = func(name, upstream, size, configSecretName string, storageClassName *string, additionalEnvs []corev1.EnvVar) string { out := `apiVersion: apps/v1 kind: StatefulSet metadata: @@ -228,7 +228,14 @@ spec: containers: - env: - name: OTEL_TRACES_EXPORTER - value: none + value: none` + for i := range additionalEnvs { + _ = i + out += ` + - name: ` + additionalEnvs[i].Name + ` + value: ` + additionalEnvs[i].Value + } + out += ` image: ` + image + ` imagePullPolicy: IfNotPresent livenessProbe: @@ -379,11 +386,11 @@ status: {} expectedManifests := []string{ configSecretYAMLFor(dockerConfigSecretName, "registry-docker-io", "docker.io", configYAMLFor("https://registry-1.docker.io", "336h0m0s", "", "")), serviceYAMLFor("registry-docker-io", "docker.io", "https://registry-1.docker.io"), - statefulSetYAMLFor("registry-docker-io", "docker.io", "10Gi", dockerConfigSecretName, nil), + statefulSetYAMLFor("registry-docker-io", "docker.io", "10Gi", dockerConfigSecretName, nil, nil), vpaYAMLFor("registry-docker-io"), configSecretYAMLFor(arConfigSecretName, "registry-europe-docker-pkg-dev", "europe-docker.pkg.dev", configYAMLFor("https://europe-docker.pkg.dev", "0s", "", "")), serviceYAMLFor("registry-europe-docker-pkg-dev", "europe-docker.pkg.dev", "https://europe-docker.pkg.dev"), - statefulSetYAMLFor("registry-europe-docker-pkg-dev", "europe-docker.pkg.dev", "20Gi", arConfigSecretName, ptr.To("premium")), + statefulSetYAMLFor("registry-europe-docker-pkg-dev", "europe-docker.pkg.dev", "20Gi", arConfigSecretName, ptr.To("premium"), nil), vpaYAMLFor("registry-europe-docker-pkg-dev"), } Expect(manifests).To(ConsistOf(expectedManifests)) @@ -411,10 +418,65 @@ status: {} expectedManifests := []string{ configSecretYAMLFor(dockerConfigSecretName, "registry-docker-io", "docker.io", configYAMLFor("https://registry-1.docker.io", "336h0m0s", "", "")), serviceYAMLFor("registry-docker-io", "docker.io", "https://registry-1.docker.io"), - statefulSetYAMLFor("registry-docker-io", "docker.io", "10Gi", dockerConfigSecretName, nil), + statefulSetYAMLFor("registry-docker-io", "docker.io", "10Gi", dockerConfigSecretName, nil, nil), + configSecretYAMLFor(arConfigSecretName, "registry-europe-docker-pkg-dev", "europe-docker.pkg.dev", configYAMLFor("https://europe-docker.pkg.dev", "0s", "", "")), + serviceYAMLFor("registry-europe-docker-pkg-dev", "europe-docker.pkg.dev", "https://europe-docker.pkg.dev"), + statefulSetYAMLFor("registry-europe-docker-pkg-dev", "europe-docker.pkg.dev", "20Gi", arConfigSecretName, ptr.To("premium"), nil), + } + Expect(manifests).To(ConsistOf(expectedManifests)) + }) + }) + + Context("when a proxy is set", func() { + BeforeEach(func() { + values.Caches[0].Proxy = &api.Proxy{ + HTTPProxy: ptr.To("http://127.0.0.1"), + HTTPSProxy: ptr.To("http://127.0.0.1"), + NoProxy: ptr.To("localhost"), + } + values.Caches[1].Proxy = &api.Proxy{ + HTTPProxy: ptr.To("http://127.0.0.1"), + HTTPSProxy: ptr.To("http://127.0.0.1"), + NoProxy: ptr.To("localhost"), + } + }) + + It("should successfully deploy the resources", func() { + Expect(registryCaches.Deploy(ctx)).To(Succeed()) + + Expect(c.Get(ctx, client.ObjectKeyFromObject(managedResource), managedResource)).To(Succeed()) + managedResourceSecret.Name = managedResource.Spec.SecretRefs[0].Name + Expect(c.Get(ctx, client.ObjectKeyFromObject(managedResourceSecret), managedResourceSecret)).To(Succeed()) + + manifests, err := test.ExtractManifestsFromManagedResourceData(managedResourceSecret.Data) + Expect(err).NotTo(HaveOccurred()) + Expect(manifests).To(HaveLen(8)) + + dockerConfigSecretName := "registry-docker-io-config-2935d46f" + arConfigSecretName := "registry-europe-docker-pkg-dev-config-245e2638" + additionalEnvs := []corev1.EnvVar{ + { + Name: "HTTP_PROXY", + Value: "http://127.0.0.1", + }, + { + Name: "HTTPS_PROXY", + Value: "http://127.0.0.1", + }, + { + Name: "NO_PROXY", + Value: "localhost", + }, + } + expectedManifests := []string{ + configSecretYAMLFor(dockerConfigSecretName, "registry-docker-io", "docker.io", configYAMLFor("https://registry-1.docker.io", "336h0m0s", "", "")), + serviceYAMLFor("registry-docker-io", "docker.io", "https://registry-1.docker.io"), + statefulSetYAMLFor("registry-docker-io", "docker.io", "10Gi", dockerConfigSecretName, nil, additionalEnvs), + vpaYAMLFor("registry-docker-io"), configSecretYAMLFor(arConfigSecretName, "registry-europe-docker-pkg-dev", "europe-docker.pkg.dev", configYAMLFor("https://europe-docker.pkg.dev", "0s", "", "")), serviceYAMLFor("registry-europe-docker-pkg-dev", "europe-docker.pkg.dev", "https://europe-docker.pkg.dev"), - statefulSetYAMLFor("registry-europe-docker-pkg-dev", "europe-docker.pkg.dev", "20Gi", arConfigSecretName, ptr.To("premium")), + statefulSetYAMLFor("registry-europe-docker-pkg-dev", "europe-docker.pkg.dev", "20Gi", arConfigSecretName, ptr.To("premium"), additionalEnvs), + vpaYAMLFor("registry-europe-docker-pkg-dev"), } Expect(manifests).To(ConsistOf(expectedManifests)) }) @@ -480,11 +542,11 @@ status: {} expectedManifests := []string{ configSecretYAMLFor(dockerConfigSecretName, "registry-docker-io", "docker.io", configYAMLFor("https://registry-1.docker.io", "336h0m0s", "docker-user", "s3cret")), serviceYAMLFor("registry-docker-io", "docker.io", "https://registry-1.docker.io"), - statefulSetYAMLFor("registry-docker-io", "docker.io", "10Gi", dockerConfigSecretName, nil), + statefulSetYAMLFor("registry-docker-io", "docker.io", "10Gi", dockerConfigSecretName, nil, nil), vpaYAMLFor("registry-docker-io"), configSecretYAMLFor(arConfigSecretName, "registry-europe-docker-pkg-dev", "europe-docker.pkg.dev", configYAMLFor("https://europe-docker.pkg.dev", "0s", "ar-user", `{"foo":"bar"}`)), serviceYAMLFor("registry-europe-docker-pkg-dev", "europe-docker.pkg.dev", "https://europe-docker.pkg.dev"), - statefulSetYAMLFor("registry-europe-docker-pkg-dev", "europe-docker.pkg.dev", "20Gi", arConfigSecretName, ptr.To("premium")), + statefulSetYAMLFor("registry-europe-docker-pkg-dev", "europe-docker.pkg.dev", "20Gi", arConfigSecretName, ptr.To("premium"), nil), vpaYAMLFor("registry-europe-docker-pkg-dev"), } Expect(manifests).To(ConsistOf(expectedManifests))