포스트

AKS에 배포된 TCP 서버에 외부 트래픽 라우팅 하기 - 1

AKS에 배포된 TCP 서버에 외부 트래픽 라우팅 하기 - 1

개요


이번 글에서는 AKS에 배포된 TCP 기반의 서버 애플리케이션 Pod에 클라이언트의 트래픽을 전달한 과정을 소개해 드리려고 합니다. LB 솔루션으로는 Azure Load Balancer를 사용했습니다.

[AKS에 배포된 TCP 서버에 외부 트래픽 라우팅 하기 - 1]
[AKS에 배포된 TCP 서버에 외부 트래픽 라우팅 하기 - 2]

배경 설명


k8s 내부 서비스를 외부 트래픽과 연결하는 방법

k8s에서 내부의 서비스들을 외부 트래픽과 연결하는 방법은 여러 가지가 있습니다. Load Balancer 타입의 서비스가 그 중 하나 입니다. Load balancer는 클라우드 환경에서 장점이 있습니다. 클라우드 제공자(Azure, AWS 등..)가 제공하는 로드 밸런서를 사용하기 때문에 비교적 간단한 설정으로 TCP기반의 서비스를 외부에 노출할 수 있습니다.

다른 방법으로는 Ingress 또는 Gateway API가 있습니다. 다만, 아쉽게도 이들은 HTTP/HTTPS 통신에 최적화 되어 있습니다. Nginx 또는 HAProxy와 같은 몇몇 구현 벤더들이 TCP 통신을 지원하고는 있으나, 다소 제한적인 기능만을 제공하고 있기에 사용하기 적합하지 않다고 판단했습니다.

위에 나열한 방법들 외에 NodePort, HostPort등의 방법들도 있지만 클라우드 환경에서 사용하기에는 적합하지 않다고 판단했습니다.

Azure의 LB 솔루션들

Azure에서는 Load Balancer 외에도 여러 가지 로드 밸런싱 솔루션을 제공하고 있습니다. 아래 플로우차트는 애플리케이션의 요구사항을 기준으로 로드 밸런싱 솔루션을 결정하는 플로우 차트입니다. TCP 트래픽은 Azure Load Balancer(또는 + Traffic Manager)를 선택해야 함을 알 수 있습니다. Application Gateway는 TCP 프로토콜을 아직 정식 지원하고 있지 않습니다. (2024-10-19 기준)

Decision tree for load balancing in Azure (출처: Azure Learn)

Azure Load balancer 간단 소개

Azure Load Balancer는 OSI 모델 4계층에서 동작하는 로드 밸런서 구현체 입니다. Azure Load Balancer는 애플리케이션의 높은 성능을 보장하기 위해 여러 컴포넌트들을 이용합니다. 또한 요구사항에 따라 Public / internal 로드 밸런서를 구축할 수 있습니다. What is Azure Load Balancer?

실제 문제 / 경험


이제 AKS에 로드밸런서 타입의 서비스를 생성하고, Azure Load Balancer를 통해 트래픽이 전달되는지 확인해 보겠습니다. 로드밸런서 타입의 서비스를 생성할 때 Azure에서 제공하는 k8s 어노테이션으로 커스텀을 할 수 있습니다.

LoadBalancer type의 AKS service 생성

우선 기본 틀이 되는 k8s 서비스 객체를 생성해 보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: v1
kind: Service
metadata:
  name: kimmap-backend-tcp
  namespace: kimmap
spec:
  selector:
    app: kimmap-backend
  ports:
    - protocol: TCP
    port: 9999
    targetPort: 8888
    name: tcp-client
  type: LoadBalancer

이 서비스가 생성되면, Azure가 제공하는 접근 가능한 IP 주소의 9999포트로 들어온 TCP 트래픽이 AKS에 배포된 kimmap-backend 파드의 8888포트로 전달되게 됩니다.
Service 객체에 작성한 설정 기반으로 Load Balancer Rules이 생성이 되는데요. Azure portal에서 확인이 가능합니다.

Azure Load balancer 리소스 그룹

회사 인프라 관리 정책에 의해 AKS 클러스터와 Azure Load Balancer의 리소스 그룹이 동일하지 않을 수 있습니다.

이럴 때는 Service 객체 생성 시 Azure Load Balancer의 리소스 그룹을 지정해주어야 합니다.
앞에서 Azure에서 제공하는 k8s 어노테이션으로 Azure Load Balancer의 리소스 그룹을 지정할 수 있습니다.

1
2
3
4
5
6
7
8
9
apiVersion: v1
kind: Service
metadata:
  name: kimmap-backend-tcp
  namespace: kimmap
  annotations:
    # Azure Load Balancer의 리소스 그룹을 rg-network로 지정
    service.beta.kubernetes.io/azure-load-balancer-resource-group: rg-network 
spec: ...

Azure Load Balancer가 ‘rg-network’ 리소스 그룹에 포함되어 있다고 가정했습니다.
azure-load-balancer-resource-group 어노테이션을 사용하여 Azure Load Balancer의 리소스 그룹을 ‘rg-network’로 지정했습니다.

공용 IP(PIP) 고정하기

AKS에서 로드밸런서를 생성할 때 공용 IP 주소는 자동으로 생성됩니다. 그런데 서비스가 특정 IP 주소를 유지해야 하는 경우에는 곤란할 수 있습니다. AKS 로드 밸런서 설정을 업데이트할 때마다 공용 IP가 변경되기 때문입니다.

이럴 때는 로드밸런서가 사용자가 지정한 공용 IP(PIP)를 사용할 수 있도록 지정해 주어야 합니다. 마찬가지로 Azure에서 제공하는 k8s 어노테이션으로 공용 IP(PIP)를 지정할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: Service
metadata:
  name: kimmap-backend-tcp
  namespace: kimmap
  annotations:
    service.beta.kubernetes.io/azure-load-balancer-resource-group: rg-network
    
    # 이 서비스가 사용할 공용IP 리소스는 kimmap-tcp-pip 
    service.beta.kubernetes.io/azure-pip-name: kimmap-tcp-pip
spec: ...

azure-pip-name 어노테이션을 사용하여 해당 서비스의 공용 IP를 ‘kimmap-tcp-pip’으로 지정했습니다.

Azure에서는 공용 IP 또한 리소스로 관리해야 하는데요. 당연하게도 kimmap-tcp-pip 리소스는 미리 사전에 준비되어 있어야 합니다.

health probe

Health probe는 Back-end 인스턴스 상태를 확인하여 정상 여부를 판단하는 데 사용합니다. AKS에서는 Back-end 인스턴스는 k8s Node를 의미합니다. Health probe는 AKS Node가 트래픽을 받을 수 있는지를 결정하며, 비정상 상태의 Node에는 트래픽을 보내지 않도록 합니다. 단, 프로브 실패는 이미 수립된 기존 연결에 대해서는 영향을 미치지 않습니다.

Azure Load Balancer는 TCP, HTTP, HTTPS와 같은 다양한 Health probe 타입을 설정할 수 있습니다.

  • TCP Custom probe: 정의된 port로 TCP 세션 수립이 성공하는 것에 기반합니다. 만약 연결이 거부되면 프로브는 실패합니다. Port, Interval, Unhealthy threshold를 설정할 수 있습니다.
  • HTTP / HTTPS Custom probe: Load Balancer는 주기적으로 프로빙(기본 15초) 하며, 타임아웃 시간(기본 31초) 내에 HTTP 200응답을 받으면 해당 인스턴스를 정상으로 간주합니다.

Azure Load Balancer Health probe 기본설정은 아래와 같습니다.

  • 프로토콜 : HTTP
  • 포트: 자동으로 부여된 NodePort(LoadBalancer는 NodePort의 확장입니다.)
  • path: /healthz
  • interval : 5s
  • threshhold : 1

health probe protocol 커스텀 설정

기본 설정은 애플리케이션 프로토콜이 TCP인 경우 문제가 됩니다. HTTP 요청을 받을 서버가 준비되어 있지 않기 때문입니다. 실제로 health probe 기본 설정으로 서비스를 생성하게 되면, 프로브는 실패하게 되어 외부의 트래픽이 AKS 파드로 전달되지 않습니다.

따라서 health probe 프로토콜을 애너테이션을 통해 커스텀 하게 설정을 해주어야 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: v1
kind: Service
metadata:
  name: kimmap-backend-tcp
  namespace: kimmap
  annotations:
    service.beta.kubernetes.io/azure-load-balancer-resource-group: rg-network
    service.beta.kubernetes.io/azure-pip-name: kimmap-tcp-pip
    
    # 9999포트에 대한 health probe 프로토콜은 TCP
    service.beta.kubernetes.io/port_9999_health-probe_protocol: "TCP"
spec:
  ports:
    - protocol: TCP
    port: 9999
    ...

port_9999_health-probe_protocol 을 TCP로 수정했습니다. 여기서 9999는 앞서 설정한 외부 트래픽이 접근할 포트 번호 입니다.

health probe intervals 커스텀 설정

probe interval도 애너테이션으로 설정할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Service
metadata:
  name: kimmap-backend-tcp
  namespace: kimmap
  annotations:
    service.beta.kubernetes.io/azure-load-balancer-resource-group: rg-network
    service.beta.kubernetes.io/azure-pip-name: kimmap-tcp-pip
    service.beta.kubernetes.io/port_9999_health-probe_protocol: "TCP"
    
    # Azure Load Balancer의 health probe 설정 주기는 최대 59초입니다.
    service.beta.kubernetes.io/azure-load-balancer-health-probe-interval: "59"

azure-load-balancer-health-probe-interval 을 이용해 59초로 설정했습니다.

health probe threshold

프로브가 실패되면 health probe는 해당 노드는 비정상이라고 판단하고, 이후의 트래픽을 비정상 노드에 보내지 않습니다. 이때 probe 비정상 판단의 기준이 되는 probe 실패 횟수를 정할 수 있습니다.

Azure에서는 관련 애너테이션으로 port_health-probe_num-of-probe 를 제공하고 있지만 issue로 인해 동작하지 않습니다.(2024-10-19) 즉, k8s service 애너테이션으로는 설정할 방안이 없고, Azure Property를 통해 설정해야 합니다. 추후에 다른 새로운 글로 작성을 해보도록하겠습니다.

결론


지금까지 작성한 설정만으로도 제한된 환경에서는 외부 트래픽이 AKS에 배포된 TCP 서버 애플리케이션에 정상적으로 전달되는 것을 확인할 수 있습니다.

하지만 클러스터 환경과 서버 애플리케이션의 요구사항에 따라 해결해야 하는 문제가 더 있을 수 있습니다.

  • TCP 세션 지속성 문제
  • 네트워크 hop 문제
  • source IP 숨김 문제
  • health probe threshold 설정하기

TCP 세션 지속성 문제, 네트워크 hop 문제, source IP 숨김 문제는 k8s 서비스 객체의 externalTrafficPolicy 설정을 통해 해결할 수 있습니다. 이 때 충돌되는 health probe 설정도 추가적으로 업데이트를 해주어야 합니다. 다음 글에서 알아보도록 하겠습니다.

참고


Load-balancing options What is Azure Load Balancer?

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.