この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、かたいなかです。
ExternalDNSを使用するとKubernetesのYAML内でドメイン名を指定するだけで、Route53のHosted Zoneにレコードが登録でき便利です。
実際にExternalDNSを使用していたのですが、外部向けELBのエンドポイントはPublic Hosted Zoneに、内部向けELBのエンドポイントはPriate Hosted Zoneにレコードを登録させたい状況が発生しました。
その際、ExternalDNSの--annotation-filter
というオプションを指定して適切なHosted Zoneへレコードを登録させるようにしたので、その際の内容を備忘録として記事にまとめます。
環境
- Kubernetes バージョン 1.10
- EKS プラットフォームバージョン eks.2
- kube2iam 0.10.4
- ワーカーノードとなるEC2インスタンスのロールが汚れるのが嫌なので先に導入しています。 EKSへの導入手順はこちらの記事を参考にしました。
- ExternalDNS 0.5.8
今回やりたいこと
図のように、LoadBalancer Serviceが作成するELBのエンドポイントに対して、
- 内部向けELBはエンドポイントをPrivate Hosted ZoneにALIASレコードとして登録します。
- 外部向けのELBはエンドポイントをPublic Hostex ZoneにALIASレコードとして登録します。
Hosted Zoneの作成
Record Setの登録先となるHosted Zoneを先に作成しておきます。下のようなコマンドを使用して作成しました。
$ aws route53 create-hosted-zone \
--name <ドメイン名> \
--caller-reference <任意の値> # public hosted zoneの作成
$ aws route53 create-hosted-zone \
--name <ドメイン名> \
--vpc 'VPCRegion=<region>,VPCId=<vpc-id>' \
--caller-reference <任意の値> # private hosted zoneの作成
ExternalDNSのデプロイ
次にExternalDNSをデプロイしていきます。
基本的には、こちらのExternalDNSのドキュメントに沿って進めましたが、Hosted Zoneの振り分けおよびkube2iamを使用するため、2点変更を行いました。
- External DNS用IAMロールをkube2iamで使用できるようにするため、信頼関係のポリシーを少し変更しました。
- Deploymentについては、以下で紹介する設定のように
--annotation-filter
というオプションを使用してPublic用とPrivate用の2つを作成するようにしました。
変更した点に絞って設定内容を紹介します。
External DNS用IAMロールの作成
ExternalDNSに必要な権限を持ち、kube2iamでExternalDNSのPodに割り当てられるようにロールを作成していきます。
IAMロールには、こちらのExternalDNSのドキュメントに従い以下のようなポリシードキュメントで表されるような権限をもつIAM Policyをアタッチしました。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:ChangeResourceRecordSets"
],
"Resource": [
"arn:aws:route53:::hostedzone/*"
]
},
{
"Effect": "Allow",
"Action": [
"route53:ListHostedZones",
"route53:ListResourceRecordSets"
],
"Resource": [
"*"
]
}
]
}
また、このロールをkube2iamでPodに割り当てることができるようにするため、Trust Policyはこちらの記事を参考に以下のようにしました。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
},
{
"Effect": "Allow",
"Principal": {
"AWS": "<ワーカーノードインスタンスのロールARN>"
},
"Action": "sts:AssumeRole"
}
]
}
Public Hosted Zoneに外部向けELBのRecord Setを登録させる設定
ExternalDNSのDeploymentの設定です。振り分けを行うため、2つ作成するDeploymentのうちのPublic Hosted Zone用の設定です。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: external-dns-public
spec:
strategy:
type: Recreate
template:
metadata:
labels:
app: external-dns-private
annotations:
iam.amazonaws.com/role: <先に作成しておいたExternalDNSに必要な権限を持ったIAMロール名 (not ARN)>
spec:
serviceAccountName: external-dns
containers:
- name: external-dns
image: registry.opensource.zalan.do/teapot/external-dns:latest
args:
- --source=service
- --source=ingress
- --domain-filter=<Hosted Zoneのドメイン名>
- --provider=aws
- --policy=upsert-only
- --aws-zone-type=public # Public Hosted Zoneに登録
- --registry=txt
- --annotation-filter=service.beta.kubernetes.io/aws-load-balancer-internal=false # 外部向けELBのみ対象
- --txt-owner-id=my-identifier
Public Hosted Zone用のDeploymentではExternalDNSのオプションとして以下のものを指定しました。
--aws-zone-type=private
と指定し、Public Hosted Zoneに登録--annotation-filter=service.beta.kubernetes.io/aws-load-balancer-internal=false
と指定し、外部向けELBのみ対象- annotation-filterでこのように指定したため、外部向けELBを作成するLoadBalancer Serviceでは、
アノテーションで、
service.beta.kubernetes.io/aws-load-balancer-internal:"false"
と明示的に外部向けLBであることを指定する必要があります。 - 今回はLoadBalancer Serviceが対象のため、
service.beta.kubernetes.io/aws-load-balancer-internal
というアノテーションを指定していますが、Ingressの場合はkubernetes.io/ingress.class
というアノテーションを指定すると良いようです(参考)。
- annotation-filterでこのように指定したため、外部向けELBを作成するLoadBalancer Serviceでは、
アノテーションで、
また、Deploymentのannotationでiam.amazonaws.com/role: external-dns-iam-role
のように指定し、ExternalDNSに必要な権限を持ったIAMロールをPodに割り当てるようにしました。
Private Hosted Zoneに内部向けELBのRecord Setを登録させる設定
振り分けを行うため、2つ作成するDeploymentのうちのPrivate Hosted Zone用の設定です。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: external-dns-private
spec:
strategy:
type: Recreate
template:
metadata:
labels:
app: external-dns-private
annotations:
iam.amazonaws.com/role: <先に作成しておいたExternalDNSに必要な権限を持ったIAMロール名 (not ARN)>
spec:
serviceAccountName: external-dns
containers:
- name: external-dns
image: registry.opensource.zalan.do/teapot/external-dns:latest
args:
- --source=service
- --source=ingress
- --domain-filter=<Hosted Zoneのドメイン名>
- --provider=aws
- --policy=upsert-only
- --aws-zone-type=private # Private Bosted Zoneに登録
- --registry=txt
- --annotation-filter=service.beta.kubernetes.io/aws-load-balancer-internal=true # 内部向けELBのみ対象
- --txt-owner-id=my-identifier
Private Hosted Zone用のDeploymentではExternalDNSのオプションとしてPublic Hosted Zone用のときと同様に以下のものを指定しました。
--aws-zone-type=private
と指定し、Private Hosted Zoneに登録--annotation-filter=service.beta.kubernetes.io/aws-load-balancer-internal=true
と指定し、内部向けELBのみ対象に
IAMロールに関してもPublic Hosted Zone用の設定と同様です。
ここまで紹介した変更点以外は、こちらのExternalDNSのドキュメントに載っている設定をそのまま使用します。
動作確認
ここまででExternalDNSの準備はできたので実際に外部向け/内部向けロードバランサーを作成し、動作確認してみましょう。
外部向けELBを作成するLoadBalancer Serviceを作成してみる
apiVersion: v1
kind: Service
metadata:
name: external-lb
annotations:
external-dns.alpha.kubernetes.io/hostname: external-app.katainaka.org
service.beta.kubernetes.io/aws-load-balancer-internal: "false"
spec:
type: LoadBalancer
selector:
app: external-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
上のようなYAMLで外部向けELBを作成するServiceを作成すると、以下の画像のように指定したドメインのPublic Hosted Zoneに、Serviceから作成されたELBに結びついたALIASレコードが登録されました。
内部向けELBを作成するLoadBalancer Serviceを作成してみる
apiVersion: v1
kind: Service
metadata:
name: internal-lb
annotations:
external-dns.alpha.kubernetes.io/hostname: internal-app.katainaka.org
service.beta.kubernetes.io/aws-load-balancer-internal: "true"
spec:
type: LoadBalancer
selector:
app: internal-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
上のようなYAMLで内部向けELBを作成するServiceを作成すると、以下の画像のように指定したドメインのPrivate Hosted Zoneに、Serviceから作成されたELBに結びついたALIASレコードが登録されました。
まとめ
ExternalDNSの--annotation-filter
というオプションを使用することで、アノテーションの値に基づいてどのHosted Zoneにレコードを登録するかを振り分けることができました。今回はLoadBalancer Serviceで試しましたがExternalDNSはIngressにも対応しているためIngressでも同様のことを行うことが可能です。