Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1207,6 +1207,15 @@ workflow:
compare_to: $COMPARE_TO_BRANCH
when: on_success

.on_admission_controller_or_e2e_changes:
- !reference [.on_e2e_main_release_or_rc]
- changes:
paths:
- pkg/clusteragent/admission/**/*
- pkg/util/kubernetes/cloudprovider/**/*
- test/new-e2e/tests/admission-controller/**/*
compare_to: $COMPARE_TO_BRANCH

.on_ssi_or_e2e_changes:
- !reference [.on_e2e_main_release_or_rc]
- changes:
Expand Down
31 changes: 31 additions & 0 deletions .gitlab/test/e2e/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -949,6 +949,37 @@ new-e2e-otel:
TEAM: otel
ON_NIGHTLY_FIPS: "true"

.new-e2e_admission_controller:
extends: .new_e2e_template
rules:
- !reference [.on_admission_controller_or_e2e_changes]
- !reference [.manual]
needs:
- !reference [.needs_new_e2e_template]
- qa_dca
- qa_agent_linux
variables:
TARGETS: ./tests/admission-controller
TEAM: container-integrations

new-e2e-admission-controller-kind:
extends: .new-e2e_admission_controller
variables:
E2E_PROVISIONER: kind
E2E_STACK_NAME_SUFFIX: kind

new-e2e-admission-controller-eks:
extends: .new-e2e_admission_controller
variables:
E2E_PROVISIONER: eks
E2E_STACK_NAME_SUFFIX: eks

new-e2e-admission-controller-gke:
extends: .new-e2e_admission_controller
variables:
E2E_PROVISIONER: gke
E2E_STACK_NAME_SUFFIX: gke

.new-e2e_ssi:
extends: .new_e2e_template
rules:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func NewWebhook(datadogConfig config.Component) *Webhook {

nsSelector, objSelector := labelSelectors(datadogConfig, profileOverrides)

containerRegistry := mutatecommon.ContainerRegistry(datadogConfig, "admission_controller.agent_sidecar.container_registry")
containerRegistry := mutatecommon.ContainerRegistry(context.TODO(), datadogConfig, "admission_controller.agent_sidecar.container_registry")

return &Webhook{
name: webhookName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -697,8 +697,8 @@ func TestDefaultSidecarTemplateAgentImage(t *testing.T) {
{
name: "no configuration set",
setConfig: func() model.Config { return configmock.New(t) },
containerRegistry: commonRegistry,
expectedImage: commonRegistry + "/agent:latest",
containerRegistry: "registry.datadoghq.com",
expectedImage: "registry.datadoghq.com/agent:latest",
},
{
name: "setting custom registry, image and tag",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1381,7 +1381,7 @@ func TestAutoinstrumentation(t *testing.T) {
shouldMutate: true,
expected: &expected{
initContainerImages: []string{
"gcr.io/datadoghq/dd-lib-php-init:v1",
"registry.datadoghq.com/dd-lib-php-init:v1",
"docker.io/library/apm-inject-package:v27",
},
containerNames: defaultContainerNames,
Expand Down Expand Up @@ -1409,7 +1409,7 @@ func TestAutoinstrumentation(t *testing.T) {
shouldMutate: true,
expected: &expected{
initContainerImages: []string{
"gcr.io/datadoghq/apm-inject:0",
"registry.datadoghq.com/apm-inject:0",
"foo/bar:1",
},
containerNames: defaultContainerNames,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package autoinstrumentation

import (
"context"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -125,7 +126,7 @@ func NewConfig(datadogConfig config.Component) (*Config, error) {
return nil, fmt.Errorf("unable to parse init-container's resources from configuration: %w", err)
}

containerRegistry := mutatecommon.ContainerRegistry(datadogConfig, "admission_controller.auto_instrumentation.container_registry")
containerRegistry := mutatecommon.ContainerRegistry(context.TODO(), datadogConfig, "admission_controller.auto_instrumentation.container_registry")
mutateUnlabelled := datadogConfig.GetBool("admission_controller.mutate_unlabelled")

return &Config{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func TestNewConfig(t *testing.T) {
},
expectedState: Config{
Site: "datadoghq.com",
DDRegistries: map[string]struct{}{"gcr.io/datadoghq": {}, "docker.io/datadog": {}, "public.ecr.aws/datadog": {}},
DDRegistries: map[string]struct{}{"gcr.io/datadoghq": {}, "docker.io/datadog": {}, "public.ecr.aws/datadog": {}, "datadoghq.azurecr.io": {}, "registry.datadoghq.com": {}},
BucketID: "2",
DigestCacheTTL: 1 * time.Hour,
Enabled: true,
Expand Down Expand Up @@ -64,7 +64,7 @@ func TestNewConfig(t *testing.T) {
},
expectedState: Config{
Site: "datad0g.com",
DDRegistries: map[string]struct{}{"gcr.io/datadoghq": {}, "docker.io/datadog": {}, "public.ecr.aws/datadog": {}},
DDRegistries: map[string]struct{}{"gcr.io/datadoghq": {}, "docker.io/datadog": {}, "public.ecr.aws/datadog": {}, "datadoghq.azurecr.io": {}, "registry.datadoghq.com": {}},
BucketID: "2",
DigestCacheTTL: 1 * time.Hour,
Enabled: true,
Expand All @@ -80,7 +80,7 @@ func TestNewConfig(t *testing.T) {
},
expectedState: Config{
Site: "datadoghq.com",
DDRegistries: map[string]struct{}{"gcr.io/datadoghq": {}, "docker.io/datadog": {}, "public.ecr.aws/datadog": {}},
DDRegistries: map[string]struct{}{"gcr.io/datadoghq": {}, "docker.io/datadog": {}, "public.ecr.aws/datadog": {}, "datadoghq.azurecr.io": {}, "registry.datadoghq.com": {}},
BucketID: "0",
DigestCacheTTL: 1 * time.Hour,
Enabled: true,
Expand All @@ -97,7 +97,7 @@ func TestNewConfig(t *testing.T) {
},
expectedState: Config{
Site: "datadoghq.com",
DDRegistries: map[string]struct{}{"gcr.io/datadoghq": {}, "docker.io/datadog": {}, "public.ecr.aws/datadog": {}},
DDRegistries: map[string]struct{}{"gcr.io/datadoghq": {}, "docker.io/datadog": {}, "public.ecr.aws/datadog": {}, "datadoghq.azurecr.io": {}, "registry.datadoghq.com": {}},
BucketID: "0",
DigestCacheTTL: 1 * time.Hour,
Enabled: false,
Expand All @@ -114,7 +114,7 @@ func TestNewConfig(t *testing.T) {
},
expectedState: Config{
Site: "datadoghq.com",
DDRegistries: map[string]struct{}{"gcr.io/datadoghq": {}, "docker.io/datadog": {}, "public.ecr.aws/datadog": {}},
DDRegistries: map[string]struct{}{"gcr.io/datadoghq": {}, "docker.io/datadog": {}, "public.ecr.aws/datadog": {}, "datadoghq.azurecr.io": {}, "registry.datadoghq.com": {}},
BucketID: "0",
DigestCacheTTL: 2 * time.Hour,
Enabled: true,
Expand Down
35 changes: 31 additions & 4 deletions pkg/clusteragent/admission/mutate/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
package common

import (
"context"
"encoding/json"
"fmt"
"slices"
Expand All @@ -21,6 +22,7 @@ import (

"github.com/DataDog/datadog-agent/comp/core/config"
"github.com/DataDog/datadog-agent/pkg/clusteragent/admission/metrics"
"github.com/DataDog/datadog-agent/pkg/util/kubernetes/cloudprovider"
"github.com/DataDog/datadog-agent/pkg/util/log"
)

Expand Down Expand Up @@ -195,15 +197,40 @@ func containsVolumeMount(volumeMounts []corev1.VolumeMount, element corev1.Volum
return false
}

// defaultRegistryForProvider returns the preferred container registry for the
// given cloud provider. This follows the Datadog recommendation of using
// cloud-provider-specific registries for lower latency and reduced egress.
func defaultRegistryForProvider(provider string) string {
switch provider {
case "eks":
return "public.ecr.aws/datadog"
case "gke":
return "gcr.io/datadoghq"
case "aks":
return "datadoghq.azurecr.io"
default:
return "registry.datadoghq.com"
}
}

// ContainerRegistry gets the container registry config using the specified
// config option, and falls back to the default container registry if no
// webhook-specific container registry is set.
func ContainerRegistry(datadogConfig config.Component, specificConfigOpt string) string {
if datadogConfig.IsSet(specificConfigOpt) {
// webhook-specific container registry is set. If no global registry is
// explicitly configured, it auto-selects based on the detected cloud provider,
// falling back to registry.datadoghq.com.
func ContainerRegistry(ctx context.Context, datadogConfig config.Component, specificConfigOpt string) string {
if datadogConfig.IsConfigured(specificConfigOpt) {
return datadogConfig.GetString(specificConfigOpt)
}

return datadogConfig.GetString("admission_controller.container_registry")
if datadogConfig.IsConfigured("admission_controller.container_registry") {
return datadogConfig.GetString("admission_controller.container_registry")
}

provider := cloudprovider.DCAGetName(ctx)
registry := defaultRegistryForProvider(provider)
log.Infof("Auto-detected cloud provider %q, using container registry %q", provider, registry)
return registry
}

// MarkVolumeAsSafeToEvictForAutoscaler adds the Kubernetes cluster-autoscaler
Expand Down
66 changes: 66 additions & 0 deletions pkg/clusteragent/admission/mutate/common/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@
package common

import (
"context"
"reflect"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"

configmock "github.com/DataDog/datadog-agent/pkg/config/mock"
)

func Test_contains(t *testing.T) {
Expand Down Expand Up @@ -324,3 +327,66 @@ func TestMarkVolumeAsSafeToEvictForAutoscaler(t *testing.T) {
}

}

func Test_defaultRegistryForProvider(t *testing.T) {
tests := []struct {
provider string
expected string
}{
{"eks", "public.ecr.aws/datadog"},
{"gke", "gcr.io/datadoghq"},
{"aks", "datadoghq.azurecr.io"},
{"", "registry.datadoghq.com"},
{"unknown", "registry.datadoghq.com"},
}

for _, tt := range tests {
t.Run("provider_"+tt.provider, func(t *testing.T) {
assert.Equal(t, tt.expected, defaultRegistryForProvider(tt.provider))
})
}
}

func Test_ContainerRegistry(t *testing.T) {
tests := []struct {
name string
specificKey string
specificValue string
globalValue string
expectedPrefix string
}{
{
name: "webhook-specific config wins",
specificKey: "admission_controller.auto_instrumentation.container_registry",
specificValue: "my-custom-registry.io/datadog",
globalValue: "global-registry.io/datadog",
expectedPrefix: "my-custom-registry.io/datadog",
},
{
name: "global config used when no specific config",
specificKey: "admission_controller.auto_instrumentation.container_registry",
globalValue: "global-registry.io/datadog",
expectedPrefix: "global-registry.io/datadog",
},
{
name: "auto-detection when no config set",
specificKey: "admission_controller.auto_instrumentation.container_registry",
expectedPrefix: "registry.datadoghq.com", // no cloud provider detected in tests → default
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockConfig := configmock.New(t)
if tt.specificValue != "" {
mockConfig.SetWithoutSource(tt.specificKey, tt.specificValue)
}
if tt.globalValue != "" {
mockConfig.SetWithoutSource("admission_controller.container_registry", tt.globalValue)
}

result := ContainerRegistry(context.TODO(), mockConfig, tt.specificKey)
assert.Equal(t, tt.expectedPrefix, result)
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ func NewCWSInstrumentation(wmeta workloadmeta.Component, datadogConfig config.Co
cwsInjectorImageName := pkgconfigsetup.Datadog().GetString("admission_controller.cws_instrumentation.image_name")
cwsInjectorImageTag := pkgconfigsetup.Datadog().GetString("admission_controller.cws_instrumentation.image_tag")

cwsInjectorContainerRegistry := mutatecommon.ContainerRegistry(datadogConfig, "admission_controller.cws_instrumentation.container_registry")
cwsInjectorContainerRegistry := mutatecommon.ContainerRegistry(context.TODO(), datadogConfig, "admission_controller.cws_instrumentation.container_registry")

if len(cwsInjectorImageName) == 0 {
return nil, errors.New("can't initialize CWS Instrumentation without an image_name")
Expand Down
4 changes: 3 additions & 1 deletion pkg/config/setup/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -951,7 +951,7 @@ func InitConfig(config pkgconfigmodel.Setup) {
config.BindEnvAndSetDefault("admission_controller.mutation.enabled", true)
config.BindEnvAndSetDefault("admission_controller.mutate_unlabelled", false)
config.BindEnvAndSetDefault("admission_controller.port", 8000)
config.BindEnvAndSetDefault("admission_controller.container_registry", "gcr.io/datadoghq")
config.BindEnvAndSetDefault("admission_controller.container_registry", "registry.datadoghq.com")
config.BindEnvAndSetDefault("admission_controller.timeout_seconds", 10) // in seconds (see kubernetes/kubernetes#71508)
config.BindEnvAndSetDefault("admission_controller.service_name", "datadog-admission-controller")
config.BindEnvAndSetDefault("admission_controller.certificate.validity_bound", 365*24) // validity bound of the certificate created by the controller (in hours, default 1 year)
Expand Down Expand Up @@ -984,6 +984,8 @@ func InitConfig(config pkgconfigmodel.Setup) {
"gcr.io/datadoghq",
"docker.io/datadog",
"public.ecr.aws/datadog",
"datadoghq.azurecr.io",
"registry.datadoghq.com",
})
config.BindEnvAndSetDefault("admission_controller.auto_instrumentation.gradual_rollout.enabled", true)
config.BindEnvAndSetDefault("admission_controller.auto_instrumentation.gradual_rollout.cache_ttl", "1h")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
enhancements:
- |
The admission controller now auto-selects the container registry based on the
detected cloud provider (EKS uses ``public.ecr.aws/datadog``, GKE uses
``gcr.io/datadoghq``, AKS uses ``datadoghq.azurecr.io``). The new default for
environments where no cloud provider is detected is ``registry.datadoghq.com``
(previously ``gcr.io/datadoghq``). Explicit configuration via
``admission_controller.container_registry`` or webhook-specific overrides still
takes precedence. To restore the previous default, set
``admission_controller.container_registry`` to ``gcr.io/datadoghq``. See
`Changing your container registry <https://docs.datadoghq.com/containers/guide/changing_container_registry/>`_
for all available registries and configuration options.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
enhancements:
- |
The default container registry for the admission controller has changed from
``gcr.io/datadoghq`` to ``registry.datadoghq.com``. On managed Kubernetes
environments, the cluster agent now auto-selects a cloud-provider-specific
registry (EKS: ``public.ecr.aws/datadog``, GKE: ``gcr.io/datadoghq``, AKS:
``datadoghq.azurecr.io``). To restore the previous default, set
``admission_controller.container_registry`` to ``gcr.io/datadoghq``. See
`Changing your container registry <https://docs.datadoghq.com/containers/guide/changing_container_registry/>`_
for all available registries and configuration options.
Loading
Loading