대표적인 서비스들의 IP 는 모두 부하 분산을 위해 발급된 가상 IP 이다. 파드의 IP를 직접 노출하는것이 아니라 가상의 IP를 통해 여러 파드에 로드밸런싱 하는 것이다.

서비스 종류 IP 엔드포인트의 역할
ClusterIP 쿠버네티스 클러스터 내부에서만 통신이 가능한 가상 IP
ClusterIP - ExternalIPs 지정한 쿠버네티스 노드의 IP(들)
NodePort 모든 쿠버네티스 노드의 IP(들)
LoadBalancer 클러스터 외부 로드 밸런서의 가상 IP

 

반면, 헤드리스(Headless) 서비스는 목적지 파드의 IP 주소를 직접 반환하는 서비스이다. DNS 라운드 로빈 방식을 사용한 엔드포인트를 제공한다. 클러스터 내부 DNS에서 목적지 파드의 IP 주소를 반환하는 것이다.

 

sample-headless.default.svc.cluster.local 도메인으로 요청 -> 클러스터 내부 DNS 에서 라운드 로빈 방식으로 특정 파드의 IP 를 매핑

 

스테이트풀셋이 헤드리스 서비스를 사용하여 제공되는 경우에 파드명으로 IP 주소를 디스커버리할 수 있다. 예를 들어 sample-statefulset-headless-0 스테이트풀셋 파드의 IP 로 호출하고 싶은 경우

sample-statefulset-headless-0.sample-headless.default.svc.cluster.local 도메인으로 호출하면 "sample-statefulset-headless-0" 파드명으로 특정 파드를 호출할 수 있는 것이다.(매니페스트는 아래에서 다룸)

 

1. 생성

아래와 같이 spec.type: ClusterIP 와 spec.clusterIP: None 을 지정하여 생성한다.

apiVersion: v1
kind: Service
metadata:
  name: sample-headless
spec:
  type: ClusterIP
  clusterIP: None
  ports:
    - name: "http-port"
      protocol: "TCP"
      port: 80
      targetPort: 80
  selector:
    app: sample-app

 

이렇게만 서비스를 생성하면 DNS 라운드 로빈 방식으로 서비스 디스커버리된다. 이 서비스를 통해 스테이트풀셋을 파드명으로 질의 가능하도록 구성하려면, 아래와 같이 스테이트풀셋 매니페스트의 spec.serviceName 에 사용할 헤드리스 서비스명을 지정하면 된다.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: sample-statefulset-headless
spec:
  serviceName: sample-headless
  replicas: 3
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
        - name: nginx-container
          image: amsy810/echo-nginx:v2.0

여기서는 volumeClaimTemplates 를 지정하지 않아서 PV, PVC 가 생성되지 않는데, 자세한 스테이트풀셋 구성 방법은 스테이트풀셋 포스트를 참고하기 바란다.

 

2. 헤드리스 서비스 질의해보기

아래의 커맨드로 FQDN 으로 클러스터 내부 DNS에 질의해보면 ClusterIP 의 IP 주소가 아닌, 여러 파드의 IP 주소가 반환되는 것을 볼 수 있다. 따라서 클라이언트에서는 DNS 캐시에 주의하여야 한다.

# 스테이트풀셋으로 관리되는 파드들의 IP 주소 확인
$ kubectl get pods -o wide
NAME                            READY   STATUS    RESTARTS   AGE   IP             NODE              NOMINATED NODE   READINESS GATES
sample-statefulset-headless-0   1/1     Running   0          13m   10.244.1.179   desktop-worker    <none>           <none>
sample-statefulset-headless-1   1/1     Running   0          13m   10.244.1.180   desktop-worker    <none>           <none>
sample-statefulset-headless-2   1/1     Running   0          13m   10.244.2.119   desktop-worker2   <none>           <none>

# 클러스터 내부에서 FQDN 질의
$ kubectl run --image=amsy810/tools:v2.0 --restart=Never --rm -i testpod --command -- dig sample-headless.default.svc.cluster.local
...
;; QUESTION SECTION:
;sample-headless.default.svc.cluster.local. IN A

;; ANSWER SECTION:
sample-headless.default.svc.cluster.local. 30 IN A 10.244.1.179
sample-headless.default.svc.cluster.local. 30 IN A 10.244.2.119
sample-headless.default.svc.cluster.local. 30 IN A 10.244.1.180
...
pod "testpod" deleted

 

3. 스테이트풀셋 파드명으로 헤드리스 서비스 질의해보기

위에서 생성한 스테이트풀셋의 경우는 spec.serviceName 으로 헤드리스 서비스를 지정했다. 이렇게 서비스로 노출된 파드는 파드명을 FQDN 에 포함하여 다음 규칙으로 DNS 에 질의할 수 있게 된다.

 

<파드명>.<서비스명>.<네임스페이스명>.svc.cluster.local

 

아래처럼 질의해보면 특정 파드의 IP 로 해석되는 것을 볼 수 있다.

# <파드명>.<서비스명>.<네임스페이스명>.svc.cluster.local 로 질의
$ kubectl run --image=amsy810/tools:v2.0 --restart=Never --rm -i testpod --command -- dig sample-statefulset-headless-0.sample-headless.default.svc.cluster.local
;; QUESTION SECTION:
;sample-statefulset-headless-0.sample-headless.default.svc.cluster.local. IN A

;; ANSWER SECTION:
sample-statefulset-headless-0.sample-headless.default.svc.cluster.local. 30 IN A 10.244.1.179
...
pod "testpod" deleted

 

4. 스테이트풀셋 외의 리소스 hostname 으로 도메인 해석하기

스테이트풀셋으로 관리되지 않는 파드의 경우에도 Pod 의 매니페스트 설정을 통해 파드단위로 질의(이름해석)할 수는 있긴 하다. 다음과 같이 Pod 의 spec.hostname, spec.subdomain 을 지정하되, subdomain 에는 헤드리스 서비스(ClusterIP: None)의 이름을 지정한다.

---
apiVersion: v1
kind: Pod
metadata:
  name: subdomain-pod
  labels:
    app: sample-app
spec:
  hostname: sample-hostname
  subdomain: sample-subdomain # 사용할 헤드리스 Service 의 이름을 설정
  containers:
    - name: nginx-container
      image: amsy810/tools:v2.0
---
apiVersion: v1
kind: Service
metadata:
  name: sample-subdomain
spec:
  type: ClusterIP
  clusterIP: None
  ports: []
  selector:
    app: sample-app

 

항목  
spec.hostname 파드의 host명(임의)
spec.subdomain 파드를 노출하고자 하는 헤드리스 서비스명

 

이렇게 설정하고 나면 아래와 같은 규칙으로 특정 파드에 질의할 수 있다.

 

<hostname>.<서비스명>.<네임스페이스명>.svc.cluster.local

 

하지만, 일반적으로 파드는 deployment 를 통해서 관리하게 되는데, 디플로이먼트의 매니페스트에서는 구조상 여러 파드에 각각의 hostname 을 설정할 수 없다. 이렇게 hostname 이 같게 되면 하나의 A 레코드만 반환되기 때문에 개별 파드명으로 이름 해석이 불가능하다. 쿠버네티스에서는 일반적인 파드 각각에 대해서 의식하지 않고도 서비스를 통해 사용할 수 있게 구성하도록 권장하고 있고, 추후 확장성이나 관리용이성을 위해서라도 파드명으로 이름 해석을 사용하는 것은 최대한 지양하여야 한다.

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,