在 Day 17,我們透過 AWS Load Balancer Controller,讓 Kubernetes 的 Service / Ingress 可以自動建立對應的 ALB 或 NLB。雖然流量入口已經打通,但還有一個缺口:DNS 解析。
若每次建立 Ingress / Service,都要手動到 Route53 建立記錄,顯然既麻煩又容易出錯。這就是今天的主角 —— ExternalDNS。
ExternalDNS 是一個 Kubernetes Controller,會自動觀察叢集裡的 Service 和 Ingress,然後在 DNS 提供者(AWS Route53、Cloudflare…等)建立或刪除對應的 DNS record。
舉例:
host: argocd.example.com 的 Ingress。argocd.example.com → NLB/ALB 的 CNAME/A記錄。我們的 DNS 並不是由專案帳號直接管理,而是放在另一個專用的 AWS Account。
因此,這邊我們不會使用 ApplicationSet,而是單純用 Application 在 central cluster 安裝 ExternalDNS。
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: external-dns
  namespace: argocd
spec:
  project: infra
  source:
    repoURL: https://kubernetes-sigs.github.io/external-dns
    chart: external-dns
    targetRevision: 1.14.5
    helm:
      releaseName: external-dns
      valueFiles:
        - infra-charts/external-dns/values.yaml
  destination:
    name: in-cluster
    namespace: kube-system
  syncPolicy:
    syncOptions:
      - serverSideApply=true
以下是我們實際使用的 values(精簡版):
serviceAccount:
  create: true
  name: external-dns
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::DNSACCOUNT00:role/external-dns
rbac:
  create: true
interval: 5m
policy: sync
registry: txt
provider: aws
tolerations:
  - operator: Exists
extraArgs:
  - --annotation-filter=external-dns.alpha.kubernetes.io/exclude notin (true)
resources:
  requests:
    cpu: 10m
    memory: 50Mi
  limits:
    memory: 50Mi
txtOwnerId: example-internal
txtPrefix: example-internal-edns-
domainFilters:
  - example.com
eks.amazonaws.com/role-arn 綁到 DNS 管理帳號的 IAM Role。external-dns.alpha.kubernetes.io/exclude: true 的 Ingress,避免誤加記錄。細節可以看這項 comment。有了前面幾個幫我們打通網路的工具(ingress-nginx / load balancer controller / external-dns)之後,我們終於可以拿 ArgoCD 建立 ingress,並且用 domain name 正正當當的連進去看、不用再使用 port forward 了!
我們只需要在 ArgoCD 的 value file 中加入以下的設定,並再次使用 terraform apply:
server:
  ingress:
    enabled: true
    ingressClassName: nginx
    hosts:
      - argocd.example.com
Helm chart 就會自動再生成一個 ingress,內容如下:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: argo-cd-argocd-server
  namespace: argocd
spec:
  ingressClassName: nginx
  rules:
  - host: argocd.example.com
    http:
      paths:
      - backend:
          service:
            name: argo-cd-argocd-server
            port:
              number: 443
        path: /
        pathType: Prefix
於是 ExternalDNS 會偵測到多了這個 ingress,並將這個 ingress 對應的 record 更新到 hosted zone 中:

接著打開我們註冊到 A record 中的 ArgoCD URL,就可以看到熟悉的 UI 了:

今天我們安裝了 ExternalDNS,讓 Kubernetes 的 Ingress / Service 自動和 Route53 同步:
到這裡,從 Pod → Service → Ingress → NLB/ALB → DNS 的完整流量鏈路已經打通。
在 Day 19,我們會進一步介紹 Monitoring(Prometheus & Grafana),讓這些基礎設施不只會動,還能被觀察 👀