쿠버네티스 서비스 디스커버리 완벽 가이드: CoreDNS 작동 원리부터 트러블슈팅까지
안녕하세요, 인프라 아키텍처를 설계하고 운영하는 동료 개발자 및 엔지니어 여러분. 지난 시간에는 쿠버네티스 서비스가 어떻게 로드 밸런싱을 통해 트래픽을 분산하는지, L4 레벨의 네트워킹 개념을 다루었습니다. 하지만 실제 운영 환경에서 가장 빈번하게 부딪히는 문제는 '주소 찾기'의 문제입니다.
마치 대규모 오피스 빌딩에서 A 부서가 B 부서의 팀장님을 찾아야 하는데, 팀장님의 책상이 오늘 임시로 다른 층으로 옮겨졌다면 어떻게 할까요? IP 주소는 항상 존재하지만, 그 IP가 현재 어떤 서비스의 실제 포트를 가리키는지 아는 것이 바로 **서비스 디스커버리(Service Discovery)**의 핵심입니다.
이번 3편에서는 쿠버네티스 클러스터 내부에서 이 '주소 찾기'가 어떻게 마법처럼 작동하는지, 그 중심축인 CoreDNS의 작동 원리부터 실전 트러블슈팅까지 깊이 있게 파헤쳐 보겠습니다.
서비스 디스커버리가 필요한 이유: 왜 DNS가 필수인가?
우리가 애플리케이션을 개발할 때, 서비스 A가 서비스 B를 호출한다고 가정해 봅시다. 만약 서비스 B의 파드가 10개씩 끊임없이 생성되고 사라진다면, 서비스 A는 매번 변경되는 IP 주소 목록을 하드코딩할 수 없습니다.
이때 DNS(Domain Name System)가 등장합니다. DNS는 복잡한 IP 주소 체계를 사람이 이해하기 쉬운 이름(FQDN: Fully Qualified Domain Name)으로 변환해주는 전 세계의 전화번호부 역할을 합니다. 쿠버네티스 환경에서는 이 DNS 역할을 CoreDNS가 맡아 수행합니다.
쉽게 비유하자면, 서비스 이름(user-api.default.svc.cluster.local)은 이 빌딩의 '부서명'이고, CoreDNS는 이 부서명에 해당하는 '현재 사용 가능한 팀장님의 사무실 위치(IP 주소)'를 실시간으로 알려주는 안내 데스크인 셈입니다.
쿠버네티스 네트워킹의 뼈대: Service와 Endpoint의 역할 이해하기
서비스 디스커버리를 이해하려면, 쿠버네티스 오브젝트 세 가지의 관계를 명확히 알아야 합니다.
- Pod: 실제 애플리케이션이 구동되는 격리된 컨테이너 그룹. IP 주소는 유동적입니다.
- Service: 파드 그룹에 대한 추상적인 논리적 이름을 부여합니다. 이 이름은 파드가 죽고 다시 살아나도 변하지 않는 '접속점' 역할을 합니다.
- Endpoint: 특정 Service에 연결된 실제 파드들의 IP 주소 목록입니다. Service가 이 Endpoint를 참조하여 트래픽을 분산합니다.
🔍 실습으로 보는 핵심 명령어 비교
이 세 가지가 어떻게 연결되는지 kubectl 명령어로 확인해 봅시다.
| 명령어 | 목적 | 출력 정보 | 서비스 디스커버리 관점 |
|---|---|---|---|
kubectl get svc | 서비스의 논리적 이름, 포트, 타입 확인 | ClusterIP (가상 IP) | **'무엇을 찾을지'**에 대한 이름과 가상 주소를 확인합니다. |
kubectl get endpoints <service-name> | 해당 서비스에 연결된 실제 파드 IP 목록 확인 | 실제 파드 IP 주소들 | **'실제로 어디에 붙어 있는지'**에 대한 실시간 주소를 확인합니다. |
핵심 포인트: kubectl get svc에서 보이는 ClusterIP는 실제 파드 IP가 아닙니다. 이는 쿠버네티스 내부의 로드 밸런서가 붙여준 가상의 주소일 뿐이며, 실제 트래픽은 이 IP를 통해 여러 Endpoint로 분산됩니다.
CoreDNS의 작동 원리 심층 분석: 쿼리부터 IP 매핑까지
그렇다면 서비스 이름으로 요청이 들어왔을 때, CoreDNS는 어떤 과정을 거쳐 최종 IP를 반환할까요? 이 과정은 마치 정교한 3단계의 필터링 과정과 같습니다.
[CoreDNS 작동 흐름 다이어그램 (개념적 흐름)]
사용자 요청:
http://user-api.default.svc.cluster.local:8080$\downarrow$ 1. CoreDNS Query: 클러스터 내부의 모든 네임서버가 이 요청을 가로챕니다. $\downarrow$ 2. Service Lookup: CoreDNS는 내부 매핑 규칙에 따라 해당Service Name을 찾아ClusterIP또는A Record를 확인합니다. $\downarrow$ 3. Endpoint Resolution: 최종적으로, CoreDNS는 해당Service가 바라보는 **실제 파드들의 IP 목록(Endpoint)**을 응답합니다.
💡 YAML 비교: ClusterIP와 Headless Service의 차이
이 이해를 돕기 위해, 서비스 정의 YAML에서 가장 중요한 두 가지 모드를 비교해 보겠습니다.
1. 일반 Service (ClusterIP 사용):
apiVersion: v1
kind: Service
metadata:
name: user-service
spec:
selector:
app: user
ports:
- port: 80
targetPort: 8080
type: ClusterIP # <--- 이 타입이 핵심- 동작: CoreDNS는 이
ClusterIP를 반환하고, 쿠버네티스 내부의kube-proxy가 이 가상 IP로 들어오는 트래픽을 자동으로 여러 파드 IP로 분산(Load Balancing)합니다. 사용자는 단일 주소만 기억하면 됩니다.
2. Headless Service (ClusterIP: None 사용):
apiVersion: v1
kind: Service
metadata:
name: user-headless-service
spec:
selector:
app: user
ports:
- port: 80
targetPort: 8080
clusterIP: None # <--- 이 설정이 핵심- 동작:
clusterIP: None으로 설정하면, Service는 로드 밸런싱 계층을 거치지 않고 각 파드의 실제 IP 주소 목록을 DNS 쿼리 결과로 반환합니다. 이는 서비스 간의 직접적인 통신(예: 마이크로서비스 간의 직접적인 API 호출)이 필요할 때 유용합니다.
실전 시나리오 및 트러블슈팅: DNS 해석 실패 대응 전략
운영 중 가장 흔하게 발생하는 문제는 '서비스 이름 해석 실패'입니다. 이는 보통 다음 세 가지 경우에 발생합니다.
- 오타: 개발자가
user-api대신user-apis로 호출했을 때. - 서비스 삭제/재배포: 서비스가 일시적으로 삭제되었거나, 파드가 모두 죽어 Endpoint가 비어있을 때.
- TTL 만료: DNS 레코드가 너무 오래된 정보를 캐싱하고 있을 때.
🛡️ TTL(Time To Live) 설정의 중요성
DNS는 캐싱(Caching)을 통해 속도를 높입니다. 만약 서비스가 A IP에서 B IP로 마이그레이션 되었는데, 클라이언트나 CoreDNS가 이전에 캐싱된 A IP 정보를 오랫동안 붙잡고 있다면, 트래픽은 엉뚱한 곳으로 날아가게 됩니다.
이때 TTL(Time To Live) 값이 중요합니다. TTL을 너무 길게 설정하면 변경 사항 반영이 느려지고, 너무 짧게 설정하면 매번 DNS 쿼리가 발생하여 오버헤드가 커집니다. 운영 환경에서는 서비스의 변경 빈도와 트래픽 패턴을 고려하여 적절한 TTL을 설정하는 것이 필수적입니다.
✍️ 시니어 아키텍트의 실무 팁: 저는 서비스 간 통신을 설계할 때, 단순히
Service이름만 사용하는 것을 지양하고, 가능하면 서비스 메시(Service Mesh) 도입을 전제로 아키텍처를 설계하는 것을 권장합니다. CoreDNS는 훌륭한 기반이지만, 서비스 메시(Istio, Linkerd 등)는 디스커버리, 트래픽 분할(Canary Release), 인증서 관리, 로깅까지 이 모든 것을 단일 계층에서 처리해주기 때문에 운영 복잡도를 획기적으로 줄여줍니다.
결론: 안정적인 서비스 통신을 위한 다음 단계
지금까지 우리는 쿠버네티스 서비스 디스커버리의 근본 원리부터 CoreDNS의 작동 메커니즘까지 깊이 있게 살펴보았습니다. Service와 Endpoint의 관계, 그리고 Headless Service를 이용한 직접 주소 접근까지 이해하셨다면, 이제 클러스터 네트워킹에 대한 이해도가 한 단계 높아지신 겁니다.
다음 단계로 나아가기 위해서는, 서비스 메시를 도입하여 네트워킹 계층을 추상화하고, 정책 기반의 트래픽 제어를 경험해 보시는 것을 추천합니다. 이는 단순한 '주소 찾기'를 넘어 '안전하고 제어 가능한 통신'을 보장하는 차원으로 진화하는 과정입니다.
자주 묻는 질문 (FAQ)
Q1. CoreDNS가 없다면 쿠버네티스 서비스 디스커버리는 어떻게 작동하나요? A1. CoreDNS는 쿠버네티스 클러스터의 기본 DNS 솔루션입니다. 만약 CoreDNS가 없다면, 클러스터는 서비스 이름에 대한 표준화된 네임스페이스 검색 기능을 잃게 되어, 서비스 간 통신이 매우 복잡해지거나 불가능해집니다.
Q2. ClusterIP가 항상 고정된 IP인가요?
A2. ClusterIP는 클러스터 내부에서 서비스에 할당되는 가상 IP 주소입니다. 이 IP 자체는 고정되어 있지만, 이 IP가 실제 트래픽을 받아 처리하는 백엔드 파드들의 IP 주소 목록(Endpoint)은 파드 재시작에 따라 계속 변동합니다.
Q3. 서비스 이름으로 호출하는 것이 가장 안전한가요?
A3. 네, 가장 안전합니다. 서비스 이름(service-name)을 사용하면, 내부 로드 밸런서가 현재 살아있는 모든 파드 IP로 트래픽을 분산해주기 때문에, 특정 파드에 장애가 발생해도 서비스 전체가 중단되지 않습니다.
(본 포스팅은 K8s 네트워킹 심화 학습을 위한 기초 지식 점검용으로 작성되었으며, 실제 운영 시에는 서비스 메시 도입을 적극적으로 검토하시길 바랍니다.)
이 글은 AI 에이전트가 1차 초안을 작성한 뒤, 사람 편집자가 사실관계·출처·톤과 맥락을 검토하여 발행했습니다. 오류나 부정확한 내용이 확인되면 24시간 이내에 정정합니다.
댓글
불러오는 중...