ExternalDNS + Route 53 Auto Naming(Service Discovery)でEKSのServiceをRoute53で名前解決してみる
こんにちは、かたいなかです。
レガシーシステムをEKSに段階を踏んで移行していく際、途中の段階でレガシーシステム側からEKSのサービスにアクセスさせたいことがあります。そんなとき、名前解決をしたいが手動で管理するのも面倒だ、と悩んでいる方も多いのではないでしょうか。
そこで今回はExternalDNSというツールを用いてサービスに対して特定のFQDNを紐付けて名前解決を行えるようにする方法をご紹介します。
ExternalDNSとは
ExternalDNSはKubernetesのServiceやIngressをDNSプロバイダに対して同期してくれるツールです。これを用いることで、Kubernetesのリソースを用いてDNSのレコードをDNSプロバイダに依存しない形で動的に管理できます。
今回はExternalDNSをRoute53のAuto Namingと合わせて用いることで、ServiceをFQDNと結びつけ、VPC内でPrivate DNSによる名前解決ができるようにしていきます。
ServiceDiscoveryの準備をする
まず、Route53の設定を行っていきます。Auto Namingがマネジメントコンソールに対応していないため、AWS CLIから作業を行っていきます。
今回はオレゴンリージョンにEKSクラスタが存在することを前提に、オレゴンリージョンで作業を行っていきます。
$ export AWS_DEFAULT_REGION=us-west-2
今回は、VPC内でのPrivateなDNSとして使用するため、EKSのワーカーノードがデプロイされているVPCと結びつけたprivate-dns-namespaceを作成します。
$ aws servicediscovery create-private-dns-namespace --name eks-services.katainaka.org --vpc vpc-XXXXXX
$ aws servicediscovery list-namespaces { "Namespaces": [ { "Type": "DNS_PRIVATE", "Id": "ns-XXXXXXXXXXXXXXXX", "Arn": "arn:aws:servicediscovery:us-west-2:XXXXXXXXXXXX:namespace/ns-XXXXXXXXXXXXXXXX", "Name": "eks-services.katainaka.org" } ] }
さらに、ExternalDNSからAレコードを登録させるサービスを作成します。
今回はnginx.eks-services.katainaka.org
という名前でIPアドレスを解決できるようにしたいので、nginx
という名前を指定して以下のように作成します。
$ aws servicediscovery create-service --name nginx --dns-config 'NamespaceId=ns-XXXXXXXXXXXXXX,DnsRecords=[{Type=A,TTL=60}]'
$ aws servicediscovery list-services { "Services": [ { "Description": "heritage=external-dns,external-dns/owner=default,external-dns/resource=service/default/nginx", "Id": "srv-XXXXXXXXXXXXX", "Arn": "arn:aws:servicediscovery:us-west-2:XXXXXXXXXXXX:service/srv-XXXXXXXXXXXXX", "Name": "nginx" } ] }
ここまでで、Route53の設定は終わりです。
EKSのワーカーノードにRoute53に対しての権限を与える
ExternalDNSがRoute53のレコードを修正できるようにするため、EKSのワーカーノードに対してRoute53のレコードを操作する権限を与える必要があります。
今回はAmazonRoute53AutoNamingFullAccess
というAWS管理ポリシーをEKSのワーカーノードのIAMロールにアタッチしておきます。
ExternalDNSをデプロイする
ServiceAccount,ClusterRole,ClusterRoleBindingを準備
登録されたServiceやIngressの情報を元にRoute53にレコードを登録できるようにするため、ExternalDNSのPodにKubernetesのServiceの一覧を取得したりする権限を与える必要があります。 そのため必要になる、ServiceAccountとClusterRole、さらにそれらを組み合わせるClusterRoleBindingを先にデプロイします。
apiVersion: v1 kind: ServiceAccount metadata: name: external-dns --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRole metadata: name: external-dns rules: - apiGroups: [""] resources: ["services"] verbs: ["get","watch","list"] - apiGroups: [""] resources: ["pods"] 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
ExternalDNSをデプロイ
先に作成したServiceAccountを指定してExternalDNSをDeploymentとしてデプロイします。
apiVersion: extensions/v1beta1 kind: Deployment metadata: labels: app: external-dns name: external-dns spec: strategy: type: Recreate template: metadata: labels: app: external-dns spec: serviceAccountName: external-dns # 作成したServiceAccountを指定 containers: - name: external-dns image: registry.opensource.zalan.do/teapot/external-dns:latest args: - --source=service # serviceとingressを対象にする - --source=ingress - --domain-filter=eks-services.katainaka.org #namespaceと同じ値を持つドメインの場合は登録する - --provider=aws-sd #Route53のServiceDiscoveryに登録 - --aws-zone-type=private #privateのdns-namespaceを使用するため。publicのものを使用する場合はpublic - --txt-owner-id=my-cluster-id env: - name: AWS_REGION value: us-west-2
動作を確認してみる
ExternalDNSがデプロイされたところで、以下のようなServiceを作成します。
Serviceのexternal-dns.alpha.kubernetes.io/hostname
というannotationでRoute53に登録するFQDNを指定しています。
apiVersion: v1 kind: Service metadata: name: nginx annotations: external-dns.alpha.kubernetes.io/hostname: nginx.eks-services.katainaka.org #service名.namespace名 spec: type: NodePort #LoadBalancerも可能 ports: - port: 80 name: http targetPort: 80 selector: app: nginx --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx spec: template: metadata: labels: app: nginx spec: containers: - image: nginx name: nginx ports: - containerPort: 80 name: http
EKSが作成されたVPCにEC2インスタンスを作成、SSHでログインして名前解決できていることを実際に確認してみます。
[ec2-user@ip-192-168-69-50 ~]$ dig nginx.eks-services.katainaka.org ; <<>> DiG 9.9.4-RedHat-9.9.4-61.amzn2.1.1 <<>> nginx.eks-services.katainaka.org ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 36647 ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;nginx.eks-services.katainaka.org. IN A ;; ANSWER SECTION: nginx.eks-services.katainaka.org. 60 IN A 192.168.149.170 nginx.eks-services.katainaka.org. 60 IN A 192.168.86.1 ;; Query time: 2 msec ;; SERVER: 192.168.0.2#53(192.168.0.2) ;; WHEN: 月 10月 01 06:55:03 UTC 2018 ;; MSG SIZE rcvd: 93
nginx.eks-services.katainaka.org
というFQDNからプライベートIPアドレスに解決できています。
また、external-dns.alpha.kubernetes.io/hostname
をアノテーションで指定したServiceを削除してみます。
$ kubectl delete service nginx
この状態で名前解決を試みると
[ec2-user@ip-192-168-69-50 ~]$ dig nginx.eks-services.katainaka.org ; <<>> DiG 9.9.4-RedHat-9.9.4-61.amzn2.1.1 <<>> nginx.eks-services.katainaka.org ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 63690 ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;nginx.eks-services.katainaka.org. IN A ;; AUTHORITY SECTION: eks-services.katainaka.org. 57 IN SOA ns-1536.awsdns-00.co.uk. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400 ;; Query time: 0 msec ;; SERVER: 192.168.0.2#53(192.168.0.2) ;; WHEN: 月 10月 01 07:37:20 UTC 2018 ;; MSG SIZE rcvd: 148
プライベートアドレスが解決されなりました。Aレコードが削除されています。
まとめ
Route53のAuto NamingとExternalDNSを用いてVPCの中からEKSのサービスに対して特定のFQDNで名前解決できるようにできました。
今回はプライベートなnamespaceによるVPC内での名前解決のためのものでしたがパブリックなnamespaceを用いればPublicなHostedZoneに登録できますし、Auto Namingを使用せずRoute53のPublic/Private Hosted Zoneを使用することももちろん可能です。
また、Route53に限らず、Google CloudDNSやAzureDNS、CloudFlare、DigitalOcean等にも対応できるようなのでEKSに限らず便利に使えるのではないでしょうか。