こんにちは、(株)日立製作所 研究開発グループ サービスコンピューティング研究部の中村です。
kubernetesでWebサービスを公開する場合、L7 Load Balancerとして動作するIngressを利用している方も多いと思います。そして、Webサービスを外部に公開するためにDNSレコードの自動作成をExternalDNSで管理している方も多いと思います。今回は、IngressコントローラとしてTraefik 2とExternalDNSを連携させて、DNSレコードを自動作成する方法について紹介したいと思います。
そもそも、Ingressコントローラは、kubernetesプロジェクトとして標準サポートしているnginx以外にも、以下のようなものがIngressコントローラがあります。
Traefikは、それ単体でLet's encrypt(ACME)をサポートし証明書更新が自動化される点と、ユーザ認証によるアクセス制限されていないWebアプリをOAuth2.0認証できるようするForward Auth機能を備えている点が他よりも使いやすいと感じており、個人的にはよく利用しています。
また、Traefikは、2019年9月にv2.0が正式にリリースされ、v1系と比較すると、かなり機能が変わりました。
その中でも大きな改善項目は、v1系ではL7 Load Balancerとしてしか動作しなかったのが、v2.0からL4 Load Balancerとして動作するようになった点です。これにより、HTTP(80)/HTTPS(443)のポートだけではなく、それ以外のポートであるSSHやDatabaseをTraefik経由で公開できたり、HTTPS Terminateさせずにbackendにforwardさせるようにできるようになっています。
動作環境
以下の環境を前提に説明を進めます。
種別 | コンポーネント | Version |
---|---|---|
OS | MacOS | Catalina(10.15.1) |
OSS | Kubernetes | 1.16.3 |
OSS | kubectl | 1.16.3 |
OSS | ExternalDNS | 0.8.3 |
OSS | Traefik | 2.1.1 |
KubernetesクラスタとExternalDNSのセットアップ
こちら([Mac] ExternalDNS+ローカルCoreDNS/etcdでkind上のServiceを名前解決してみる - Qiita)を参考にKubernetessクラスタとExternalDNSをセットアップしてください。
Traefikのセットアップ
Namespace "kube-system"にTraefikをIngress Controllerとしてデプロイします。以下のようなmanifestファイルを作成し、kubectlでデプロイします。
---
kind: ServiceAccount
apiVersion: v1
metadata:
name: traefik-ingress-controller
namespace: kube-system
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: traefik
rules:
- apiGroups: [""]
resources: ["pods", "services", "endpoints", "secrets"]
verbs: ["get", "list", "watch"]
- apiGroups: ["extensions"]
resources: ["ingresses"]
verbs: ["get", "list", "watch"]
- apiGroups: ["extensions"]
resources: ["ingresses/status"]
verbs: ["update"]
- apiGroups: ["traefik.containo.us"]
resources:
- ingressroutes
- ingressroutetcps
- middlewares
- tlsoptions
- traefikservices
verbs: ["get", "list", "watch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: traefik
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik
subjects:
- kind: ServiceAccount
name: traefik-ingress-controller
namespace: kube-system
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: traefik-ingress-controller
namespace: kube-system
labels:
app: traefik
spec:
replicas: 1
selector:
matchLabels:
app: traefik
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
metadata:
labels:
app: traefik
spec:
serviceAccountName: traefik-ingress-controller
terminationGracePeriodSeconds: 60
containers:
- image: traefik:2.1.1
name: traefik-ingress-controller
ports:
- name: traefik
containerPort: 8000
protocol: TCP
- name: web
containerPort: 80
protocol: TCP
- name: websecure
containerPort: 443
protocol: TCP
args:
- --entryPoints.traefik.address=:8000
- --entryPoints.web.address=:80
- --entryPoints.websecure.address=:443
- --api.dashboard=true
- --ping=true
- --providers.kubernetescrd
- --providers.kubernetesingress
- --providers.kubernetesingress.ingressendpoint.publishedservice=kube-system/traefik-ingeress-svc
- --log.level=debug
---
apiVersion: v1
kind: Service
metadata:
name: traefik-ingeress-svc
namespace: kube-system
labels:
app: traefik
spec:
type: LoadBalancer
selector:
app: traefik
ports:
- name: traefik
port: 8000
targetPort: traefik
- name: web
port: 80
targetPort: web
- name: websecure
port: 443
targetPort: websecure
TraefikのPodが起動したか確認してみましょう。
$ kubectl -n kube-system get pods -l app=traefik
NAME READY STATUS RESTARTS AGE
traefik-ingress-controller-64cc9449cb-kgwjl 1/1 Running 0 2m23s
もし、STATUSがRunningとなっていなければ、Runningになるまで待ってください。
また、TraefikのServiceがLoadBalancerとしてデプロイされ、External IPが割り当てられているか確認してみましょう。
$ kubectl -n kube-system get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 2d5h
traefik-ingeress-svc LoadBalancer 10.107.102.194 172.17.255.1 8000:30403/TCP,80:32367/TCP,443:30214/TCP 8s
次に、Custom Resource Definition(CRD)を利用するので、下記のようなCRDを定義したmanifestファイルを作成して、こちらも忘れずにデプロイします。
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: ingressroutes.traefik.containo.us
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: IngressRoute
plural: ingressroutes
singular: ingressroute
scope: Namespaced
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: ingressroutetcps.traefik.containo.us
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: IngressRouteTCP
plural: ingressroutetcps
singular: ingressroutetcp
scope: Namespaced
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: middlewares.traefik.containo.us
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: Middleware
plural: middlewares
singular: middleware
scope: Namespaced
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: tlsoptions.traefik.containo.us
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: TLSOption
plural: tlsoptions
singular: tlsoption
scope: Namespaced
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: traefikservices.traefik.containo.us
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: TraefikService
plural: traefikservices
singular: traefikservice
scope: Namespaced
TraefikでのEndpoint公開方法
サービスを外部に公開する際、Traefik 2では以下2通りの方法を提供しています。
- Kubernetes標準のIngressリソースで公開する
- Traefik独自CRD(IngressRoute/IngressTCPRoute)リソースで公開する
以下、具体例を元に詳細について紹介したいと思います。
1. Ingressリソースで公開する
単純なWebサービスをDeploymentとしてデプロイして、Ingressリソースで外部からアクセスできるようにしてみたいと思います。
今回は、Webサービスとして、paulbouwer/hello-kubernetesというDockerイメージを利用しました。
以下のようなmanifestファイルを作成し、kubectlでデプロイします。
apiVersion: apps/v1
kind: Deployment
metadata:
name: helloworld-ingress
spec:
selector:
matchLabels:
app: helloworld-ingress
template:
metadata:
labels:
app: helloworld-ingress
spec:
containers:
- name: helloworld-ingress
image: paulbouwer/hello-kubernetes:1.5
ports:
- name: http
containerPort: 8080
env:
- name: MESSAGE
value: This is defined by an Ingress resource!
---
apiVersion: v1
kind: Service
metadata:
name: helloworld-ingress-svc
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: http
selector:
app: helloworld-ingress
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: helloworld-ingress
annotations:
kubernetes.io/ingress.class: "traefik"
spec:
rules:
- host: helloworld-ingress.example.com
http:
paths:
- path: /
backend:
serviceName: helloworld-ingress-svc
servicePort: 80
TraefikをIngress Controllerとして、Kubernetes標準のIngressリソースを定義するには、annotationにkubernetes.io/ingress.class: "traefik"
を忘れずに追加してください。
動作確認
Ingressリソースが作成で来ているか確認してみます。
$ kubectl get ingress helloworld-ingress
NAME HOSTS ADDRESS PORTS AGE
helloworld-ingress helloworld-ingress.example.com 172.17.255.1 80 28s
Ingressリソースが作成され、TraefikのServiceにアサインされたExternal IPと同じアドレスがADDRESSに割り当てられています。
次に、ExternalDNSのログを確認してみます。
$ kubectl -n kube-system logs external-dns-56c79c6b69-ptzsr
〜〜〜
time="2019-12-20T00:17:20Z" level=debug msg="No endpoints could be generated from service default/kubernetes"
time="2019-12-20T00:17:20Z" level=debug msg="No endpoints could be generated from service kube-system/kube-dns"
time="2019-12-20T00:17:20Z" level=debug msg="No endpoints could be generated from service kube-system/traefik-ingeress-svc"
time="2019-12-20T00:17:20Z" level=debug msg="No endpoints could be generated from service default/helloworld-ingress-svc"
time="2019-12-20T00:17:20Z" level=debug msg="Endpoints generated from ingress: default/helloworld-ingress: [helloworld-ingress.example.com 0 IN A 172.17.255.1 []]"
time="2019-12-20T00:17:20Z" level=info msg="Add/set key /skydns/com/example/helloworld-ingress/30e3a08a to Host=172.17.255.1, Text=\"heritage=external-dns,external-dns/owner=default,external-dns/resource=ingress/default/helloworld-ingress\", TTL=0"
〜〜〜
Ingressリソースを検出し、DNSレコードが登録されたログが確認できました。
それでは、実際にアクセスしてみます。ブラウザを開き、アドレスバーに"http://helloworld-ingress.example.com"と入力してみます。
無事にアクセスできました。
2. IngressRouteで公開する
次に、Traefik 2.0より追加されたCustom Resource Definition(CRD)であるIngressRouteを使って公開してみたいと思います。
先程のIngressで公開した時と同じWebサービスをDeploymentでデプロイし、TraefikのCRDであるIngressRouteを使って定義してみます。
具体的には、以下のようなmanifestファイルを作成し、デプロイします。
apiVersion: apps/v1
kind: Deployment
metadata:
name: helloworld-ingressroute-crd
spec:
selector:
matchLabels:
app: helloworld-ingressroute-crd
template:
metadata:
labels:
app: helloworld-ingressroute-crd
spec:
containers:
- name: helloworld-ingressroute-crd
image: paulbouwer/hello-kubernetes:1.5
ports:
- name: http
containerPort: 8080
env:
- name: MESSAGE
value: This is defined by an IngressRoute resource!
---
apiVersion: v1
kind: Service
metadata:
name: helloworld-ingressroute-crd-svc
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: http
selector:
app: helloworld-ingressroute-crd
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: helloworld-ingressroute-crd
spec:
entryPoints:
- web
routes:
- match: Host(`helloworld-ingressroute.example.com`)
kind: Rule
services:
- name: helloworld-ingressroute-crd-svc
port: 80
実際にIngressRouteリソースが作成されたか確認してみます。
$ kubectl describe ingressroute helloworld-ingressroute-crd
Name: helloworld-ingressroute-crd
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"traefik.containo.us/v1alpha1","kind":"IngressRoute","metadata":{"annotations":{},"name":"helloworld-ingressroute-crd","name...
API Version: traefik.containo.us/v1alpha1
Kind: IngressRoute
Metadata:
Creation Timestamp: 2019-12-20T00:43:22Z
Generation: 1
Resource Version: 108873
Self Link: /apis/traefik.containo.us/v1alpha1/namespaces/default/ingressroutes/helloworld-ingressroute-crd
UID: ad90f795-0dc5-453d-af6c-27340737cbb1
Spec:
Entry Points:
web
Routes:
Kind: Rule
Match: Host(`helloworld-ingressroute.example.com`)
Services:
Name: helloworld-ingressroute-crd-svc
Port: 80
Events: <none>
正常に作成できているようです。
それでは、ExternalDNSのログをみてみましょう。
$ kubectl -n kube-system logs external-dns-56c79c6b69-ptzsr
〜〜〜
time="2019-12-20T00:39:19Z" level=debug msg="No endpoints could be generated from service default/kubernetes"
time="2019-12-20T00:39:19Z" level=debug msg="No endpoints could be generated from service kube-system/kube-dns"
time="2019-12-20T00:39:19Z" level=debug msg="No endpoints could be generated from service kube-system/traefik-ingeress-svc"
time="2019-12-20T00:39:19Z" level=debug msg="No endpoints could be generated from service default/helloworld-ingress-svc"
time="2019-12-20T00:39:19Z" level=debug msg="Endpoints generated from ingress: default/helloworld-ingress: [helloworld-ingress.example.com 0 IN A 172.17.255.1 []]"
time="2019-12-20T00:39:32Z" level=debug msg="pod added"
time="2019-12-20T00:39:32Z" level=debug msg="service added"
time="2019-12-20T00:40:19Z" level=debug msg="No endpoints could be generated from service default/kubernetes"
time="2019-12-20T00:40:19Z" level=debug msg="No endpoints could be generated from service kube-system/kube-dns"
time="2019-12-20T00:40:19Z" level=debug msg="No endpoints could be generated from service kube-system/traefik-ingeress-svc"
time="2019-12-20T00:40:19Z" level=debug msg="No endpoints could be generated from service default/helloworld-ingress-svc"
time="2019-12-20T00:40:19Z" level=debug msg="No endpoints could be generated from service default/helloworld-ingressroute-crd-svc"
time="2019-12-20T00:40:19Z" level=debug msg="Endpoints generated from ingress: default/helloworld-ingress: [helloworld-ingress.example.com 0 IN A 172.17.255.1 []]"
〜〜〜
Serviceリソースが追加されていることは検知できているようですが、IngressRouteリソースの追加が検知できていないので、DNSレコードの作成がされていないようです。
実際に、curlでアクセスして確認してみましょう。
$ curl http://helloworld-ingressroute.example.com
curl: (6) Could not resolve host: helloworld-ingressroute.example.com
DNSで名前解決できていないようですね。
ExternalDNSがサポートしているリソース
なぜExternalDNSで自動でDNSレコードができなかったのか考えてみたいと思います。
ExternalDNSのSourceに関するドキュメントを確認してみましょう。ExternalDNSでサポートしているのは、以下の通りです。
- ServiceSource
- IngressSource
- IstioGatewaySource
- ContourIngressRouteSource
- FakeSource
- ConnectorSource
- CRDSource
- EmptySource
これを見ると、CRDもサポートしているように見えます。どのようなものか詳細をこちらで確認してみましょう。
どうも、CRDとしてサポートしているデータ構造は、特定のもののようです。また、ExternalDNSのIssueで調べてみても、こちらのように、TraefikのIngressRouteはサポートされていないようです。これはTraefikに限らず、その他のCRDを使ってサービス公開を行うIngress Controller(例えば、AmbassadorやVoyager)も同様の問題にぶつかってしまうと思われます。
解決策
現状、どのような解決策があるか整理してみたいと思います。
- ExternalDNSのCRDSourceを使ってDNSを定義する
- Serviceリソース(ExternalName)を使ってDNSを定義する
1つ目は、ExternalDNSのIssueでも推奨されていましたが、ExternalDNSのDNS定義専用のCRD("DNSEndpoint")を用いる方法です。
2つ目は、ExternalDNSがサポートしているServiceリソースのtypeをExternalNameを用いて、DNSを定義する方法です。
以下、実際に、その手順を紹介したいと思います。
(解決策1) ExternalDNSのCRDSourceを使ってDNSを定義する
ExternalDNSのドキュメントを参考に、進めていきたいと思います。
まずは、CRDを定義した以下の様なmanifestファイルを作成します。
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
creationTimestamp: null
labels:
api: externaldns
kubebuilder.k8s.io: 1.0.0
name: dnsendpoints.externaldns.k8s.io
spec:
group: externaldns.k8s.io
names:
kind: DNSEndpoint
plural: dnsendpoints
scope: Namespaced
subresources:
status: {}
validation:
openAPIV3Schema:
properties:
apiVersion:
type: string
kind:
type: string
metadata:
type: object
spec:
properties:
endpoints:
items:
properties:
dnsName:
type: string
labels:
type: object
providerSpecific:
items:
properties:
name:
type: string
value:
type: string
type: object
type: array
recordTTL:
format: int64
type: integer
recordType:
type: string
targets:
items:
type: string
type: array
type: object
type: array
type: object
status:
properties:
observedGeneration:
format: int64
type: integer
type: object
version: v1alpha1
status:
acceptedNames:
kind: ""
plural: ""
conditions: null
これをkubectlでデプロイします。デプロイする際には、validateが無効になるオプションをつけて実行します。
$ kubectl apply --validate=false -f dnsendpoint-crd.yaml
customresourcedefinition.apiextensions.k8s.io/dnsendpoints.externaldns.k8s.io created
次に、ExternalDNSにRBACを設定している場合は、先程追加したCRDに対するアクセス権を付与する以下のmanifestファイルを作成し、適用します。
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: external-dns-crd
rules:
- apiGroups: ["externaldns.k8s.io"]
resources: ["dnsendpoints"]
verbs: ["get","watch","list","update"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: external-dns-crd-manager
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: external-dns-crd
subjects:
- kind: ServiceAccount
name: external-dns
namespace: kube-system
そして、追加したCRDをExternalDNSが検出できるように、ExternalDNSの起動時のオプションを追加します。以下のようなmanifestファイルを作成し、ExternalDNSのDeploymentをUpdateします。
apiVersion: apps/v1
kind: Deployment
metadata:
name: external-dns
namespace: kube-system
spec:
strategy:
type: Recreate
selector:
matchLabels:
app: external-dns
template:
metadata:
labels:
app: external-dns
spec:
serviceAccountName: external-dns
containers:
- name: external-dns
image: registry.opensource.zalan.do/teapot/external-dns:latest
args:
- --source=service
- --source=ingress
- --provider=coredns
- --log-level=debug
- --policy=sync
- --domain-filter=example.com
- --source=crd # <--- 追加
- --crd-source-apiversion=externaldns.k8s.io/v1alpha1 # <--- 追加
- --crd-source-kind=DNSEndpoint # <--- 追加
env:
- name: ETCD_URLS
value: http://host.docker.internal:2379
最後に、追加したCRD"DNSEndpoint"を使って、DNSを以下のように定義して、kubectlでデプロイします。なお、最後のtargetsには、Ingress ControllerであるTraefikのServiceに割り当てられたExternal IPを指定します。
apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
name: helloworld-ingressroute-dnsrecord
spec:
endpoints:
- dnsName: helloworld-ingressroute.example.com
recordTTL: 180
recordType: A
targets:
- 172.17.255.1
それでは、確認してみましょう。まずは、DNSEndpointリソースが作成されているか確認します。
$ kubectl get dnsendpoint
NAME AGE
helloworld-ingressroute-dnsrecord 21s
次に、ExternalDNSのログを確認してみます。
$ kubectl -n kube-system logs external-dns-6f59d484c-nh6zv
〜〜〜
time="2019-12-20T01:54:14Z" level=debug msg="No endpoints could be generated from service default/kubernetes"
time="2019-12-20T01:54:14Z" level=debug msg="No endpoints could be generated from service kube-system/kube-dns"
time="2019-12-20T01:54:14Z" level=debug msg="No endpoints could be generated from service kube-system/traefik-ingeress-svc"
time="2019-12-20T01:54:14Z" level=debug msg="No endpoints could be generated from service default/helloworld-ingress-svc"
time="2019-12-20T01:54:14Z" level=debug msg="No endpoints could be generated from service default/helloworld-ingressroute-crd-svc"
time="2019-12-20T01:54:14Z" level=debug msg="Endpoints generated from ingress: default/helloworld-ingress: [helloworld-ingress.example.com 0 IN A 172.17.255.1 []]"
time="2019-12-20T01:54:14Z" level=warning msg="Could not update ObservedGeneration of the CRD: dnsendpoints.externaldns.k8s.io \"helloworld-ingressroute-dnsrecord\" is forbidden: User \"system:serviceaccount:kube-system:external-dns\" cannot update resource \"dnsendpoints/status\" in API group \"externaldns.k8s.io\" in the namespace \"default\""
time="2019-12-20T01:54:14Z" level=info msg="Add/set key /skydns/com/example/helloworld-ingressroute/089779ea to Host=172.17.255.1, Text=\"heritage=external-dns,external-dns/owner=default,external-dns/resource=crd/default/helloworld-ingressroute-dnsrecord\", TTL=180"
〜〜〜
CRDの情報を元に、DNSレコードが追加されたようです。
早速、ブラウザからアクセスできるか確認してみましょう。
無事にアクセスできました。
別の解決策を試すために、一旦、追加したDNSEndpointリソースを削除します。
$ kubectl delete dnsendpoint helloworld-ingressroute-dnsrecord
dnsendpoint.externaldns.k8s.io "helloworld-ingressroute-dnsrecord" deleted
1分程度待ってからcurlでアクセスすると、以下のようにDNSの名前解決に失敗すると思います。
$ curl http://helloworld-ingressroute.example.com
curl: (6) Could not resolve host: helloworld-ingressroute.example.com
(解決策2) Serviceリソース(ExternalName)を使ってDNSを定義する
今度は、Kubernetes標準のServiceリソースだけでDNSを定義したいと思います。
まずは、以下のようなServiceリソースを定義します。これは、サービスを公開するときに作成しているServiceとは別に、DNSレコード登録用のServiceリソースになるので、名前が重複しないように気をつけて作成してください。
apiVersion: v1
kind: Service
metadata:
name: hellowrold-ingressroute-svc-external
annotations:
external-dns.alpha.kubernetes.io/hostname: helloworld-ingressroute.example.com <-- 3
spec:
type: ExternalName <-- 1
externalName: 172.17.255.1 <-- 2
ポイントは以下の3点です。
- typeをExternalNameと指定
- externalNameに、Ingress ControllerであるTraefikのServiceに割り当てられたExternal IPを指定
- annotationにDNSとして登録したいhostnameを記載
この作成したmanifestファイルをデプロイすればOKです。
早速、確認してみましょう。
まずは、Serviceリソースが作成されているかを確認します。
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
helloworld-ingress-svc ClusterIP 10.98.240.223 <none> 80/TCP 124m
helloworld-ingressroute-crd-svc ClusterIP 10.103.54.127 <none> 80/TCP 101m
hellowrold-ingressroute-svc-external ExternalName <none> 172.17.255.1 <none> 7s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d7h
typeがExternalNameのServiceリソースが作成されているようです。
次に、ExternalDNSのログを確認します。
$ kubectl -n kube-system logs external-dns-6f59d484c-nh6zv
〜〜〜
time="2019-12-20T02:20:13Z" level=debug msg="No endpoints could be generated from service default/kubernetes"
time="2019-12-20T02:20:13Z" level=debug msg="No endpoints could be generated from service kube-system/kube-dns"
time="2019-12-20T02:20:13Z" level=debug msg="No endpoints could be generated from service kube-system/traefik-ingeress-svc"
time="2019-12-20T02:20:13Z" level=debug msg="No endpoints could be generated from service default/helloworld-ingress-svc"
time="2019-12-20T02:20:13Z" level=debug msg="No endpoints could be generated from service default/helloworld-ingressroute-crd-svc"
time="2019-12-20T02:20:13Z" level=debug msg="Endpoints generated from ingress: default/helloworld-ingress: [helloworld-ingress.example.com 0 IN A 172.17.255.1 []]"
time="2019-12-20T02:20:41Z" level=debug msg="service added"
time="2019-12-20T02:21:12Z" level=debug msg="No endpoints could be generated from service default/helloworld-ingressroute-crd-svc"
time="2019-12-20T02:21:12Z" level=debug msg="Endpoints generated from service: default/hellowrold-ingressroute-svc-external: [helloworld-ingressroute.example.com 0 IN A 172.17.255.1 []]"
time="2019-12-20T02:21:12Z" level=debug msg="No endpoints could be generated from service default/kubernetes"
time="2019-12-20T02:21:12Z" level=debug msg="No endpoints could be generated from service kube-system/kube-dns"
time="2019-12-20T02:21:12Z" level=debug msg="No endpoints could be generated from service kube-system/traefik-ingeress-svc"
time="2019-12-20T02:21:12Z" level=debug msg="No endpoints could be generated from service default/helloworld-ingress-svc"
time="2019-12-20T02:21:12Z" level=debug msg="Endpoints generated from ingress: default/helloworld-ingress: [helloworld-ingress.example.com 0 IN A 172.17.255.1 []]"
time="2019-12-20T02:21:12Z" level=info msg="Add/set key /skydns/com/example/helloworld-ingressroute/671dbad1 to Host=172.17.255.1, Text=\"heritage=external-dns,external-dns/owner=default,external-dns/resource=service/default/hellowrold-ingressroute-svc-external\", TTL=0"
〜〜〜
Serviceの追加が検出され、DNSレコードが登録されたようです。
最後に、ブラウザからアクセスできるか確認してみます。
先程と全く同じ画面が表示されることが確認できました。
まとめ
IngressコントローラとしてTraefik 2とExternalDNSを連携させて、DNSレコードを自動作成する方法について紹介しました。Kubernetes標準のIngressリソースの場合は特に問題はなかったのですが、Traefik独自のCRDを用いた場合は、そのままではExternalDNSが追加されたCRDを検出できずDNSレコードの作成がされないという問題があり、その解決方法を2つ紹介しました。
ご紹介した2つの解決方法はどちらも、Ingress ControllerのServiceにアサインされているExternal IPを手作業で埋める必要があるので、運用は煩雑になってしまいます。
この問題は、Traefikのコミュニティでも認識されており、これに関するIssueが登録されています。早く改善されることを望みながら、この動向をWatchしていきたいと思います。