ExternalDNS は Kubernetes の Service や Ingress の host と外部の DNS のレコードを同期するアプリケーション。Route53 のレコードの作成は CDK で行うこともできるが cluster.addManifest() してから非同期に作られ、Controller によって管理される ELB の扱いが難しい。
まずは Route53 のレコードを編集するための Role を作成する。
const externalDNSRole = new iam.Role(scope, 'ExternalDNSRole', {
roleName: `ExternalDNSRole-${cluster.clusterName}`,
assumedBy: new iam.WebIdentityPrincipal(
cluster.openIdConnectProvider.openIdConnectProviderArn,
{
"StringEquals": new cdk.CfnJson(scope, 'ExternalDNSRoleStringEquals', { value: {
[`${cluster.clusterOpenIdConnectIssuer}:aud`]: 'sts.amazonaws.com',
[`${cluster.clusterOpenIdConnectIssuer}:sub`]: 'system:serviceaccount:external-dns:external-dns-sa'
}}),
},
),
inlinePolicies: {
'Route53': new iam.PolicyDocument({
statements: [
new iam.PolicyStatement({
actions: [
'route53:ChangeResourceRecordSets',
],
resources: [
'arn:aws:route53:::hostedzone/*'
]
}),
new iam.PolicyStatement({
actions: [
'route53:ListHostedZones',
'route53:ListResourceRecordSets',
'route53:ListTagsForResource'
],
resources: [
'*'
]
})
]
})
}
})
既存のゾーンでの挙動を確認するためレコードをいくつか登録した。
Helm Chart で 対象のゾーンを domainFilters で指定して ExternalDNS をインストールする。複数の ExternalDNS が同じドメインを参照する場合、txtOwnerId で変更するレコードが選択されるため、重複しない値にしないと相互にレコードを削除しようとしてしまう。
const externalDns = cluster.addHelmChart('ExternalDNS', {
release: 'external-dns',
chart: 'external-dns',
repository: 'https://kubernetes-sigs.github.io/external-dns',
version: '1.14.3',
namespace: 'external-dns',
createNamespace: true,
values: {
serviceAccount: {
name: "external-dns-sa",
annotations: {
'eks.amazonaws.com/role-arn': externalDNSRole.roleArn
}
},
sources: [
'service',
'ingress'
],
domainFilters: ['externaldns.test'],
provider: 'aws',
policy: 'sync', // or 'upsert-only'
awsZoneType: 'public',
registry: 'txt', // Specify the registry for storing ownership and labels
txtOwnerId: 'external-dns', // Specify an identifier for this instance of ExternalDNS
},
wait: true,
})
if (cluster.albController) {
externalDns.node.addDependency(cluster.albController)
}
Service の external-dns.alpha.kubernetes.io/hostname annotations や Ingress の rule.host を指定すると
apiVersion: v1
kind: Service
metadata:
name: nginx
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: external
external-dns.alpha.kubernetes.io/hostname: cccc.externaldns.test
spec:
type: LoadBalancer
ports:
- port: 80
name: http
targetPort: 80
selector:
app: nginx
対応する A レコードと “heritage=external-dns,external-dns/owner=external-dns,external-dns/resource=service/default/nginx” のような TXT レコードが作られる。
Desired change: CREATE cccc.externaldns.test A [Id: /hostedzone/****]
Desired change: CREATE cccc.externaldns.test TXT [Id: /hostedzone/****]
Desired change: CREATE cname-cccc.externaldns.test TXT [Id: /hostedzone/****]
3 record(s) in zone externaldns.test. [Id: /hostedzone/****] were successfully updated
Applying provider record filter for domains: [externaldns.test. .externaldns.test.]
All records are already up to date
Load Balancer Controller の ALB は Host ヘッダーによるルーティングを行う。
EKSクラスタにAWS Load Balancer ControllerをインストールしてALBのIngressを立てる - sambaiz-net
policyがsyncの場合、リソースを削除すると作られたレコードは削除されるが、既存のレコードは残る。
Desired change: DELETE cccc.externaldns.test A [Id: /hostedzone/****]
Desired change: DELETE cccc.externaldns.test TXT [Id: /hostedzone/****]
Desired change: DELETE cname-cccc.externaldns.test TXT [Id: /hostedzone/****]
3 record(s) in zone externaldns.test. [Id: /hostedzone/****] were successfully updated
All records are already up to date
同名のレコードを登録するには external-dns.alpha.kubernetes.io/set-identifier と併せて external-dns.alpha.kubernetes.io/aws-weight などを設定する必要がある。
既存のレコードとルーティングポリシーが異なる場合エラーになる。
Failure in zone externaldns.test. [Id: /hostedzone/*****] when submitting change batch: InvalidChangeBatch: [RRSet with DNS name bbbb.externaldns.test., type A, SetIdentifier nginx cannot be created as a non-weighted set exists with the same name and type.]\n\tstatus code: 400