본문 바로가기
프로젝트&&스터디/KANS2기

[KANS-9주차] Topology Aware Routing

by james_janghun 2024. 10. 31.

해당 내용은 kubernetes 1.23 beta에서 시행된 내용입니다.

1.27 이전에는 Topology Aware Hints라는 내용으로 잘 알려져있습니다.

 

kubernetes 공식문서에서 확인할 수 있습니다.

기능

가장 활용도가 높은 곳은 아무래도 multi-zone을 사용하는 환경에서 매우 좋습니다. 해당 기능의 목적은 해당 존에서 발생한 트래픽은 해당 존에서 유지되는 것을 목표로 합니다. 

 

활용도

비용적인 측면에서도 다른 AZ에 대해서 통신을 하지 않기 때문에 많이 절약할 수 있고 네트워크 홉도 줄 일 수 있게 됩니다. 아무래도 각 AZ 별로 엔드포인트가 많아야 효용이 높습니다.

 

활용 방법

service.kubernetes.io/topology-mode=auto 라는 annotation을 service에 추가해주면 됩니다. 충분한 endpointslice가 존재하면 자동으로 hints를 할당해 줍니다.

1.27 버전 이전에는 service.kubernetes.io/topology-aware-hints 주석을 사용하였습니다.

 

테스트를 위한 배포

각 AZ 마다 pod가 1대씩 배포되며, b영역에만 netshoot pod를 하나 배포하고 여기에서 트래픽이 발생합니다.

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-echo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: deploy-websrv
  template:
    metadata:
      labels:
        app: deploy-websrv
    spec:
      terminationGracePeriodSeconds: 0
      containers:
      - name: websrv
        image: registry.k8s.io/echoserver:1.5
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: svc-clusterip
spec:
  ports:
    - name: svc-webport
      port: 80
      targetPort: 8080
  selector:
    app: deploy-websrv
  type: ClusterIP
EOF

 

접속 테스트를 수행할 pod

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: netshoot-pod
spec:
  containers:
  - name: netshoot-pod
    image: nicolaka/netshoot
    command: ["tail"]
    args: ["-f", "/dev/null"]
  terminationGracePeriodSeconds: 0
EOF

 

파드가 배포된 Zone 확인

kubectl get pod -l app=deploy-websrv -owide

 

100번의 트래픽 요청

트래픽을 100번 날릴 경우 모든 파드에 균일하게 보내는 것을 확인할 수 있습니다.

kubectl exec -it netshoot-pod -- zsh -c "for i in {1..100}; do curl -s svc-clusterip | grep Hostname; done | sort | uniq -c | sort -nr"

 

 

노드1에서 IP table 정책을 살펴보면 고르게 부하분산 하는 것을 확인할 수 있습니다.

 

동일하게 노드 2와 노드 3도 해보면 똑같다는 것을 알 수 있습니다.

 

Topology Mode 설정

이제 실제로 Topology Mode를 생성합니다. 이 때 hints는 엔드포인트가 트래픽을 제공해야 하는 영역을 설명합니다. 적용된 hints는 kube-proxy에 따라 각 존에서 엔드포인트로 트래픽을 라우팅 합니다. 이 역할은 endpointSlice Controller가 실질적으로 담당합니다.

 

설정을 위해서 annotation을 적용합니다. service에서 annotation 하나만 붙이면 되서 매우 간단합니다.

kubectl annotate service svc-clusterip "service.kubernetes.io/topology-mode=auto"

 

신기하게 하나의 pod만 계속 전송되는 것을 확인할 수 있습니다.

트래픽을 날리는 netshoot-pod와 같은 위치에 존재하는 pod만 호출한 다는 것을 확인할 수 있습니다.

 

endpointslices 를 조회해서 hints 정보를 확인할 수 있습니다. (describe 에서는 확인불가)

kubectl get endpointslices -l kubernetes.io/service-name=svc-clusterip -o yaml

 

실제로 각 노드의 Iptable을 확인해보면 해당 노드에 해당하는 zone만 트래픽을 보내는 걸로 라우팅되어 있습니다.

 

만약 같은 AZ에 목적지 파드가 없는 경우는?

해당 내용은 공식문서에서 Safeguards 부분을 확인하면 됩니다. safeguards에 의하면 예제로 만약 같은 AZ에 목적지 파드가 없는 경우, 자동으로 hints를 할당하지 않게 됩니다. 

결론적으로 말하면 이런 경우는 어쩔 수 없으므로 다른 AZ라도 요청을 보냅니다.

 

다음과 같이 호출해보면 트래픽이 가는데 문제없습니다.

또한 같은 방식으로 iptable을 확인해보면 해당 목적지로 모두 지정된 것을 확인할 수 있습니다.

 

다만 Topology Aware Routing를 사용하지 않기 때문에 endpointslices에서 hints 정보는 사라지게 됩니다.

 

hints 정보 삭제

annotation을 삭제하면 해당 옵션을 사용하지 않을 수 있습니다.

kubectl annotate service svc-clusterip "service.kubernetes.io/topology-mode-"

 

리소스 삭제

실습한 리소스는 모두 삭제하도록 합니다.

kubectl delete deploy deploy-echo; kubectl delete svc svc-clusterip