먼저, 클러스터 내부 DNS 가 무엇인지 알아야 한다.
클러스터 내부 DNS 는 쿠버네티스 파드에서 질의한 도메인이 최우선적으로 바라보는 쿠버네티스 DNS 이다. 도메인이 클러스터 내부 도메인 규칙을 준수한다면 외부 DNS 에 질의하지 않고 클러스터 내부에서 도메인 해석을 끝낸다. 클러스터 내부 DNS 는 kube-system 네임스페이스에 속한 kube-dns 라는 서비스가 그 실체이다.(ClusterIP 타입)
아래의 커맨드로 조회할 수 있다.
$ kubectl get services -n kube-system
# kube-dns 서비스의 CLUSTER-IP 확인. 이 주소가 클러스터 내부 DNS 서버 주소이다.
쿠버네티스에서 서비스 디스커버리란, 특정 서비스명으로부터 그 서비스의 엔드포인트 정보를 판별하는 것이다. 특정 조건의 대상이 되는 파드를 판별하는 것이라고 생각해도 좋다. 서비스 디스커버리를 수행하는 방법은 크게 아래 세가지가 있다.
- 환경변수를 이용
- DNS A 레코드를 이용
- DNS SRV 레코드를 이용
1. 환경변수를 이용한 서비스 디스커버리
서비스와 연결된 Pod 에 대해 아래 커멘드처럼 env 를 조회하면, kubernetes 에서 관리하는 환경변수가 설정되어 있음을 알 수 있다. 이 환경변수 값들을 가지고 서비스 디스커버리를 수행하는 것이다. 파드 템플릿의 spec.enableServiceLinks: false 로 설정시에는 환경변수 추가가 비활성화된다.(기본값 true)
$ kubectl exec -it sample-deployment-75c768d5fb-2lkwp -- env | grep -i kubernetes
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
2. DNS A 레코드를 이용한 서비스 디스커버리
쿠버네티스에서 서비스 엔드포인트에 접속하기 위해서는 당연히 서비스에 할당된 IP 주소를 사용할 수 있지만, 클러스터 내부 DNS 에 자동 등록된 IP-DNS 레코드명을 사용하는 것이 관리 측면에서 바람직하다. IP 주소는 서비스를 생성할 때 마다 변경되기 때문에 미리 알 수 없기 때문이다. DNS명으로 주소를 사용하면 서비스 재생성에 따른 IP 주소 변경에 신경 쓸 필요가 없어진다.
ClusterIP 를 생성하면, 서비스의 name 값이 자동으로 DNS명으로 등록된다. 아래의 커맨드로 ClusterIP 서비스로 호출을 해보면 IP로 직접 호출하는것과 서비스 name 으로 호출하는 것이 동일한 것을 알 수 있다.
# 서비스의 IP로 호출
$ kubectl run --image=amsy810/tools:v2.0 --restart=Never --rm -i testpod --command -- curl -s http://10.96.82.60:8080
Host=10.96.82.60 Path=/ From=sample-deployment-75c768d5fb-g5vkv ClientIP=10.244.1.135 XFF=
pod "testpod" deleted
# 서비스의 name 으로 호출(DNS명으로 호출)
$ kubectl run --image=amsy810/tools:v2.0 --restart=Never --rm -i testpod --command -- curl -s http://sample-clusterip:8080
Host=sample-clusterip Path=/ From=sample-deployment-75c768d5fb-9qdjm ClientIP=10.244.1.134 XFF=
pod "testpod" deleted
실제로 등록된 FQDN 형식은 "{서비스명}.{네임스페이스명}.svc.cluster.local" 이다. 이를 확인하려면 클러스터 내의 컨테이너에서 dig(Domain Information Groper) 명령어를 사용해보면 된다. 아래 커맨드를 실행하여 클러스터 내부 DNS 에 등록된 레코드를 확인해보자. sample-clusterip.default.svc.cluster.local. 30 IN A 10.96.82.60 레코드가 등록된 것을 알 수 있다.
# dig 명령어로 DNS 정보 확인
$ kubectl run --image=amsy810/tools:v2.0 --restart=Never --rm -i testpod --command -- dig sample-clusterip.default.svc.cluster.local
If you don't see a command prompt, try pressing enter.
...
;; QUESTION SECTION:
;sample-clusterip.default.svc.cluster.local. IN A
;; ANSWER SECTION:
sample-clusterip.default.svc.cluster.local. 30 IN A 10.96.82.60
...
pod "testpod" deleted
QUESTION SECTION 에 출력된
;sample-clusterip.default.svc.cluster.local. IN A
내용을 해석하면 아래와 같다.
- ; → dig에서 질의한 도메인 이름을 표시할 때 붙는 기호
- sample-clusterip.default.svc.cluster.local. → 실제 DNS 서버에 요청한 도메인 전체 이름(FQDN)
- IN → 인터넷 클래스
- A → IPv4 주소를 요청했다는 뜻
ANSWER SECTION 에 출력된
sample-clusterip.default.svc.cluster.local. 30 IN A 10.96.82.60
내용을 해석하면 아래와 같다.
- sample-clusterip.default.svc.cluster.local. → 응답한 도메인 이름
- 30 → TTL(Time To Live): DNS 결과를 캐시해둘 수 있는 시간(초 단위)
- IN → 인터넷 클래스
- A → IPv4 주소를 요청했다는 뜻
- 10.96.82.60 → 해당 서비스의 ClusterIP 주소
즉, 쿠버네티스 DNS(CoreDNS)가 sample-clusterip라는 Service를 찾아서, 그 서비스의 클러스터 내부 IP(10.96.82.60)를 응답했다는 뜻이다.
아래의 커맨드로 컨테이너 내의 DNS 설정파일을 확인하면, ndots:5 와 search: default.svc.cluster.local, svc.cluster.local, cluster.local 값이 명시되어 있다. 즉, 질의된 도메인의 dot 갯수가 5개 미만이면 질의된 도메인의 suffix 로 search 에 명시된 도메인들을 하나씩 붙여 질의해보는 것이다. 모든 질의에 실패하게 되면 최초 질의된 도메인으로 질의하게 된다.
예를 들어, sample-clusterip 도메인으로 질의하면 dot 이 5개 미만이라 FQDN 으로 인식하지 않기 때문에 아래 순서대로 질의에 성공할때까지 질의하게 된다.
- sample-clusterip.default.svc.cluster.local
- sample-clusterip.svc.cluster.local
- sample-clusterip.cluster.local
- sample-clusterip
예를 들어, test1.test2.sample.clusterip.com 도메인으로 질의하면 dot 이 5개 미만이라 마찬가지로 아래 순서대로 성공할때까지 질의함
- test1.test2.sample.clusterip.com.default.svc.cluster.local
- test1.test2.sample.clusterip.com.svc.cluster.local
- test1.test2.sample.clusterip.com.cluster.local
- test1.test2.sample.clusterip.com
$ kubectl run --image=amsy810/tools:v2.0 --restart=Never --rm -i testpod --command -- cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5
pod "testpod" deleted
출력 결과를 보면 알 수 있듯이 default 네임스페이스임을 명시하고 있다. 만약 test 네임스페이스라면 default 부분이 test 로 되어있을 것이다. 같은 네임스페이스에 속한 도메인으로 질의할 때는 네임스페이스를 생략하여도 되지만, 다른 네임스페이스로 질의할 때는 명시해야 하는 것이다.
아래 커맨드를 이용하면 역방향으로 IP -> 도메인명을 질의할 수 있다.
$ kubectl run --image=amsy810/tools:v2.0 --restart=Never --rm -i testpod --command -- dig -x 10.96.82.60
...
;; QUESTION SECTION:
;60.82.96.10.in-addr.arpa. IN PTR
;; ANSWER SECTION:
60.82.96.10.in-addr.arpa. 30 IN PTR sample-clusterip.default.svc.cluster.local.
...
pod "testpod" deleted
3. DNS SRV 레코드를 이용한 서비스 디스커버리
SRV 레코드란 특정 서비스가 어떤 호스트와 포트에서 제공되는지를 나타내는 DNS 레코드이다. 즉, SRV 레코드를 조회하면 특정 서비스가 어떤 포트에서 서비스되고 있는지 알 수 있다. 쿠버네티스에서 자동으로 생성하는 SRV 레코드 규칙은 다음과 같다.(port 명과 protocol 에는 접두어 "_" 가 포함됨)
"_{서비스 포트명}._{프로토콜}.{서비스명}.{네임스페이스명}.svc.cluster.local"
예를 들어 default 네임스페이스에서 아래와 같은 매니페스트로 생성된 서비스는
"_http-port.tcp.sample-clusterip.default.svc.cluster.local" 으로 SRV 레코드가 생성된다.
apiVersion: v1
kind: Service
metadata:
name: sample-clusterip
spec:
type: ClusterIP
ports:
- name: "http-port"
protocol: "TCP"
port: 8080
targetPort: 80
selector:
app: sample-app
아래 커맨드로 컨테이너 내부에서 SRV 레코드를 조회할 수 있다.
$ kubectl run --image=amsy810/tools:v2.0 --restart=Never --rm -i testpod --command -- dig _http-port._tcp.sample-clusterip.default.svc.cluster.local SRV
...
;; QUESTION SECTION:
;_http-port._tcp.sample-clusterip.default.svc.cluster.local. IN SRV
;; ANSWER SECTION:
_http-port._tcp.sample-clusterip.default.svc.cluster.local. 30 IN SRV 0 100 8080 sample-clusterip.default.svc.cluster.local.
;; ADDITIONAL SECTION:
sample-clusterip.default.svc.cluster.local. 30 IN A 10.96.82.60
...
pod "testpod" deleted
ANSWER SECTION 에 출력된
_http-port._tcp.sample-clusterip.default.svc.cluster.local. 30 IN SRV 0 100 8080 sample-clusterip.default.svc.cluster.local.
내용을 해석하면 아래와 같다.
이름 | _http-port._tcp.sample-clusterip.default.svc.cluster.local. | 질의한 서비스 이름 |
TTL | 30 | 30초 동안 캐시 가능 |
클래스 | IN | 인터넷 클래스 |
타입 | SRV | SRV 레코드 |
Priority | 0 | 우선순위 (낮을수록 우선) |
Weight | 100 | 동일 우선순위 내에서의 부하분산 비율 |
Port | 8080 | 서비스가 제공되는 포트 |
Target | sample-clusterip.default.svc.cluster.local. | 실제 트래픽을 전달할 대상 호스트명(서비스의 DNS 이름) |
즉, sample-clusterip.default.svc.cluster.local 서비스의 _http-port라는 HTTP 서비스가 TCP 8080 포트에서 제공되고 있다는 것을 DNS 레코드로부터 해석할 수 있다.
위와 같이 쿠버네티스 클러스터 내부 DNS 의 서비스 디스커버리 방식을 알아보았다. 그렇다면, 클러스터 내부 DNS 가 아닌 클러스터 외부 DNS 를 사용하려면 어떻게 해야 할까?
[Kubernetes] 파드 DNS 설정 에서 다루었는데, 파드 매니페스트의 spec.dnsPolicy: None 를 지정하고 spec.dnsConfig 필드에 외부 DNS 서버를 지정해주면 된다. 이러한 설정을 해주지 않으면 기본적으로 spec.dnsPolicy: ClusterFirst 으로 적용되어 클러스터 내부 DNS 에 우선 질의한다.(단, spec.dnsPolicy: None 지정시에도 searchs, options 설정에 따라 클러스터 내부 DNS 를 우선적으로 질의하도록 설정할 수 있다.) 클러스터 내부 DNS 에는 "*.cluster.local" 레코드가 지정되어 있으므로 이를 서비스 디스커버리에 우선적으로 사용하고, 조건에 부합하지 않는 도메인 질의시에는 외부 DNS 에 다시 질의하게 된다.
DNS 질의 시간을 단축하기 위하여 클러스터 내부 DNS 인 kube-dns 를 사용하기 전에 각 노드에 DNS 캐시 파드를 따로 두고, 이를 우선적으로 사용하는 구조도 있다.(Node Local DNS Cache)
'Kubernetes' 카테고리의 다른 글
[Kubernetes] Multi Port ClusterIP, 포트 이름을 사용한 참조 (0) | 2025.10.12 |
---|---|
[Kubernetes] 클러스터 네트워크 개괄 (0) | 2025.10.12 |
[Kubernetes] 크론잡 (0) | 2025.10.07 |
[Kubernetes] 완료된 잡 정리(ttlSecondsAfterFinished) (0) | 2025.10.06 |
[Kubernetes] 잡 병렬 실행 (0) | 2025.10.04 |