この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、かたいなかです。
レガシーシステムを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に限らず便利に使えるのではないでしょうか。