Amazon EKSにデプロイしたGitLabのALB DNS名をExternalDNSを使ってRoute53に登録する
Amazon EKSにHelmを使ってGitLabをインストールしました。
検証で作成削除する機会が多く、毎回Route53レコードを手動で登録するのが面倒に感じました。
ExternalDNSを使って、GitLab公開用のALBをRoute53に登録してみました。
ExternalDNSとは?
ExternalDNSは、KubernetesのServiceやIngressのリソースを自動的にパブリックDNSプロバイダー(Route53、Cloud DNS、Azure DNSなど)に同期させるツールです。
例えば、AWS Load Balancer Controllerを利用して、ELBを作成したとします。
ELBをインターネット上に公開したいときに、DNSプロバイダーにELB用のレコードを作成する必要があります。
手動で作成することも可能ですが、マニフェスト適用時に自動でレコードも追加したいです。
ExternalDNSを使うことで、これを実現できます。
なぜExternalDNSを選択したか?
前提
ExternalDNSを使うか、TerraformでRoute53レコードを管理するか迷いました。
現状の構成では、GitLabのHelmチャートにてAWS Load Balancer Controller経由でALBが作成されるようにしていました。(TerraformでALBを管理していない)
そのため、ALBのDNS名はHelmインストール後に分かります。
terraform apply(EKSクラスター等)
-> helm install
という流れをとっており、helm install
後にterraform apply(route53レコード)
を行うのは手順が複雑に思いました。
ExternalDNSとAWS Load Balancer Controller TargetGroupBinding
以下2つの方式を検討し今回は「2.」のExternalDNSを利用しました。
- AWS LoadBalancer ControllerでALB関連リソースを作成・ExternalDNSを利用してRoute53レコードを作成
- TerraformでALB・Route53レコードを作成、AWS Load Balancer ControllerのTargetGroupBindingを利用して、Terraformで作成したTargetGroupにノードを登録する
理由はGitLabのHelmチャート側でやってくれるものはそちらに寄せたかったからです。
GitLabのHelmチャートでは、ALB関連の設定を一通りやってくれます。(ALB・リスナールール・ターゲットグループ作成、ノードのターゲットグループの紐づけ等)
Helmチャート側のアップデートでALBの設定変更が必要になった場合も、バージョンを上げるだけで済みます。
一方、TerraformでALB作成からやってしまうと、変更内容によってはTerraformへ記述の追加等が必要になります。
TargetGroupBinding - AWS Load Balancer Controller
余談: HelmのTerraform管理
Helm部分もTerraform化して、helm_release
のattributes
からALBのDNS名を取得しaws_route53_record
に渡す方法も考えられます。
この方法はHelmで生成されたマニフェストから値を抜き出す必要があります。
Helmチャートのバージョンアップで、生成されるマニフェストが変わったときに対応するのが大変かもしれません。
Helmチャートを自組織で管理している場合だとハードルは下がるかもしれませんが、今回はGitLab提供のHelmチャートを使うため厳しいように思いました。
helm_release | Resources | hashicorp/helm | Terraform | Terraform Registry
やってみた
以下を参考に、ExternalDNSをセットアップします。
Setting up ExternalDNS for Services on AWS - external-dns
ExternalDNSのインストール
Helmを使うため、ExternalDNS用のvalues.yaml
を用意します。
provider:
name: aws
env:
- name: AWS_DEFAULT_REGION
value: <リージョン> # example: us-east-1
EKSクラスターにExternalDNSをインストールします。
helm repo add external-dns https://kubernetes-sigs.github.io/external-dns/
helm install external-dns external-dns/external-dns -f values.yaml -n kube-system
Deploymentexternal-dns
が作成されていたらOKです。
kubectl get deployments.apps -n kube-system | grep external-dns
external-dns 1/1 1 1 5m
インストール時に自動でexternal-dns
という名前のServiceAccountが作成されます。
kubectl get sa external-dns -o yaml -n kube-system
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
meta.helm.sh/release-name: external-dns
meta.helm.sh/release-namespace: kube-system
creationTimestamp: "2025-02-23T02:32:55Z"
labels:
app.kubernetes.io/instance: external-dns
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: external-dns
app.kubernetes.io/version: 0.15.1
helm.sh/chart: external-dns-1.15.2
name: external-dns
namespace: kube-system
resourceVersion: "3338"
uid: 3669ef20-6a59-4211-8077-00e14cb6bb80
次のステップでは、このServiceAccountに対して、Pod Identityを利用してAWSの権限を付与します。
IAM Role作成・Pod Identityの関連付けを作成
Amazon EKSクラスターとAWS間の認証はPod Identityを使います。
以下のTerraformコードでExternalDNS用のIAMポリシーとIAMロールをデプロイします。
### External DNS
resource "aws_iam_role" "external_dns" {
name = "test-external-dns"
assume_role_policy = data.aws_iam_policy_document.eks_pod_assume_role.json
}
data "aws_iam_policy_document" "eks_pod_assume_role" {
statement {
actions = [
"sts:AssumeRole",
"sts:TagSession"
]
effect = "Allow"
principals {
type = "Service"
identifiers = ["pods.eks.amazonaws.com"]
}
}
}
resource "aws_iam_policy" "external_dns_policy" {
name = "test-external-dns-policy"
description = "Policy for External DNS to manage Route 53 records"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"route53:ChangeResourceRecordSets"
]
Resource = [
"arn:aws:route53:::hostedzone/*" # hostedzoneを指定することで、より細かな制御が可能
]
},
{
Effect = "Allow"
Action = [
"route53:ListHostedZones",
"route53:ListResourceRecordSets",
"route53:ListTagsForResource"
]
Resource = [
"*"
]
}
]
})
}
resource "aws_iam_role_policy_attachment" "external_dns" {
role = aws_iam_role.external_dns.name
policy_arn = aws_iam_policy.external_dns_policy.arn
}
resource "aws_eks_pod_identity_association" "external_dns" {
cluster_name = module.eks.cluster_name
namespace = "kube-system"
service_account = "external-dns"
role_arn = aws_iam_role.external_dns.arn
}
Terraformを実行してリソースを作成します。
terraform init
terraform plan
terraform apply
GitLab values.yamlを更新
GitLab側はアノテーションexternal-dns.alpha.kubernetes.io/hostname
を追加するだけです。
nginx-ingress:
enabled: false
global:
# 省略
ingress:
# Common annotations used by kas, registry, and webservice
annotations:
alb.ingress.kubernetes.io/backend-protocol: HTTP
alb.ingress.kubernetes.io/certificate-arn: <ACM ARN>
alb.ingress.kubernetes.io/group.name: gitlab
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS": 443}]'
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
kubernetes.io/ingress.class: alb
nginx.ingress.kubernetes.io/connection-proxy-header: "keep-alive"
# 以下を追加
external-dns.alpha.kubernetes.io/hostname: <ドメイン名> #example: gitlab.example.com
この際、ドメイン名はgitlab.<ドメイン名>
としてください。(hostnameを変えている場合は、gitlab
部分も合わせて変える必要があります)
ドメイン名だけではドメイン名に対して、ALB用のレコードが作成されます。
対して、デフォルトのGitLab用のALBのリスナールールのHTTPホストヘッダーはgitlab.<ドメイン名>
で作成されます。
example.comがドメイン名だとすると、以下の状況になり疎通ができません。
- Route53レコード
- レコード名: example.com
- 値: ALB DNS名
- ALBリスナールール
-HTTPホストヘッダー: gitlab.example.com
values.yaml
の準備ができたら、適用します。
helm upgrade gitlab gitlab/gitlab -n gitlab -f values.yaml
動作確認
PodのログからRoute53レコードの更新を確認できます。
Pod名(external-dns-645b8d7fdb-tlmpd
の部分)は各自の環境に合わせて変更してください。
kubectl get pod -n kube-system # pod名の確認
kubectl logs external-dns-645b8d7fdb-tlmpd # ログの確認
冒頭のブログの手順でGitLabを構築している場合、gitlab
kas
registry
分のAレコードとTXTレコード作成のログが確認できるはずです。
time="2025-02-23T02:54:15Z" level=info msg="Desired change: UPSERT gitlab.example.com A" profile=default zoneID=/hostedzone/XXXXXXXXXX zoneName=example.com.
time="2025-02-23T02:54:15Z" level=info msg="Desired change: UPSERT gitlab.example.com TXT" profile=default zoneID=/hostedzone/XXXXXXXXXX zoneName=example.com.
ブラウザのアドレスバーにgitlab.<ドメイン名>
を入力して、GitLabにアクセスできることも確認できました。
おわりに
ExternalDNSを使うことで、簡単にRoute53レコードの管理もKubernetes側で管理できました。
AWS Load Balancer ControllerでELB管理している環境と相性が良いように思いました。
EKSを利用している場合は、IaCツールを使っていることも多いと思います。
Route53レコードをIaCツールで管理するパターンも多いと思いますが、ExternalDNS利用も選択肢の一つとして持っておきたいですね。
以上、AWS事業本部の佐藤(@chari7311)でした。)