EKSとExternalDNSでドメイン名を設定する

皆さん、こんにちは。技術開発グループのn-ozawanです。
暑いですね。部屋の中にいても熱中症になる危険がありますので、細目に水分補給するようにしましょう。

本題です。
EKSで構築されたアプリケーションに対してドメインを紐付ける方法としてExternalDNSがあります。ExternalDNSを利用すると、自動的にKubernetesのIngressで指定したホスト名でDNSホストゾーンのAレコードを登録してくれるので便利です。

ExternalDNS

ExternalDNSはKubernetesのクラスタで動作するPODで、外部に公開するKubernetesのアプリケーションとDNSプロバイダーを同期してくれます。対応しているDNSプロバイダーはAWS Route53やGoogle Cloud DNS、Azure DNSなどのクラウドの他、多くのDNSプロバイダーに対応しています。詳細はこちらを参照してください。

今回はAWSのEKSで構築された環境と、AWS Route53と同期するやり方を紹介したいと思います。

ゴール

ExternalDNSをHELMでインストールします。また、ExternalDNSからRoute53へのアクセス権限が必要ですので、ポリシーの定義とServiceAccountの作成が必要になります。ここまでをTerraformで構築します。最後にKubernetesのIngressのマニフェストを定義します。

サービスアカウントの作成

ExternalDNSからRoute53への操作を行えるようにするためにサービスアカウントを作成する必要があります。作成手順については、以前の記事「EKSでロードバランサーを構築する」で記載した「サービスアカウントの作成」と同じです。以前の記事と異なるのはポリシーの定義だけですので、本稿ではポリシーの定義を紹介します。

resource "aws_iam_policy" "external_dns" {
  name       = "external-dns-policy"
  policy     = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "route53:ChangeResourceRecordSets"
      ],
      "Resource": [
        "arn:aws:route53:::hostedzone/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "route53:ListHostedZones",
        "route53:ListResourceRecordSets"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}
POLICY
}

Route53のホストゾーンの参照と、そのホストゾーンのリソースレコードの変更および参照を許可しています。

ExternalDNSのインストール

ExternalDNSをHELMでインストールします。

resource "helm_release" "external_dns" {
  name            = "external-dns"
  chart           = "external-dns"
  repository      = "https://kubernetes-sigs.github.io/external-dns/"
  namespace       = "kube-system"

  dynamic "set" {
    for_each = {
      "serviceAccount.create" = false
      "serviceAccount.name" = "external-dns-service-account"
    }
    content {
      name = set.key
      value = set.value
    }
  }
}

chartは”external-dns”で、repositoryには”https://kubernetes-sigs.github.io/external-dns/”を指定します。

ExternalDNSは、デフォルトでサービスアカウントを作成します。今回は自前で用意したサービスアカウントを利用しますので、serviceAccount.createを”false”に指定して、サービスアカウントを作成しないようにします。また、serviceAccount.nameに先ほど作成したサービスアカウントの名前を指定します。

Ingressの定義

KubernetesのIngressを定義します。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: http-ingress
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
spec:
  rules:
  - host: www.ios-eks-example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: http-service
            port:
              number: 80

metadata.annotationsで指定しているのはALB(Application Load Balancer)と連携するための設定です。今回のExternalDNSとは関係ありませんが、外部へ公開するためには必要な設定となります。

ExternalDNSに関係するのはspec.rules.hostになります。クラスタにIngressリソースを反映した際に、spec.rules.hostに指定したホスト名で、Route53のホストゾーンにAレコードが登録されます。

spec.rules.httpには受け取ったトラフィックを、どのNodePortへ送るのかを指定します。

おわりに

Ingressの定義でAレコードまで登録してくれるExternalDNSは便利ではあります。ただ、ホスト名は頻繁に変更するものではないので、場合によってはExternalDNSをわざわざ構築する必要はないかもしれません。その辺は費用対効果を見て構築した方が良いでしょう。

ではまた。

Recommendおすすめブログ