[kubernetes] ExternalDNS란? 개념부터 설치까지 정리(AWS EKS)
IT/DevOps

[kubernetes] ExternalDNS란? 개념부터 설치까지 정리(AWS EKS)

반응형

ExternalDNS란?


ExternalDNS는 kubernetes dns(kube-dns)와 상반되는 개념으로 내부 도메인서버가 아닌 Public한 도메인서버(AWS Route53, GCP DNS 등)를 사용하여 쿠버네티스의 리소스를 쿼리할 수 있게 해주는 오픈소스 솔루션입니다.

ExternalDNS를 사용하면 public도메인 서버가 무엇이든 상관없이 쿠버네티스 리소스를 통해서 DNS레코드를 동적으로 관리 할 수 있습니다. 많은 기업들이 두려워하는 Vendor Lock-In에 좀 더 자유로워 질 수 있게 되는 것이죠.

사용가능한 public DNS 제공 업체들

ExternalDNS를 사용할 수 있는 public DNS서버들은 다음 URL을 https://github.com/kubernetes-sigs/external-dns#the-latest-release-v08 참고하면 자세히 확인이 가능하며 대표적인 몇개만 나열해보도록 하겠습니다.

  • Google Cloud DNS
  • AWS Route 53
  • AzureDNS
  • BlueCat
  • CloudFlare
  • RcodeZero
  • DigitalOcean
  • Hetzne
  • Oracle Cloud Infrastructure DNS
    ... 등등 (처음 보는 업체들도 많이 있네요)

역시 우리의 오픈소스 쿠버네티스는 관대합니다만 역시나 오픈소스이기 때문에 모든 업체를 stability 한 레벨로 지원해주고 있지는 않습니다. 차츰 개선되겠지만 그 기간이 얼마나 걸릴지는 파악하기가 힘들죠. (오픈소스의 최대 단점 중 하나입니다.)

현재 2021.09 기준으로 GCP DNS, AWS Route53이 stable단계 이며 나머지는 모두 Alpha, Beta 단계 입니다.

ExternalDNS 설치

ExternalDNS설치는 AWS EKS클러스터 기준으로 설명드리겠습니다.

쿠버네티스 Namespace생성

논리적으로 구분하여 관리하기위해 ExternalDNS용도의 namespace를 생성합니다.

kubectl create namespace external-dns

IAM Policy 생성

ExternalDNS가 AWS Route53를 제어해야 하기 때문에 그에 대한 권한 정책을 생성 하는 작업입니다.

조금 자세히 설명드리면 쿠버네티스는 OIDC(OpenID Connect)를 통해 인증을 할 수 있도록 설계되어있습니다. OIDC 기술은 IDP(Idetytity Providers)에 의해 제공되며 사용자가 어떤 행위를 할 수 있는지를 인증해주게 됩니다.

AWS EKS 또한 OIDC를 지원하하는데, AWS IAM의 IDP에서 OIDC를 생성하여 사용할 수 있습니다.

아래의 json형식의 policy를 AllowExternalDNSUpdates 라는 이름으로 으로 생성하겠습니다.
(aws cli를 사용 하며 aws cli설치 및 aws configure 설정은 생략하였습니다.)

cat > AllowExternalDNSUpdates.json << EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "route53:ChangeResourceRecordSets"
      ],
      "Resource": [
        "arn:aws:route53:::hostedzone/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "route53:ListHostedZones",
        "route53:ListResourceRecordSets"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}
EOF

aws iam create-policy --policy-name AllowExternalDNSUpdates --policy-document file://AllowExternalDNSUpdates.json

Create IAM Role

쿠버네티스 문에는 kiam 또는 kube2iam 으로 생성했을 경우와 1.13버전 이상의 EKS Cluster의 경우가 있는데 저희는 후자인 1.13버전 이상의 EKS Cluster의 경우만 보도록 하겠습니다.

(eksctl을 사용하며 설치방법은 생략하겠습니다.)

service_account_name : ExternalDNS service account명 입력 (=external-dns)

service_account_namespace : ExternalDNS namespace명 입력 (=external-dns)

cluster_name : EKS클러스터명

IAM_policy_ARN : 위에서 생성한 policy arn (예시: arn:aws:iam::AWS_ACCOUNT_ID:policy/AllowExternalDNSUpdates)

eksctl create iamserviceaccount \
    --name <service_account_name> \
    --namespace <service_account_namespace> \
    --cluster <cluster_name> \
    --attach-policy-arn <IAM_policy_ARN> \
    --approve \
    --override-existing-serviceaccounts

External DNS 배포 (RBAC을 사용하는 경우)

apiVersion: v1
kind: ServiceAccount
metadata:
  name: external-dns
  # If you're using Amazon EKS with IAM Roles for Service Accounts, specify the following annotation.
  # Otherwise, you may safely omit it.
  annotations:
    # Substitute your account ID and IAM service role name below.
    eks.amazonaws.com/role-arn: arn:aws:iam::ACCOUNT-ID:role/IAM-SERVICE-ROLE-NAME
---
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: external-dns ## 이부분 공식문서와 다릅니다. 공식문서는 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.7.6
        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

여기서 몇가지 변수값에 대해 설명 드리겠습니다.

eks.amazonaws.com/role-arn : 위에서 생성한 IAM Role의 arn
domain-filter : Route53에 생성되어있는 hostzone 명
policy : Route53을 제어하는 정책 설정

  • upsert-only : 레코드셋 생성,업데이트 (삭제 불가능)
  • sync : 레코듯셋 생성,업데이트,삭제
  • create-only: 레코드셋 생성 (삭제, 업데이트 불가능)
    txt-owner-id : Route53 에 hostzone을 생성하면 Z로 시작하는 ID 할당되며 해당 ID를 입력

여기서 policy 타입 설정이 중요합니다. 도메인은 실제 고객이 서비스를 사용하기 위한 최상단의 접점이기 때문에 엄격하게 관리되어야 합니다. 예제에서도 upsert-only 로 되어있듯이 삭제는 관리자가 직접 눈으로 보고 삭제할 것을 권장 합니다.

ExternalDNS 동작확인 예제

external-dns.alpha.kubernetes.io/hostname 부분은 실제 테스트할 도메인으로 변경

apiVersion: v1
kind: Service
metadata:
  name: nginx
  annotations:
    external-dns.alpha.kubernetes.io/hostname: test.kimdragon50.ml
spec:
  type: LoadBalancer
  ports:
  - port: 80
    name: http
    targetPort: 80
  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

externaldns 로그 확인하여 실제 레코드 생성되는지 확인

kubectl logs -f external-dns-75c947bf69-v8qdc -n external-dns
반응형