Amazon EKS ExternalDNSでサービスを公開する


はじめに

本記事はAmazon EKSでExternalDNSのデプロイを行ない、サービスを公開する方法について記載しています。

Amazon EKSでクラスターを作成し、ドメインを取得してアプリケーションを外部に公開するためには、ドメインとAmazon EKSを紐付ける作業が必要になります。

ExternalDNSを用いてデプロイすることで動的にServiceとドメインの紐付けができます。また、サブドメインの管理も柔軟に行うことができます。

ExternalDNSの構築

ExternalDNSを使用するためにはドメインの取得が必要です。

ドメインはお名前.comなどのドメイン登録サービスか、Amazon Web Services(AWS)のRoute53で取得します。なお、お名前.com等外部のドメイン登録サービスを利用する場合は、Route53で管理するためネームサーバの設定が必要になります。

本記事ではお名前.comで取得したドメインを、Route53で管理する場合を例に解説します。

Route53

はじめにAWSコンソール画面からRoute53を選択します。
画面左ペインの「ホストゾーン」を選択し、「ホストゾーンの作成」をクリックします。

ドメイン名に取得したドメインの名前を入力し、タイプはパブリックホストゾーンを選択して「ホストゾーンの作成」をクリックします。

作成されたネームサーバの情報は、ドメインを取得したお名前.comなどのドメイン登録サービスのネームサーバ情報に設定します。

IAMのポリシー設定

ExternalDNSからRoute53を操作するための権限を、IAMのポリシーに設定します。

AWSコンソール画面からIAMを選択します。
画面左ペインのポリシーを選択し、「ポリシーの作成」をクリックします。

  • ポリシーの作成
{
"Version": "2012-10-17",
 "Statement": [
   {
     "Effect": "Allow",
     "Action": [
       "route53:ChangeResourceRecordSets"
     ],
     "Resource": [
       "arn:aws:route53:::hostedzone/*"
     ]
   },
   {
     "Effect": "Allow",
     "Action": [
       "route53:ListHostedZones",
       "route53:ListResourceRecordSets"
     ],
     "Resource": [
       "*"
     ]
   }
 ]
}

ExternalDNSのIAMロールの作成

ExternalDNS用のIAMロールを作成して、先ほど作成したポリシーとAmazon EKSのノードとの紐付けを行います。

AWSコンソール画面からIAMを選択します。
画面左ペインのロールを選択し、「ロールの作成」をクリックします。

先ほど作成したポリシーをアタッチし、信頼関係を編集します。
信頼関係は以下のアクセスコントロールポリシードキュメントを編集します。
ポリシードキュメントの<EKSワーカーノードのARN>は、使用するAmazon EKSノードのロールARNの文字列を記載します。

  • 信頼関係の編集
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    },
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": <EKSワーカーノードのARN>
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

マニフェストファイルの作成

デプロイするためのマニフェストファイルを作成します。
annotationsの<EKSワーカーノードのARN>は、使用するAmazon EKSノードのロールARNの文字列を、domain-filterの<取得したドメイン名>は、取得したドメイン名を記載します。

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","watch"]
- apiGroups: [""]
  resources: ["endpoints"]
  verbs: ["get","watch","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
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: external-dns
spec:
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: external-dns
  template:
    metadata:
      labels:
        app: external-dns
      annotations:
        iam.amazonaws.com/role: <EKSワーカーノードの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=<取得したドメイン名>
        - --provider=aws
        - --policy=sync
        - --aws-zone-type=public
        - --registry=txt
        - --txt-owner-id=example-identifier

ExternalDNSのデプロイ

マニフェストファイルの作成後、kubectlコマンドでデプロイします。
以下のコマンドを実行し、ExternalDNSのデプロイを行ないます。

$ kubectl apply -f external-dns-manifest.yaml

以下はサンプルのデプロイメントとサービスになります。
Serviceとドメインが紐づいているのでServiceを介してNginxにアクセスできます。

  • sample-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
spec:
  selector:
    matchLabels:
      app: sample-app
  replicas: 2
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
      - name: nginx-container
        image: nginx:latest
        ports:
        - containerPort: 80
  • sample-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: sample-service
  annotations:
    external-dns.alpha.kubernetes.io/hostname: test.<取得したドメイン>
spec:
  type: LoadBalancer
  selector:
    app: sample-app
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

以下のコマンドを実行し、デプロイします。

$ kubectl apply -f sample-deployment.yaml
$ kubectl apply -f sample-service.yaml

デプロイ後、ブラウザからtest.<取得したドメイン名>にアクセスするとNginxのWelcome画面が表示されます。

以下のコマンドを実行し、リアルタイムでドメインの反映を確認できます。
ドメインは約1分程度で反映されます。

$ while true; do dig test.<取得したドメイン名>; sleep 1;done

おわりに

以上、Amazon EKSでExternalDNSを用いてデプロイする方法でした。
ExternalDNSを使用することで高速デプロイを実現しますが、HTTPSなどは別途考慮が必要です。