feat(traefik)!: disable legacy listeners on traefik.containo.us API Group (#5565)

* feat(traefik)!: disable legacy listeners on traefik.containo.us API Group

* update docs accordingly

* update test accordingly

* type argument is infered

* fix rebase
This commit is contained in:
Michel Loiseleur 2025-07-03 18:15:27 +02:00 committed by GitHub
parent fc4a2cb6ac
commit 8cc73bd1e4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 37 additions and 47 deletions

View File

@ -50,7 +50,7 @@
| `--service-type-filter=SERVICE-TYPE-FILTER` | The service types to filter by. Specify multiple times for multiple filters to be applied. (optional, default: all, expected: ClusterIP, NodePort, LoadBalancer or ExternalName) |
| `--source=source` | The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, node, pod, fake, connector, gateway-httproute, gateway-grpcroute, gateway-tlsroute, gateway-tcproute, gateway-udproute, istio-gateway, istio-virtualservice, cloudfoundry, contour-httpproxy, gloo-proxy, crd, empty, skipper-routegroup, openshift-route, ambassador-host, kong-tcpingress, f5-virtualserver, f5-transportserver, traefik-proxy) |
| `--target-net-filter=TARGET-NET-FILTER` | Limit possible targets by a net filter; specify multiple times for multiple possible nets (optional) |
| `--[no-]traefik-disable-legacy` | Disable listeners on Resources under the traefik.containo.us API Group |
| `--[no-]traefik-enable-legacy` | Enable legacy listeners on Resources under the traefik.containo.us API Group |
| `--[no-]traefik-disable-new` | Disable listeners on Resources under the traefik.io API Group |
| `--provider=provider` | The DNS provider where the DNS records will be created (required, options: akamai, alibabacloud, aws, aws-sd, azure, azure-dns, azure-private-dns, civo, cloudflare, coredns, digitalocean, dnsimple, exoscale, gandi, godaddy, google, inmemory, linode, ns1, oci, ovh, pdns, pihole, plural, rfc2136, scaleway, skydns, transip, webhook) |
| `--provider-cache-time=0s` | The time to cache the DNS provider record list requests. |

View File

@ -82,15 +82,11 @@ kubectl delete -f externaldns.yaml
| Flag | Description |
|--------------------------|----------------------------------------------------------|
| --traefik-disable-legacy | Disable listeners on Resources under traefik.containo.us |
| --traefik-enable-legacy | Enable listeners on Resources under traefik.containo.us |
| --traefik-disable-new | Disable listeners on Resources under traefik.io |
### Disabling Resource Listeners
### Resource Listeners
Traefik has deprecated the legacy API group, `traefik.containo.us`, in favor of `traefik.io`. By default the `traefik-proxy` source will listen for resources under both API groups; however, this may cause timeouts with the following message
Traefik has deprecated the legacy API group, _traefik.containo.us_, in favor of _traefik.io_. By default the `traefik-proxy` source listen for resources under traefik.io API groups.
```sh
FATA[0060] failed to sync traefik.io/v1alpha1, Resource=ingressroutes: context deadline exceeded
```
In this case you can disable one or the other API groups with `--traefik-disable-new` or `--traefik-disable-legacy`
If needed, you can enable legacy listener with `--traefik-enable-legacy` and also disable new listener with `--traefik-disable-new`.

View File

@ -209,7 +209,7 @@ type Config struct {
WebhookProviderReadTimeout time.Duration
WebhookProviderWriteTimeout time.Duration
WebhookServer bool
TraefikDisableLegacy bool
TraefikEnableLegacy bool
TraefikDisableNew bool
NAT64Networks []string
ExcludeUnschedulable bool
@ -359,7 +359,7 @@ var defaultConfig = &Config{
TLSCA: "",
TLSClientCert: "",
TLSClientCertKey: "",
TraefikDisableLegacy: false,
TraefikEnableLegacy: false,
TraefikDisableNew: false,
TransIPAccountName: "",
TransIPPrivateKeyFile: "",
@ -486,7 +486,7 @@ func App(cfg *Config) *kingpin.Application {
app.Flag("service-type-filter", "The service types to filter by. Specify multiple times for multiple filters to be applied. (optional, default: all, expected: ClusterIP, NodePort, LoadBalancer or ExternalName)").Default(defaultConfig.ServiceTypeFilter...).StringsVar(&cfg.ServiceTypeFilter)
app.Flag("source", "The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, node, pod, fake, connector, gateway-httproute, gateway-grpcroute, gateway-tlsroute, gateway-tcproute, gateway-udproute, istio-gateway, istio-virtualservice, cloudfoundry, contour-httpproxy, gloo-proxy, crd, empty, skipper-routegroup, openshift-route, ambassador-host, kong-tcpingress, f5-virtualserver, f5-transportserver, traefik-proxy)").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "node", "pod", "gateway-httproute", "gateway-grpcroute", "gateway-tlsroute", "gateway-tcproute", "gateway-udproute", "istio-gateway", "istio-virtualservice", "cloudfoundry", "contour-httpproxy", "gloo-proxy", "fake", "connector", "crd", "empty", "skipper-routegroup", "openshift-route", "ambassador-host", "kong-tcpingress", "f5-virtualserver", "f5-transportserver", "traefik-proxy")
app.Flag("target-net-filter", "Limit possible targets by a net filter; specify multiple times for multiple possible nets (optional)").StringsVar(&cfg.TargetNetFilter)
app.Flag("traefik-disable-legacy", "Disable listeners on Resources under the traefik.containo.us API Group").Default(strconv.FormatBool(defaultConfig.TraefikDisableLegacy)).BoolVar(&cfg.TraefikDisableLegacy)
app.Flag("traefik-enable-legacy", "Enable legacy listeners on Resources under the traefik.containo.us API Group").Default(strconv.FormatBool(defaultConfig.TraefikEnableLegacy)).BoolVar(&cfg.TraefikEnableLegacy)
app.Flag("traefik-disable-new", "Disable listeners on Resources under the traefik.io API Group").Default(strconv.FormatBool(defaultConfig.TraefikDisableNew)).BoolVar(&cfg.TraefikDisableNew)
// Flags related to providers

View File

@ -96,7 +96,7 @@ type Config struct {
OCPRouterName string
UpdateEvents bool
ResolveLoadBalancerHostname bool
TraefikDisableLegacy bool
TraefikEnableLegacy bool
TraefikDisableNew bool
ExcludeUnschedulable bool
ExposeInternalIPv6 bool
@ -142,7 +142,7 @@ func NewSourceConfig(cfg *externaldns.Config) *Config {
OCPRouterName: cfg.OCPRouterName,
UpdateEvents: cfg.UpdateEvents,
ResolveLoadBalancerHostname: cfg.ResolveServiceLoadBalancerHostname,
TraefikDisableLegacy: cfg.TraefikDisableLegacy,
TraefikEnableLegacy: cfg.TraefikEnableLegacy,
TraefikDisableNew: cfg.TraefikDisableNew,
ExcludeUnschedulable: cfg.ExcludeUnschedulable,
ExposeInternalIPv6: cfg.ExposeInternalIPV6,
@ -533,7 +533,7 @@ func buildTraefikProxySource(ctx context.Context, p ClientGenerator, cfg *Config
if err != nil {
return nil, err
}
return NewTraefikSource(ctx, dynamicClient, kubernetesClient, cfg.Namespace, cfg.AnnotationFilter, cfg.IgnoreHostnameAnnotation, cfg.TraefikDisableLegacy, cfg.TraefikDisableNew)
return NewTraefikSource(ctx, dynamicClient, kubernetesClient, cfg.Namespace, cfg.AnnotationFilter, cfg.IgnoreHostnameAnnotation, cfg.TraefikEnableLegacy, cfg.TraefikDisableNew)
}
func buildOpenShiftRouteSource(ctx context.Context, p ClientGenerator, cfg *Config) (Source, error) {

View File

@ -100,7 +100,8 @@ func NewTraefikSource(
dynamicKubeClient dynamic.Interface,
kubeClient kubernetes.Interface,
namespace, annotationFilter string,
ignoreHostnameAnnotation, disableLegacy, disableNew bool) (Source, error) {
ignoreHostnameAnnotation, enableLegacy, disableNew bool,
) (Source, error) {
// Use shared informer to listen for add/update/delete of Host in the specified namespace.
// Set resync period to 0, to prevent processing when nothing has changed.
informerFactory := dynamicinformer.NewFilteredDynamicSharedInformerFactory(dynamicKubeClient, 0, namespace, nil)
@ -128,7 +129,7 @@ func NewTraefikSource(
},
)
}
if !disableLegacy {
if enableLegacy {
oldIngressRouteInformer = informerFactory.ForResource(oldIngressRouteGVR)
oldIngressRouteTcpInformer = informerFactory.ForResource(oldIngressRouteTCPGVR)
oldIngressRouteUdpInformer = informerFactory.ForResource(oldIngressRouteUDPGVR)
@ -232,7 +233,7 @@ func (ts *traefikSource) Endpoints(_ context.Context) ([]*endpoint.Endpoint, err
// ingressRouteEndpoints extracts endpoints from all IngressRoute objects
func (ts *traefikSource) ingressRouteEndpoints() ([]*endpoint.Endpoint, error) {
return extractEndpoints[IngressRoute](
return extractEndpoints(
ts.ingressRouteInformer.Lister(),
ts.namespace,
func(u *unstructured.Unstructured) (*IngressRoute, error) {
@ -297,7 +298,7 @@ func (ts *traefikSource) ingressRouteTCPEndpoints() ([]*endpoint.Endpoint, error
// ingressRouteUDPEndpoints extracts endpoints from all IngressRouteUDP objects
func (ts *traefikSource) ingressRouteUDPEndpoints() ([]*endpoint.Endpoint, error) {
return extractEndpoints[IngressRouteUDP](
return extractEndpoints(
ts.ingressRouteUdpInformer.Lister(),
ts.namespace,
func(u *unstructured.Unstructured) (*IngressRouteUDP, error) {
@ -311,7 +312,7 @@ func (ts *traefikSource) ingressRouteUDPEndpoints() ([]*endpoint.Endpoint, error
// oldIngressRouteEndpoints extracts endpoints from all IngressRoute objects
func (ts *traefikSource) oldIngressRouteEndpoints() ([]*endpoint.Endpoint, error) {
return extractEndpoints[IngressRoute](
return extractEndpoints(
ts.oldIngressRouteInformer.Lister(),
ts.namespace,
func(u *unstructured.Unstructured) (*IngressRoute, error) {
@ -327,7 +328,7 @@ func (ts *traefikSource) oldIngressRouteEndpoints() ([]*endpoint.Endpoint, error
// oldIngressRouteTCPEndpoints extracts endpoints from all IngressRouteTCP objects
func (ts *traefikSource) oldIngressRouteTCPEndpoints() ([]*endpoint.Endpoint, error) {
return extractEndpoints[IngressRouteTCP](
return extractEndpoints(
ts.oldIngressRouteTcpInformer.Lister(),
ts.namespace,
func(u *unstructured.Unstructured) (*IngressRouteTCP, error) {
@ -341,7 +342,7 @@ func (ts *traefikSource) oldIngressRouteTCPEndpoints() ([]*endpoint.Endpoint, er
// oldIngressRouteUDPEndpoints extracts endpoints from all IngressRouteUDP objects
func (ts *traefikSource) oldIngressRouteUDPEndpoints() ([]*endpoint.Endpoint, error) {
return extractEndpoints[IngressRouteUDP](
return extractEndpoints(
ts.oldIngressRouteUdpInformer.Lister(),
ts.namespace,
func(u *unstructured.Unstructured) (*IngressRouteUDP, error) {

View File

@ -330,7 +330,6 @@ func TestTraefikProxyIngressRouteEndpoints(t *testing.T) {
expected: nil,
},
} {
t.Run(ti.title, func(t *testing.T) {
t.Parallel()
@ -624,7 +623,6 @@ func TestTraefikProxyIngressRouteTCPEndpoints(t *testing.T) {
expected: nil,
},
} {
t.Run(ti.title, func(t *testing.T) {
t.Parallel()
@ -766,7 +764,6 @@ func TestTraefikProxyIngressRouteUDPEndpoints(t *testing.T) {
expected: nil,
},
} {
t.Run(ti.title, func(t *testing.T) {
t.Parallel()
@ -1096,7 +1093,6 @@ func TestTraefikProxyOldIngressRouteEndpoints(t *testing.T) {
expected: nil,
},
} {
t.Run(ti.title, func(t *testing.T) {
t.Parallel()
@ -1121,7 +1117,7 @@ func TestTraefikProxyOldIngressRouteEndpoints(t *testing.T) {
_, err = fakeDynamicClient.Resource(oldIngressRouteGVR).Namespace(defaultTraefikNamespace).Create(context.Background(), &ir, metav1.CreateOptions{})
assert.NoError(t, err)
source, err := NewTraefikSource(context.TODO(), fakeDynamicClient, fakeKubernetesClient, defaultTraefikNamespace, "kubernetes.io/ingress.class=traefik", ti.ignoreHostnameAnnotation, false, false)
source, err := NewTraefikSource(context.TODO(), fakeDynamicClient, fakeKubernetesClient, defaultTraefikNamespace, "kubernetes.io/ingress.class=traefik", ti.ignoreHostnameAnnotation, true, false)
assert.NoError(t, err)
assert.NotNil(t, source)
@ -1390,7 +1386,6 @@ func TestTraefikProxyOldIngressRouteTCPEndpoints(t *testing.T) {
expected: nil,
},
} {
t.Run(ti.title, func(t *testing.T) {
t.Parallel()
@ -1415,7 +1410,7 @@ func TestTraefikProxyOldIngressRouteTCPEndpoints(t *testing.T) {
_, err = fakeDynamicClient.Resource(oldIngressRouteTCPGVR).Namespace(defaultTraefikNamespace).Create(context.Background(), &ir, metav1.CreateOptions{})
assert.NoError(t, err)
source, err := NewTraefikSource(context.TODO(), fakeDynamicClient, fakeKubernetesClient, defaultTraefikNamespace, "kubernetes.io/ingress.class=traefik", ti.ignoreHostnameAnnotation, false, false)
source, err := NewTraefikSource(context.TODO(), fakeDynamicClient, fakeKubernetesClient, defaultTraefikNamespace, "kubernetes.io/ingress.class=traefik", ti.ignoreHostnameAnnotation, true, false)
assert.NoError(t, err)
assert.NotNil(t, source)
@ -1532,7 +1527,6 @@ func TestTraefikProxyOldIngressRouteUDPEndpoints(t *testing.T) {
expected: nil,
},
} {
t.Run(ti.title, func(t *testing.T) {
t.Parallel()
@ -1557,7 +1551,7 @@ func TestTraefikProxyOldIngressRouteUDPEndpoints(t *testing.T) {
_, err = fakeDynamicClient.Resource(oldIngressRouteUDPGVR).Namespace(defaultTraefikNamespace).Create(context.Background(), &ir, metav1.CreateOptions{})
assert.NoError(t, err)
source, err := NewTraefikSource(context.TODO(), fakeDynamicClient, fakeKubernetesClient, defaultTraefikNamespace, "kubernetes.io/ingress.class=traefik", ti.ignoreHostnameAnnotation, false, false)
source, err := NewTraefikSource(context.TODO(), fakeDynamicClient, fakeKubernetesClient, defaultTraefikNamespace, "kubernetes.io/ingress.class=traefik", ti.ignoreHostnameAnnotation, true, false)
assert.NoError(t, err)
assert.NotNil(t, source)
@ -1574,7 +1568,7 @@ func TestTraefikProxyOldIngressRouteUDPEndpoints(t *testing.T) {
}
}
func TestTraefikAPIGroupDisableFlags(t *testing.T) {
func TestTraefikAPIGroupFlags(t *testing.T) {
t.Parallel()
for _, ti := range []struct {
@ -1582,7 +1576,7 @@ func TestTraefikAPIGroupDisableFlags(t *testing.T) {
ingressRoute IngressRoute
gvr schema.GroupVersionResource
ignoreHostnameAnnotation bool
disableLegacy bool
enableLegacy bool
disableNew bool
expected []*endpoint.Endpoint
}{
@ -1603,9 +1597,9 @@ func TestTraefikAPIGroupDisableFlags(t *testing.T) {
},
},
},
gvr: oldIngressRouteGVR,
disableLegacy: false,
disableNew: false,
gvr: oldIngressRouteGVR,
enableLegacy: true,
disableNew: false,
expected: []*endpoint.Endpoint{
{
DNSName: "a.example.com",
@ -1636,9 +1630,9 @@ func TestTraefikAPIGroupDisableFlags(t *testing.T) {
},
},
},
gvr: oldIngressRouteGVR,
disableLegacy: true,
disableNew: false,
gvr: oldIngressRouteGVR,
enableLegacy: false,
disableNew: false,
},
{
title: "IngressRoute.traefik.io with the new API group enabled",
@ -1657,9 +1651,9 @@ func TestTraefikAPIGroupDisableFlags(t *testing.T) {
},
},
},
gvr: ingressRouteGVR,
disableLegacy: false,
disableNew: false,
gvr: ingressRouteGVR,
enableLegacy: true,
disableNew: false,
expected: []*endpoint.Endpoint{
{
DNSName: "a.example.com",
@ -1690,12 +1684,11 @@ func TestTraefikAPIGroupDisableFlags(t *testing.T) {
},
},
},
gvr: ingressRouteGVR,
disableLegacy: false,
disableNew: true,
gvr: ingressRouteGVR,
enableLegacy: true,
disableNew: true,
},
} {
t.Run(ti.title, func(t *testing.T) {
t.Parallel()
@ -1720,7 +1713,7 @@ func TestTraefikAPIGroupDisableFlags(t *testing.T) {
_, err = fakeDynamicClient.Resource(ti.gvr).Namespace(defaultTraefikNamespace).Create(context.Background(), &ir, metav1.CreateOptions{})
assert.NoError(t, err)
source, err := NewTraefikSource(context.TODO(), fakeDynamicClient, fakeKubernetesClient, defaultTraefikNamespace, "kubernetes.io/ingress.class=traefik", ti.ignoreHostnameAnnotation, ti.disableLegacy, ti.disableNew)
source, err := NewTraefikSource(context.TODO(), fakeDynamicClient, fakeKubernetesClient, defaultTraefikNamespace, "kubernetes.io/ingress.class=traefik", ti.ignoreHostnameAnnotation, ti.enableLegacy, ti.disableNew)
assert.NoError(t, err)
assert.NotNil(t, source)