Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 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
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 behavior, set
``admission_controller.container_registry`` to ``gcr.io/datadoghq`` in your
``datadog.yaml`` or via the ``DD_ADMISSION_CONTROLLER_CONTAINER_REGISTRY``
environment variable.
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``) for lower latency and reduced egress. To restore the
previous default, set ``admission_controller.container_registry`` to
``gcr.io/datadoghq`` in your ``datadog.yaml`` or via the
``DD_ADMISSION_CONTROLLER_CONTAINER_REGISTRY`` environment variable.
Loading
Loading