ExternalDNS@ネットワーク系¶
はじめに¶
本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。
01. ExternalDNSアドオンの仕組み¶
アーキテクチャ¶
ExternalDNSコントローラーは、ネットワークからのリクエストにDNSレコードを必要とするKubernetesリソース (例:Ingress、Serviceなど) の設定値に応じて、DNSプロバイダー (例:AWS Route53) にDNSレコードを自動的に作成する。
Ingressコントローラー (例:aws-load-balancer-controller、glb-controller) と合わせて使用し、パブリックネットワークからのリクエストをArgoCDのダッシュボード (argocd-server) にルーティング可能にする。
AWSの場合¶
以下のようなIngressを定義したとする。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: foo-alb-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
spec:
ingressClassName: alb
rules:
- host: example.com
http:
paths:
- backend:
service:
name: foo-service
port:
number: 80
path: /
pathType: Prefix
するとExternalDNSアドオンは、Ingressの.spec.rules[*].host
キーに応じて、AWS Route53にAレコードとTXTレコードを作成する。
$ kubectl logs external-dns -n kube-system | grep example.com
time="2023-02-28T10:09:30Z" level=info msg="Desired change: CREATE example.com A [Id: /hostedzone/*****]"
time="2023-02-28T10:09:30Z" level=info msg="Desired change: CREATE example.com TXT [Id: /hostedzone/*****]"
02. マニフェスト¶
マニフェストの種類¶
ExternalDNSアドオンは、Deployment (external-dns) 、Serviceなどのマニフェストから構成される。
Deployment配下のPod¶
▼ external-dns¶
記入中...
apiVersion: v1
kind: Pod
metadata:
name: external-dns
namespace: kube-system
spec:
serviceAccountName: external-dns
containers:
- name: external-dns
image: registry.k8s.io/external-dns/external-dns:v0.13.2
args:
# DNSゾーンタイプを設定する
- --aws-zone-type=public
- --log-level=info
- --log-format=text
- --registry=txt
# DNSレコード追加のために検知するKubernetesリソースを設定する
- --source=service
- --source=ingress
# DNSレコード追加対象のDNSゾーン (例:AWS Route53のホストゾーン) を設定する
- --domain-filter=example.com
# Ingressからルールを削除した場合に、対応するAWSリソース (AWS ALBリスナールール、AWS Route53 DNSレコード) も削除する
- --policy=sync
- --provider=aws
- --txt-owner-id=external-dns
env:
- name: AWS_DEFAULT_REGION
value: ap-northeast-1
...
この時、--annotation-filter
オプションを使用すると、条件に合致するアノテーションを持つIngressやServiceを、ExternalDNSの検知から除外する。
apiVersion: v1
kind: Pod
metadata:
name: external-dns
namespace: kube-system
spec:
serviceAccountName: external-dns
containers:
- name: external-dns
image: registry.k8s.io/external-dns/external-dns:v0.13.2
args:
...
- --annotation-filter=<任意の.metadata.annotationsキー名> in <値>
- --annotation-filter=<任意の.metadata.annotationsキー名> notin <値>
...
ServiceAccount、ClusterRole¶
▼ external-dns¶
ExternalDNSコントローラーがDNSプロバイダー (例:AWS Route53) にリクエストを送信できるように、ExternalDNSコントローラーにはClusterRoleに基づく認可スコープを持つ。
apiVersion: v1
kind: ServiceAccount
metadata:
name: external-dns
namespace: kube-system
labels:
app.kubernetes.io/name: external-dns
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: external-dns
labels:
app.kubernetes.io/name: external-dns
rules:
- apiGroups: [""]
resources: ["services", "endpoints", "pods", "nodes"]
verbs: ["get", "watch", "list"]
- apiGroups: ["extensions", "networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: external-dns-viewer
labels:
app.kubernetes.io/name: external-dns
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: external-dns
subjects:
- kind: ServiceAccount
name: external-dns
namespace: kube-system
03. セットアップ¶
Kubernetes側¶
▼ Helmの場合¶
Helmを使用する。
別途、IngressやServiceの作成が必要である。
$ helm repo add <チャートリポジトリ名> https://kubernetes-sigs.github.io/external-dns/
$ helm install <Helmリリース名> <チャートリポジトリ名>/external-dns -n kube-system --version <バージョンタグ>
AWS側¶
▼ Terraformの公式モジュールの場合¶
ArgoCDのセットアップのうち、AWS側で必要なものをまとめる。
ここでは、Terraformの公式モジュールを使用する。
module "iam_assumable_role_with_oidc_external_dns" {
source = "terraform-aws-modules/iam/aws//modules/iam-assumable-role-with-oidc"
version = "<バージョン>"
# ExternalDNSのPodに紐付けるIAMロール
create_role = true
role_name = "foo-external-dns"
# AWS EKS ClusterのOIDCプロバイダーURLからhttpsプロトコルを除いたもの
provider_url = replace(module.eks.cluster_oidc_issuer_url, "https://", "")
# AWS IAMロールに紐付けるIAMポリシー
role_policy_arns = [
"arn:aws:iam::<AWSアカウントID>:policy/ExternalDNSIAMPolicy"
]
# ExternalDNSのPodのServiceAccount名
# ServiceAccountは、Terraformではなく、マニフェストで定義した方が良い
oidc_fully_qualified_subjects = [
"system:serviceaccount:kube-system:foo-external-dns",
...
]
}
module "acm" {
source = "terraform-aws-modules/acm/aws"
version = "~> 4.3.2"
domain_name = aws_route53_zone.foo.name
zone_id = aws_route53_zone.foo.zone_id
# ワイルドカード証明書とする
subject_alternative_names = [
"*.example.com"
]
}
resource "aws_route53_zone" "foo" {
name = "example.com"
}
resource "aws_route53_record" "foo" {
zone_id = aws_route53_zone.foo.id
name = "foo.example.com"
# Route53のTerraformとExternalDNSのマニフェストを分離するために、NSタイプを使用する
type = "NS"
ttl = 30
records = aws_route53_zone.foo.name_servers
}