Amazon EKS で ExternalDNS を設定する方法

所要時間4分
0

自分の Amazon Elastic Kubernetes サービス (Amazon EKS) で ExternalDNS を設定したいと考えています。

簡単な説明

ExternalDNS は Amazon EKS クラスターで実行されるポッドです。Amazon EKS で ExternalDNS をプラグインとして使用するには、AWS Identity and Access Management (IAM) のアクセス許可を設定します。これらのアクセス許可では、Amazon EKS に Amazon Route 53 へのアクセス許可を付与する必要があります。

注記: 次の解決方法を実施し始める前に、ドメイン名と Route 53 ホストゾーンが存在することを確認してください。

解決方法

IAM アクセス許可を設定して ExternalDNS をデプロイする

  1. AWS アカウント内に Route 53 レコードを作成、更新、削除するアクセス許可を ExternalDNS ポッドに付与するように、IAM アクセス許可を設定します。

IAM ポリシーは次のとおりです。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "route53:ChangeResourceRecordSets"
      ],
      "Resource": [
        "arn:aws:route53:::hostedzone/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "route53:ListHostedZones",
        "route53:ListResourceRecordSets"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}

注記: 前述のポリシーを調整して、明示的なホストゾーン ID の更新を許可することもできます。

  1. 前述のポリシーを使用して、サービスアカウントに IAM ロールを作成します。
eksctl create iamserviceaccount --name SERVICE_ACCOUNT_NAME --namespace NAMESPACE --cluster CLUSTER_NAME --attach-policy-arn IAM_POLICY_ARN --approve

注記: SERVICE_ACCOUNT_NAME をサービスアカウントの名前、NAMESPACE を名前空間、CLUSTER_NAME をクラスターの名前、そして IAM\ _POLICY\ _ARN を IAM ポリシーの ARN に置き換えてください。

サービスアカウントの名前を確認するには、次のコマンドを実行します。

kubectl get sa

出力例:

NAME           SECRETS   AGE
default        1         23h
external-dns   1         23h

上記の出力例では、external-dns はサービスアカウントにその作成時に付けられた名前です。

  1. ExternalDNS をデプロイします。

Amazon EKS クラスターで RBAC がオンになっているかどうかを確認します。

kubectl api-versions | grep rbac.authorization.k8s.io

注記: 次のマニフェストを適用する前に、 (GitHub のウェブサイトに) ExternalDNS の最新バージョンがあるかどうかを確認してください。

次のコマンドを実行します。

kubectl apply DEPLOYMENT_MANIFEST_FILE_NAME.yaml

注記: DEPLOYMENT_MANIFEST_FILE_NAME をデプロイマニフェストのファイル名に置き換えてください。

RBAC がオンになっている場合は、次のマニフェストを使用して ExternalDNS をデプロイします。

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: external-dns
rules:
- apiGroups: [""]
  resources: ["services","endpoints","pods"]
  verbs: ["get","watch","list"]
- apiGroups: ["extensions","networking.k8s.io"]
  resources: ["ingresses"]
  verbs: ["get","watch","list"]
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["list","watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
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
    spec:
      serviceAccountName: external-dns
      containers:
      - name: external-dns
        image: k8s.gcr.io/external-dns/external-dns:v0.10.2
        args:
        - --source=service
        - --source=ingress
        - --domain-filter=external-dns-test.my-org.com # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones
        - --provider=aws
        - --policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization
        - --aws-zone-type=public # only look at public hosted zones (valid values are public, private or no value for both)
        - --registry=txt
        - --txt-owner-id=my-hostedzone-identifier
      securityContext:
        fsGroup: 65534 # For ExternalDNS to be able to read Kubernetes and AWS token files

RBAC がオンになっていない場合は、次のマニフェストを使用して ExternalDNS をデプロイします。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: external-dns
spec:
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: external-dns
  template:
    metadata:
      labels:
        app: external-dns
    spec:
      containers:
      - name: external-dns
        image: k8s.gcr.io/external-dns/external-dns:v0.10.2
        args:
        - --source=service
        - --source=ingress
        - --domain-filter= <Your_R53_Domain_Name>  # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones
        - --provider=aws
        - --policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization
        - --aws-zone-type=public # only look at public hosted zones (valid values are public, private or no value for both)
        - --registry=txt
        - --txt-owner-id=<Your_R53_HostedZone_Id>
  1. デプロイが成功したことを確認します。
kubectl get deployments

出力例:

NAME           READY   UP-TO-DATE   AVAILABLE   AGE
external-dns   1/1     1            1           85m

また、ログをチェックすれば、レコードが最新であることを確認することもできます。

kubectl logs external-dns-9f85d8d5b-sx5fg

出力例:

....
....
time="2022-02-10T20:22:02Z" level=info msg="Instantiating new Kubernetes client"
time="2022-02-10T20:22:02Z" level=info msg="Using inCluster-config based on serviceaccount-token"
time="2022-02-10T20:22:02Z" level=info msg="Created Kubernetes client https://10.100.0.1:443"
time="2022-02-10T20:22:09Z" level=info msg="Applying provider record filter for domains: [<yourdomainname>.com. .<yourdomainname>.com.]"
time="2022-02-10T20:22:09Z" level=info msg="All records are already up to date"
....
....

ExternalDNS が機能していることを確認

  1. LoadBalancer として公開されるサービスであると同時に、Route 53 でホストされているドメイン名を介して外部にルーティングできるサービスを作成します。
kubectl apply SERVICE_MANIFEST_FILE_NAME.yaml

注記: SERVICE_MANIFEST_FILE_NAME をサービスマニフェストのファイル名に置き換えてください。

マニフェストは次のとおりです。

apiVersion: v1
kind: Service
metadata:
  name: nginx
  annotations:
    external-dns.alpha.kubernetes.io/hostname: DOMAIN_NAME
spec:
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
  type: LoadBalancer
  selector:
    app: nginx

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - image: nginx
          name: nginx
          ports:
            - containerPort: 80
              name: http

注記: DOMAIN_NAME を自身のドメイン名に置き換えてください。

  1. NGINX サービスが LoadBalancer タイプで作成されていることを確認します。
kubectl get svc

出力例:

NAME         TYPE           CLUSTER-IP      EXTERNAL-IP                                                              PORT(S)        AGE
kubernetes   ClusterIP      10.100.0.1      <none>                                                                   443/TCP        26h
nginx        LoadBalancer   10.100.234.77   a1ef09255d52049f487e05b4f74faea6-954147917.us-west-1.elb.amazonaws.com   80:30792/TCP   74m

注記: このサービスは、Route 53 ホストゾーンレコードを自動的に作成します。

ログをチェックして、Route 53 レコードが作成されたことを確認します。

kubectl logs external-dns-9f85d8d5b-sx5fg

出力例:

...
...
...
time="2022-02-10T21:22:43Z" level=info msg="Applying provider record filter for domains: [<domainname>.com. .<domainname>.com.]"
time="2022-02-10T21:22:43Z" level=info msg="Desired change: CREATE <domainname>.com A [Id: /hostedzone/Z01155763Q6AN7CEI3AP6]"
time="2022-02-10T21:22:43Z" level=info msg="Desired change: CREATE <domainname>.com TXT [Id: /hostedzone/Z01155763Q6AN7CEI3AP6]"
time="2022-02-10T21:22:43Z" level=info msg="2 record(s) in zone xxx.com. [Id: /hostedzone/Z01155763Q6AN7CEI3AP6] were successfully updated"
time="2022-02-10T21:23:43Z" level=info msg="Applying provider record filter for domains: [<domainname>.com. .<domainname>.com.]"
time="2022-02-10T21:23:43Z" level=info msg="All records are already up to date"
...
...
...

ExternalDNS の詳細と例については、「AWS 上のサービス用の ExternalDNS の設定」(GitHub ウェブサイト) および「ExternalDNS の設定」(Kubernetes ウェブサイト) を参照してください。


AWS公式
AWS公式更新しました 1年前
コメントはありません