Service 를 만들면 클러스터 DNS 에 이름이 등록된다. 파드 사이 통신에는 IP 대신 이 이름을 쓴다. 파드 IP 는 재생성될 때마다 바뀌고 Service 의 ClusterIP 도 서비스를 다시 만들면 바뀌지만, 이름은 그대로이기 때문이다.
| 대상 | 이름 |
|---|---|
| Service | <서비스>.<네임스페이스>.svc.cluster.local |
| 헤드리스 Service 의 파드 | <파드>.<서비스>.<네임스페이스>.svc.cluster.local |
| 파드(기본) | <IP를-대시로>.<네임스페이스>.pod.cluster.local |
같은 네임스페이스 안에서는 서비스 이름만 써도 된다. 파드의 /etc/resolv.conf 에 search <네임스페이스>.svc.cluster.local svc.cluster.local cluster.local 가 들어 있어 짧은 이름이 확장되기 때문이다. 다른 네임스페이스를 부를 때는 <서비스>.<네임스페이스> 까지 적는다.
env:
- name: BACKEND_URL
value: "http://backend-service:8080"
- name: DB_HOST
value: "postgresql.databases"
cluster.local 은 클러스터 도메인 기본값이고 설치할 때 바꿀 수 있으므로, 애플리케이션 설정에 전체 FQDN 을 박기보다 짧은 이름을 쓰는 편이 이식성이 좋다.
StatefulSet 은 헤드리스 서비스(clusterIP: None)와 함께 쓸 때 파드마다 고정된 이름이 생긴다. 카프카·주키퍼처럼 구성원끼리 서로를 지목해야 하는 제품이 이 이름을 쓴다.
파드보다 먼저 만들어진 서비스는 BACKEND_SERVICE_HOST · BACKEND_SERVICE_PORT 같은 환경 변수로도 주입된다. 도커 링크 시절의 호환 기능이라 제약이 크다. 파드보다 나중에 만든 서비스는 들어오지 않고, 값이 IP 라 서비스를 다시 만들면 낡은 값이 남는다. DNS 를 쓴다.
서비스 이름에 하이픈이 있으면 환경 변수 이름은 밑줄로 바뀌므로 이름 규칙도 헷갈린다. 이 기능이 아예 없어야 한다면 파드 스펙에 enableServiceLinks: false 를 준다.
내부 이름과 외부로 공개된 호스트를 나눠서 본다.
# 내부 서비스 FQDN
kubectl get svc -A -o jsonpath='{range .items[*]}{.metadata.name}.{.metadata.namespace}.svc.cluster.local{"\n"}{end}'
# Ingress 로 공개된 호스트
kubectl get ingress -A -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name} {.spec.rules[*].host}{"\n"}{end}'
임시 파드에서 조회해 본다.
kubectl run -it --rm dnstest --image=busybox:1.36 --restart=Never -- \
nslookup backend-service.default.svc.cluster.local
이름은 풀리는데 연결이 안 되면 DNS 가 아니라 엔드포인트 문제다. 서비스의 셀렉터와 파드 라벨이 어긋나면 엔드포인트가 비어 있고, 이때 연결은 거부된다.
kubectl get endpoints backend-service
kubectl get pod --show-labels
이름 자체가 풀리지 않으면 CoreDNS 를 본다.
kubectl -n kube-system get pod -l k8s-app=kube-dns
kubectl -n kube-system logs -l k8s-app=kube-dns --tail=50