External-dns: Is it possible to use external-dns with a Traefik 2.0 IngressRoute resource?

Created on 4 Nov 2019  Â·  18Comments  Â·  Source: kubernetes-sigs/external-dns

I was able to use external-dns with AWS Route53 and EKS cluster with a Traefik 1.7 Ingress resource, but have been unable to achieve the same with the Traefik 2.0 IngressRoute resource. I have annotated my service to provide the hostname information.

  annotations:
    external-dns.alpha.kubernetes.io/hostname: my.awesome.domain.com

Of course, my.awesome.domain.com is not my real domain, but is unimportant.

Does external-dns require a Kubernetes Ingress? If not how might I get it to work with a new CRD type, such as the Traefik 2.0 IngressRoute?

Many thanks in advance!

Most helpful comment

Actually, I don't think this topic should be closed. According to the externalDNS documentation the following is stated on Service:

ServiceSource: collects all Services that have an external IP and returns them as Endpoint objects. The desired DNS name corresponds to an annotation set on the Service or is compiled from the Service attributes via the FQDN Go template string.

Which means that all the services that do not have an external-ip (when inspecting w/ kubectl get svc) will not be processed - whether or not they have a external-dns annotation.

The other option that we have is to use external dns custom resource. An example definition of that custom resource looks like this:

apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
  name: examplednsrecord
spec:
  endpoints:
  - dnsName: foo.bar.com
    recordTTL: 180
    recordType: A
    targets:
    - 192.168.99.216

Here the problem would be to dynamically update the target. How can I point als these custom DNSEndpoint resources to the LoadBalancer type service that is placed in front of traefik? I am concluding for the moment that Traefik2 is incompatible with ExternalDNS. Is that a correct assumption? How could we approach this?

All 18 comments

Here are the sources which are currently supported:

service, ingress, node, fake, connector, istio-gateway, cloudfoundry, contour-ingressroute, crd, empty

You can enable multiple sources.

So it does not require Kubernetes Ingress, e.g. Service is also fine.

Actually, I don't think this topic should be closed. According to the externalDNS documentation the following is stated on Service:

ServiceSource: collects all Services that have an external IP and returns them as Endpoint objects. The desired DNS name corresponds to an annotation set on the Service or is compiled from the Service attributes via the FQDN Go template string.

Which means that all the services that do not have an external-ip (when inspecting w/ kubectl get svc) will not be processed - whether or not they have a external-dns annotation.

The other option that we have is to use external dns custom resource. An example definition of that custom resource looks like this:

apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
  name: examplednsrecord
spec:
  endpoints:
  - dnsName: foo.bar.com
    recordTTL: 180
    recordType: A
    targets:
    - 192.168.99.216

Here the problem would be to dynamically update the target. How can I point als these custom DNSEndpoint resources to the LoadBalancer type service that is placed in front of traefik? I am concluding for the moment that Traefik2 is incompatible with ExternalDNS. Is that a correct assumption? How could we approach this?

Any updates on how the two could work together ?

@brondum I have had success with the Traefik 2.1 and external-dns 1.16.0 just now, like so:

external-dns config (not sure if all these are necessary, included what I thought is relevant or helpful):

fqdnTemplates: ["{{.Name}}.mydomain.com"]
aws:
  preferCNAME: true
combineFQDNAnnotation: true
publishInternalServices: false
registry: txt
txtPrefix: "_."
logLevel: debug

My traefik service is named traefik, so the above results in an ALIAS record traefik.mydomain.com to the ELB in Route53.

Now an ExternalName service:

kind: Service
apiVersion: v1
metadata:
  name: mysite-external-name
  annotations:
    external-dns.alpha.kubernetes.io/hostname: www.mydomain.com
spec:
  type: ExternalName
  externalName: traefik.mydomain.com

This should result in a CNAME www.mydomain.com -> traefik.mydomain.com.

Of course you have to do the requisite IAM setup and other stuff mentioned in the docs, first. But I can confirm this is all working as expected. This is a bit of a workaround, but notice that no intelligence about IngressRoute is necessary for external-dns to cope with this need.

Hope that helps you and/or googlers, even if not directly answering your question.

@jimbocoder Nice workaround, had not thought about using the ExternalName.
I will definitely try that one out :)

Our workaround was to create an empty Ingress

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: mysite-external-name-dns
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  rules:
    - host: www.mydomain.com

Related: containous/traefik#4655.

the workaround from @wizbit is not working and the one from @jimbocoder neither (Azure DNS) i think that Traefik is not suitable for external dns atm

In Traefik 2.2, the following works,
providers.kubernetesIngress.ingressEndpoint.publishedService=/
When this option is added to traefik ingress controller, the field "status.loadBalancer.ingress" is populated correctly, making external-dns to use the appropriate EXTERNAL-IP in the DNS.

@sbellan : Cool, i have to test this..

Btw, I'm using the Kubernetes ingress provider and not the K8s CRD provider
with Traefik version 2.2.

On Mon, Sep 21, 2020, 3:17 AM dirien notifications@github.com wrote:

@sbellan https://github.com/sbellan : Cool, i have to test this..

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/kubernetes-sigs/external-dns/issues/1257#issuecomment-696025608,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AADIWURXPQWNJQTRAHEIBWDSG4R5FANCNFSM4JI25S5Q
.

@sbellan do you have a gist or yaml you could share for both the external-dns config/helm values and the same for traefik?

External DNS

apiVersion: v1
kind: ServiceAccount
metadata:
  name: external-dns
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: external-dns
rules:
  - apiGroups: ['']
    resources: ['endpoints', 'pods', 'services']
    verbs: ['get', 'watch', 'list']
  - apiGroups: ['extensions']
    resources: ['ingresses']
    verbs: ['get', 'watch', 'list']
  - apiGroups: ['']
    resources: ['nodes']
    verbs: ['list']
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: external-dns-viewer
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: external-dns
subjects:
  - kind: ServiceAccount
    name: external-dns
    namespace: default
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: external-dns
spec:
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: external-dns
  template:
    metadata:
      labels:
        app: external-dns
    spec:
      serviceAccountName: external-dns
      containers:
        - name: external-dns
          image: k8s.gcr.io/external-dns/external-dns:v0.7.3
          args:
            - --source=service
            - --source=ingress
            - --registry=txt
            - --domain-filter=somedomain.com
            - --provider=aws
            - --aws-zone-type=public
            - --txt-owner-id=eks-dev

Deploy Traefik RBAC and Core in traefik namespace..

Traefik RBAC

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: traefik-ingress-controller
rules:
  - apiGroups:
      - ""
    resources:
      - services
      - endpoints
      - secrets
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - extensions
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - extensions
    resources:
      - ingresses/status
    verbs:
      - update

---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: traefik-ingress-controller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: traefik-ingress-controller
subjects:
  - kind: ServiceAccount
    name: traefik-ingress-controller
    namespace: traefik

Traefik core

apiVersion: v1
kind: ServiceAccount
metadata:
  name: traefik-ingress-controller

---

kind: Deployment
apiVersion: apps/v1
metadata:
  name: traefik
  labels:
    app: traefik

spec:
  replicas: 1
  selector:
    matchLabels:
      app: traefik
  template:
    metadata:
      labels:
        app: traefik
    spec:
      serviceAccountName: traefik-ingress-controller
      containers:
        - name: traefik
          image: traefik:v2.2
          args:
            - --log.level=DEBUG
            - --api
            - --api.insecure
            - --entrypoints.web.address=:80
            - --entrypoints.websecure.address=:443
            - --providers.kubernetesingress
            - --providers.kubernetesIngress.ingressEndpoint.publishedService=traefik/traefik
          ports:
            - name: web
              containerPort: 80
            - name: websecure
              containerPort: 443
            - name: admin
              containerPort: 8080

---
apiVersion: v1
kind: Service
metadata:
  name: traefik
spec:
  type: LoadBalancer
  selector:
    app: traefik
  ports:
    - protocol: TCP
      port: 80
      name: web
      targetPort: 80
    - protocol: TCP
      port: 443
      name: websecure
      targetPort: 443
    - protocol: TCP
      port: 8080
      name: admin
      targetPort: 8080

Sample Ingress

kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
  name: myingress
  annotations:
    traefik.ingress.kubernetes.io/router.entrypoints: websecure
    traefik.ingress.kubernetes.io/router.tls: "true"

spec:
  rules:
    - host: example.eks4.somedomain.com
      http:
        paths:
          - path: /bar
            backend:
              serviceName: whoami
              servicePort: 80
          - path: /foo
            backend:
              serviceName: whoami
              servicePort: 80
  tls:
  - secretName: example.eks4.somedomain.com-cert

Certificate

apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
  name: example.eks4.somedomain.com-cert
spec:
  commonName: example.eks4.somedomain.com
  dnsNames:
  - example.eks4.somedomain.com
  secretName: example.eks4.somedomain.com-cert
  issuerRef:
    name: cert-manager
    kind: ClusterIssuer
    group: cert-manager.io

@sbellan Your solution is about Kubernetes ingress, not about Traefik IngressRoute (as stated in the title).

I've noticed using a NodePort service makes external-dns populate the DNS records with the external IPs of Traefik which we expose directly via HostPort. This wastes a random port but at least the setup works. It would be great if external-dns was able to expose the external IPs of nodes where pods are using HostPort. The solution in the tutorials with a headless service resulted in internal IPs being used which for external dns seems wrong.

I've noticed using a NodePort service makes external-dns populate the DNS records with the external IPs of Traefik which we expose directly via HostPort. This wastes a random port but at least the setup works. It would be great if external-dns was able to expose the external IPs of nodes where pods are using HostPort. The solution in the tutorials with a headless service resulted in internal IPs being used which for _external_ dns seems wrong.

@arctica can you help to show us what you've done with nodeport? Thanks

Has there been any updates to support IngressRoute CRD?

@arctica can you help to show us what you've done with nodeport? Thanks

Nothing fancy, In my traefik-values.yml (using the traefik helm chart) I have the following:

service:
  enabled: true
  type: NodePort
  annotations:
    external-dns.alpha.kubernetes.io/hostname: traefik.example.com
    external-dns.alpha.kubernetes.io/ttl: "120"
  spec:
    externalTrafficPolicy: Local
Was this page helpful?
0 / 5 - 0 ratings

Related issues

neilhwatson picture neilhwatson  Â·  3Comments

Gnnng picture Gnnng  Â·  3Comments

nyetwurk picture nyetwurk  Â·  4Comments

naveeng68 picture naveeng68  Â·  4Comments

deimosfr picture deimosfr  Â·  3Comments