ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 쿠버네티스 DNS(kubernetes dns)
    Kubernetes 2018. 9. 17. 09:00
    쿠버네티스에서는 클러스터 내부에서만 사용가능한 DNS를 설정해 놓고 사용할 수 있습니다. 그래서 포드간 통신을 할때나 IP가 아닌 도메인을 설정해 두고 사용할 수 있습니다. 그렇게해서 한 클러스터에서 사용하던 yaml파일에서 포드간 통신을 도메인으로 설정해 둔다면 그걸 별다른 수정 없기 그대로 다른 클러스터로 가져가서 사용하는 것도 가능합니다. ip로 통신하도록 되어 있다면 한곳에서 세팅해놨던 yaml파일을 다른곳으로 옮겨 가져가서 사용하려고 할때 그 클러스터에서 사용하는 ip 대역이 다른 것이라면 그대로 사용할 수가 없게 됩니다. 이럴때 설정이 도메인을 사용하도록 되어 있다면 별다른 수정없이 그대로 사용할 수가 있습니다.
    그 뿐만 아니라 일부의 경우에는 서비스디스커버리(service discovery)용도로 사용할 수도 있습니다. 전문적인 서비스디스커버리를 사용하려면 dns가 아니라 다른 솔루션들을 사용해야 하겠지만 간단한 경우라면 dns를 이용해서 할 수도 있습니다. 특정 포드들에 접근할때 도메인을 통해서 접근하도록 설정되어 있다면 포드에 문제가 생겨서 재생성되거나 배포때문에 재생성될때 IP가 변경되더라도 자동으로 도메인에 변경된 포드의 IP가 등록되기 때문에 자연스레 새로 시작된 포드 쪽으로 연결하는 것이 가능합니다.

    클러스터내에서 도메인 사용해보기
    쿠버네티스에서 사용하는 내부 도메인은 서비스와 포드에 대해서 사용할 수 있고 일정한 패턴을 가지고 있습니다. 
    특정 서비스에 접근하는 도메인은 다음처럼 구성됩니다. aname 이라는 네임스페이스에 속한 bservice 가 있다고 했을때 이 서비스에 접근하는 도메인은 bservice.aname.svc.cluster.local입니다. bservice.aname 순으로 서비스와 네임스페이스를 연결한 다음에 마지막에 svc.cluster.local을 붙이면 됩니다. 
    특정 포드에 접근하는 도메인은 다음처럼 구성됩니다. default 네임스페이스에 속한 cpod(10.10.10.10)라는 이름의 포드에 대한 도메인은 다음처럼 구성됩니다. 10-10-10-10.default.pod.cluster.local cpod의 IP인 10.10.10.10에서 .을 -로 변경해서 사용하고 네임스페이스 이름인 default와 연결한 다음 뒤에 pod.cluster.local을 붙여주면 됩니다. 하지만 이렇게 하면 포드의 ip를 그대로 사용해야 하니까 도메인 네임을 사용하는 장점이 많이 사라지게 됩니다. 그래서 다른 방법을 사용할 수도 있습니다. 포드를 실행할때 spec에 hostname과 subdomain을 지정해서 사용할 수 있습니다. 다음처럼 예제 yaml을 보도록 하겠습니다. spec에 hostname과 subdomain을 지정했습니다.
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: kubernetes-simple-app
      labels:
        app: kubernetes-simple-app
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: kubernetes-simple-app
      template:
        metadata:
          labels:
            app: kubernetes-simple-app
        spec:
          hostname: appname
          subdomain: default-subdomain
          containers:
          - name: kubernetes-simple-app
            image: arisu1000/simple-container-app:latest
            ports:
            - containerPort: 8080

    이런경우 이 포드에 접근할수 있는 도메인은 appname.default-subdomain.default.svc.cluster.local으로 생성됩니다. hostname인 appname과 subdomain인 default-subdomain을 앞에 사용하고 네임스페이스인 default를 붙여준 다음에 .svc.cluster.local을 붙여줍니다. 여기서 눈여겨봐야할 점은 마지막에 붙인 .svc.cluster.local이 pod가 아니라 svc로 시작한다는 점입니다. 
    실제로 이 도메인 이름을 이용해서 접근이 가능한지 확인하기 위해서는 위의 예제를 실행한 후 다음처럼 확인해 볼 수 있습니다.
    $ kubectl apply -f dns-deployment.yaml
    $ kubectl get pods -o wide
    NAME                                     READY     STATUS    RESTARTS   AGE       IP           NODE
    kubernetes-simple-app-67894b6df5-2rc5f   1/1       Running   0          1m        10.1.0.162   docker-for-desktop
    $ kubectl exec kubernetes-simple-app-67894b6df5-2rc5f nslookup appname.default-subdomain.default.svc.cluster.local
    nslookup: can't resolve '(null)': Name does not resolve

    Name:      appname.default-subdomain.default.svc.cluster.local
    Address 1: 10.1.0.162 appname.default-subdomain.default.svc.cluster.local

    kubectl apply로 앱을 실행한 다음에 kubectl get pods로 포드가 실행됐는지와 이 포드의 IP를 확인해 봅니다. 그런 다음 kubectl exec 명령으로 포드내에서 nslookup 명령으로 설정한 appname.default-subdomain.default.svc.cluster.local 도메인에 대한 IP를 확인할 수 있는지 보면 됩니다. 여기서는 포드의 IP인 10.1.0.162 이 정상적으로 확인되는걸 마지막에 확인할 수 있습니다.


    DNS 구조
    dns역할을 하는 kube-dns역시 클러스터내에서 포드로 실행되고 있습니다. 
    포드내에서 DNS에 질의를 할때 어떤 순서로 할것인지 개별 포드마다 지정해 줄 수 있습니다. 포드의 spec에 dnsPolicy를 이용해서 지정할 수 있습니다. 사용가능한 옵션은 다음 4가지 입니다.
    • Default : dns 설정을 포드가 실행중인 노드의 설정을 가져와서 사용합니다.
    • ClusterFirst : cluster.local같은 미리 지정된 클러스터내부 도메인과 일치하지 않는 “www.example.com” 같은 도메인의 경우에는 클러스터 외부 DNS인 upstream DNS에 질의합니다.
    • ClusterFirstWithHostNet : 포드를 hostNetwork옵션으로 실행할때 반드시 사용해야 하는 옵션입니다.
    • None : 포드가 쿠버네티스 클러스터 내부의 DNS 설정을 무시하도록 하는 설정입니다. 이 경우에는 포드의 spec에 dnsConfig으로 별도 DNS설정을 해줘야 합니다.

    다른 포드들에서 도메인 네임을 조회하면 kube-dns쪽으로 질의를해서 해당 도메인의 IP를 확인합니다. 이 때 kube-dns 포드 내부의 DNS 캐시인 dnsmasq를 통해서 질의가 이뤄지게 됩니다. dnsmasq는 kube-dns를 질의하고 거기에서 원하는 결과를 찾을 수 없으면 custom DNS 쪽으로 질의를 하고 거기에도 없으면 다시 upstream DNS쪽으로 질의를 하도록 되어 있습니다.



    DNS 직접 설정하기
    포드내의 dns설정을 사용자가 직접하는 것도 가능합니다. spec에 dnsConfig를 설정해 주면 됩니다. dnsConfig설정은 dnsPolicy와 함께 쓸수도 있습니다. 앞에도 있지만 dnsPolicy가 none일때는 dnsConfig가 꼭 있어야 합니다.
    dnsConfig에는 다음 3가지 속성들을 설정할 수 있습니다.
    • nameservers : 포드에서 사용할 dns의 ip들입니다. dnsPolicy가 None일때는 이 값을 필수로 1개이상 넣어줘야 합니다. 최대 3개까지 입력할 수 있습니다.
    • searches : DNS를 검색할때 사용하는 기본 도메인 이름입니다. 여기에 svc.cluster.local라고 명시해 두면 a.b.svc.cluster.local이라는 도메인을 사용할때 a.b까지만 입력해도 svc.cluster.local 를 포함해서 검색을 해 줍니다. 최대 6개까지 사용할 수 있습니다. 
    • options: name과 value 를 이용해서 원하는 값을 설정할 수 있습니다. name은 필수로 있어야 하고 value는 없어도 되는 값입니다.
    dnsConfig에 설정된 값은 포드의 /etc/resolv.conf에 추가됩니다. 
    다음 pod 설정을 dns-test.yaml로 저장한 다음에 적용하고 포드내부의 resolv.conf파일 내용을 확인하면 설정이 어떻게 적용되는지 확인할 수 있습니다.
    기본설정외에 dnsConfig 로 추가할 설정이 들어가 있는걸 확인할 수 있습니다.
    dns-test.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      namespace: default
      name: dns-test
    spec:
      containers:
        - name: dns-test
          image: arisu1000/simple-container-app:latest
      dnsPolicy: ClusterFirst
      dnsConfig:
        nameservers:
          - 8.8.8.8
        searches:
          - default.svc.cluster.local
          - example.com
        options:
          - name: name01
            value: value01
          - name: name02

    $ kubectl apply -f addon/dnsconfig-pod.yaml
    pod "dns-test" created
    $ kubectl exec dns-test cat /etc/resolv.conf
    nameserver 10.96.0.10
    nameserver 8.8.8.8
    search default.svc.cluster.local svc.cluster.local cluster.local example.com
    options ndots:5 name01:value01 name02


    참조


    댓글 3

    • 프로필사진

      안녕하세요, 자세한 설명 항상 잘 보고 있습니다.
      Pod 도메인 관련해서 여쭤볼 게 있어서 문의 남깁니다.

      Deployment 에서 replicas 를 3으로 정의할 경우 Pod가 3개가 생성되는 것이고
      Service 에서 해당 Pod 를 연결할때 replicas 에 대해 랜덤으로 로드벨런싱 된다고 알고 있는데요.

      글에서 말씀하신 Pod 도메인을 사용할 경우에도 로드벨런싱이 되나요?
      아니면 중간에 Service둬야 할까요?

      2020.03.17 10:34 신고
      • 프로필사진

        안녕하세요.
        pod 도메인을 사용할경우 해당 pod로 직접 트래픽이 가는거라서 다른 pod로 로드밸런싱은 안되요.
        로드밸런싱을 원하시는거면 중간에 Service를 둬야 해요.

        2020.03.17 19:38 신고
    • 프로필사진

      네 답변 감사합니다 :)

      2020.03.19 11:42 신고
Designed by Tistory.