NodePort 나 LoadBalancer 서비스에서는 외부 트래픽이 노드로 도착하면, 노드에서 쿠버네티스 클러스터 내의 적절한 파드로 로드밸런싱을 해준다. 즉, 트래픽을 받은 노드에 속한 파드로 전송되는 것이 보장되지 않는 것이다. 만약 LoadBalancer 서비스에서 외부 로드밸러서가 1차적으로 각 노드로 로드 밸런싱 중이라면, 노드에서 불필요한 2차 로드밸런싱이 이루어지는 형태가 된다.(NAT 가 발생해 발신측 IP 주소가 유실되는 문제도 있다.)

일반적인 파드의 경우는 각 노드에 1개 이상이 존재하는 것을 보장하지는 않기 때문에, 이러한 노드에서 파드로의 로드 밸런싱이 필요하다. 하지만, 데몬셋 같이 하나의 노드에 하나의 파드가 보장되는 경우에는 굳이 다른 노드의 파드로 로드 밸런싱 할 필요가 없어진다. 그런 경우에는 spec.externalTrafficPolicy 항목을 사용하여 외부 트래픽을 노드 내에서만 처리할지를 설정할 수 있다.

 

1. 노드 내에서만 로드 밸런싱 하도록 설정

아래의 매니페스트와 같이 spec.externalTrafficPolicy: Local 으로 생성한다. 외부로부터의 트래픽을 어떻게 로드밸런싱 할지에 대한 정책이기 때문에 당연히 NodePort, LoadBalancer 서비스에서 사용 가능하다.(ClusterIP 는 내부 트래픽이기 때문에 설정 불가능)

apiVersion: v1
kind: Service
metadata:
  name: nodeport-local
spec:
  type: NodePort
  externalTrafficPolicy: Local
  ports:
    - name: "http-port"
      protocol: "TCP"
      port: 8080
      targetPort: 80
      nodePort: 30081
  selector:
    app: sample-app
spec.externalTrafficPolicy 설정값 설명
Cluster 노드에 도착한 트래픽을 클러스터 내에 존재하는 다른 노드에 속한 파드까지 대상으로 하여 다시 로드밸런싱한다.(기본값)
Local 노드에 도착한 트래픽을 해당 노드 내의 파드 대상으로만 로드밸런싱한다.

 

이제 아래 커맨드로 파드가 1개 존재하는 desktop-worker 노드를 호출하면, 여러번 호출해도 동일한 파드로 요청이 가는 것을 볼 수 있다. client IP 주소도 유지된다.

# 서비스 IP, Port 확인
$ kubectl get svc nodeport-local
NAME                    TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
sample-nodeport-local   NodePort   10.96.25.136   <none>        8080:30081/TCP   76m

# 파드 확인
$ kubectl get pods -o custom-columns="NAME:{metadata.name},Node:{spec.nodeName},NodeIP:{status.hostIP}"
NAME                                 Node              NodeIP
sample-deployment-75c768d5fb-2lkwp   desktop-worker2   172.18.0.3
sample-deployment-75c768d5fb-9qdjm   desktop-worker    172.18.0.4
sample-deployment-75c768d5fb-g5vkv   desktop-worker2   172.18.0.3

# 아래 커맨드를 여러번 실행해본다.
$ curl -s http://172.18.0.4:30081

 

2. LoadBalancer 에서 노드 health check 하기

NodePort 서비스에서 spec.externalTrafficPolicy: Local 로 지정한 경우, 노드 내에 대상 파드가 하나도 없는 경우에는 TCP 수준의 Connection refused 에러가 발생한다. 목적지 포트를 Listen 하는 프로세스(파드)가 아예 없기 때문이다. 반면에 LoadBalancer 서비스에서는 spec.externalTrafficPolicy: Local, spec.healthCheckNodePort 를 지정하여(미지정시 랜덤 포트가 자동 지정됨) 외부 로드 밸런서가 해당 노드가 타겟 파드를 가지고 있는지 확인할 수 있게 한다.(헬스 체크) 해당 노드에 파드가 존재하지 않으면 http status 503 이 반환되고, 로드 밸런싱 대상에서 제외된다.

아래와 같은 매니페스트로 LoadBalancer 에 헬스 체크용 노드포트를 지정한다.(30086)

apiVersion: v1
kind: Service
metadata:
  name: lb-local
spec:
  type: LoadBalancer
  externalTrafficPolicy: Local
  healthCheckNodePort: 30086
  ports:
    - name: "http-port"
      protocol: "TCP"
      port: 8080
      targetPort: 80
      nodePort: 30085
  selector:
    app: sample-app

 

spec.healthCheckNodePort 는 LoadBalancer 서비스 이면서 spec.externalTrafficPolicy: Local 인 경우만 지정할 수 있는 항목이다. 아래는 헬스 체크 엔드포인트가 응답하는 예시이다.

$ curl -s http://172.18.0.4:30086
{
  "service": {
    "namespace": "default",
    "name": "lb-local"
  },
  "localEndpoints": 1
}

 

블로그 이미지

망원동똑똑이

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

,