본문으로 바로가기
반응형

Intro

오늘은 EKS의 CoreDNS에 대해서 이야기 해보고자 합니다. CoreDNS란 무엇이고 EKS에서는 CoreDNS가 어떤 방식으로 스케줄링 되는지 CoreDNS를 사용해서 pod와 pod간 통신은 어떻게 이루어지는지 더 나아가 Node Instance에서는 어떤 포트를 허용해야하는지 설명 드리도록 하겠습니다.

CoreDNS란?

CoreDNS는 쿠버네티스 클러스터의 DNS역할을 수행할 수 있는, 확장 가능한 DNS서버 입니다. coreDNS를 사용하려면 pod가 service와 연결이 되어있어야 하며, servicename.namespace.svc.cluster.local 형태로 서비스 호출을 할 수 있습니다. 쿠버네티스와 동일하게 CoreDNS프로젝트도 CNCF에서 관리합니다. 현재 CoreDNS는 Graduated단계로 실제 프로덕션 환경에서 충분히 사용할 수 있는 솔루션 입니다.

쿠버네티스의 초창기 DNS는 쿠버네티스 버전 1.10 이전에 kube-dns를 사용했었으며 쿠버네티스 1.13 이상의 버전에서는 CoreDNS가 기본적으로 사용됩니다.

EKS에서 CoreDNS는?

다들 아시는 것처럼 EKS는 쿠버네티스 클러스터를 제공하며 기본적으로 쿠버네티스를 사용 하기 위한 플러그인 및 어플리케이션이 설치가 됩니다.

EKS에서는 쿠버네티스 버전 1.20 기준으로 VPC CNI를 위한 aws-node 와 쿠버네티스 통신을 위한 kube-proxy 그리고 오늘 주인공인 coredns 1.83버전이 기본적으로 kube-system 이라는 namespace에 2개의 pod로 올라가 있는 것을 확인할 수 있습니다.deployment이름은 coredns 이며 service의 이름은 kube-dns 입니다.

EKS에서 coredns의 스케줄링 (eks coredns yaml)

EKS에서 자동으로 설치 해주는 coredns의 스케줄링 정책을 보면 아래와 같습니다.

spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: beta.kubernetes.io/os
                operator: In
                values:
                - linux
              - key: beta.kubernetes.io/arch
                operator: In
                values:
                - amd64
                - arm64
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: k8s-app
                  operator: In
                  values:
                  - kube-dns
              topologyKey: kubernetes.io/hostname
            weight: 100

이를 해석해보면 nodeAffinity 는 노드의 레이블을 기준으로 파드를 매칭되는 노드에 스케줄링하는 것을 말하고 requiredDuringSchedulingIgnoredDuringExecution 는 노드에 스케줄 되도록 반드시 규칙을 만족해야하는 것을 말합니다. 아래 matchExpressions 의 조건을 보면 beta.kubernetes.io/os=linux이고 beta.kubernetes.io/arch=amd64,arm64 일 경우 coredns를 생성 하게 됩니다.

이 두개의 레이블 값은 모든 노드에 붙어있는 레이블로 사실상 어떤 노드에든 생성될 수 있음을 뜻합니다. 이 부분은 노드간 통신 제한을 할때 큰 걸림돌이 될 수 있는 포인트 이므로 반드시 이 스케줄링 정책에 대해 알고 있어야 합니다.

이어서 podAntiAffinity 는 노드의 레이블 기반이 아닌, 노드에서 이미 실행중인 파드 레이블을 기반으로 스케줄링을 하게 됩니다. preferredDuringSchedulingIgnoredDuringExecution 규칙을 가져가므로 반드시 규칙을 만족하지 않아도되는 유연함을 가져 갑니다. pod의 Anti규칙이므로 있으므로 예를들어 현재 coreDNS 파드의 레이블이 k8s-app=kube-dns 이며 A라는 node에 이미 생성이 되어있다면 A노드에는 다른 pod가 스케줄링 되지 않는다는 규칙입니다.

AWS에서 기본적으로 이중화를 고려해서 coredns pod도 2개로 설치가 되도록 deployment를 구성해놓았으며, 왠만하면 같은 노드에서 실행되지 않도록 설정을 해놓은 것입니다. 단, 노드가 1개일 경우 1개의 노드에 모두 생성이 됩니다.

EKS 노드간 통신 제한을 하고 싶어요

그런데 여기서 이슈가 발생합니다. 노드간 통신을 제한해야 할 경우 즉, 노드의 보안그룹(security group)을 제한해야하는 경우 coreDNS는 어떤 노드에 생성될지 모르기 때문에 특정 포트와 특정 노드로 제한할수가 없습니다. 그렇다면 어떻게 해야할까요?

모든 노드 끼리는 coredns에서 사용하는 DNS포트 UDP 53번을 허용하도록 구성하는 것도 방법이 될 수 있습니다만.

가장 좋은 방법은 DNS용 노드를 생성하여 nodeAffinity 를 해당 노드에 생성되도록 설정을 변경하는 것입니다. 그런데 coredns만을 위해 노드를 따로 구성하는 것은 자원과 비용 효율적이지 않기 때문에 관리용으로 용도를 구별하여 관리용노드를 구성하는 것이 좋습니다.

이 관리용 노드에는 실제 서비스에 사용되지 않는 배포용 솔루션 argocd라던지, 모니터링 솔루션 prometheus와 grafana라던지 쿠버네티스 관리용으로 사용하는 것들을 위해 사용하면 보다 자원과 비용 효율적인 아키텍처가 될 수 있습니다.

위 그림을 보면 node01을 먼저 생성하고 node02, node03을 설치하니 node01에 coredns 2개가 모두 올라가있는 모습입니다.

3개의 노드에 테스트용 nginx를 설치하였고 service를 80으로 구성하여 각 노드에 있는 pod간 coredns의 통신이 잘 되는지 테스트 한 구성이며, 통신을 위해서 coredns가 올라가 있는 node01과 UDP 53번 통신이 되도록 보안그룹(security group)을 설정해야하며, service port인 80포트의 허용이 필요합니다.

특정 노드에 coredns 스케줄링은 어떻게 설정 해야하나요? (eks coredns yaml 수정)

coredns의 스케줄링은 coredns의 deployment를 아래와 같이 수정하면 되고, 레이블 정보(nodegroup-type=manage-node)는 커스텀하게 변경하여 사용하시면 됩니다.

kubectl edit deploy coredns -n kube-system

spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: nodegroup-type
                operator: In
                values:
                - manage-node
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: k8s-app
                  operator: In
                  values:
                  - kube-dns
              topologyKey: kubernetes.io/hostname
            weight: 100

이상 EKS의 coredns가 무엇인지와 노드에 어떻게 스케줄링 되는지 그리고 노드그룹간 통신을 위해 어떻게 구성을 해야하는지 까지 알아보았습니다.

이해가 안되거나 문의사항이 있으시면 댓글 또는 메일로 최대한 답변 드리겠습니다.

감사합니다.

반응형