Computing

Pod 네트워크 (1) : Service 필요성과 개념, 종류 (ClusterIP, NodePort, LoadBalancer) 본문

Cloud/Kubernetes

Pod 네트워크 (1) : Service 필요성과 개념, 종류 (ClusterIP, NodePort, LoadBalancer)

jhson989 2022. 12. 15. 21:40

파드 통신 예시 및 Service의 필요성

쿠버네티스 클러스터에서 애플리케이션(워크로드)은 파드 단위로 실행된다. 애플리케이션은 하나 이상의 파드들로 구성될 수 있는데, 간단한 웹애플리케이션 예시를 들면 Java spring 웹애플리케이션 로직을 담당하는 파드 3개, 데이터 저장을 위한 DB 파드 하나로 구성될 수 있다.

 

Fig 1. Kubernetes 내 Pod IP 부여 예시 [1]

 

Fig 1.과 같이 모든 파드는 쿠버네티스 클러스터 안에서 가상 IP 하나를 부여받는다. 이 가상 IP는 쿠버네티스 클러스터 안에서 유일하며, 쿠버네티스 클러스터 내에서만 유효하다. 이 가상 IP를 통해 같은 쿠버네티스 클러스터 내의 파드들끼리는 통신이 가능하다. 예를 들면 Fig 1.에서 Pod A가 Pod C와 통신하기 위해서 10.1.2.1로 패킷을 보내는 것이 가능하다.

 

문제는 파드들은 예상치 못한 에러에 의해 중단되고 새로 시작될 수 있다. 새로 시작된 파드는 기존에 실행되던 노드가 아닌 전혀 다른 노드에서 실행될 수도 있다. 새로 시작된 파드는 항상(같은 노드에서 재실행된다 할지라도) 새로운 아이피가 부여된다. (파드는 stateless 로직을 처리하기에 당연하게 아닌가 싶다.) 이런 상황에서 재실행된 파드의 IP를 새롭게 알아야 통신할 수 있게 된다. (정확히는 재실행이 아니라, 같은 deployment에 속하는 완전히 새로운 파드가 생성되는 것)

 

예를 들면 Fig 1.에서 Pod A가 Pod C와 통신하다고 하자. Pod A는 10.1.2.1 주소를 통해 Pod C와 통신할 수 있다. 그런데 Node B에 갑자기 불이 나서 Pod C가 종료되고, Pod C가 Node A에서 재실행되는 상황이 발생했다. Pod C는 Node A에서 실행되기에 새로운 IP인 10.1.1.3을 부여받는다. Pod A는 Pod C의 바뀐 IP를 알 수 없기에 더 이상 통신을 못하는 상황이 발생한다. 결국 개발자가 직접 Pod A를 종료하고 Pod A에게 등록된 Pod C의 주소를 수정해줘야 한다.

 

이러한 문제 뿐만 아니라 Pod의 가상 IP는 가상, 사설 IP라는 문제도 있다. Pod의 가상 IP는 쿠버네티스 클러스터 안에서만 유효한 주소로, 외부 클라이언트는 이 주소에 접근할 수 없다. 웹애플리케이션 Pod를 쿠버네티스 클러스터에 배포하였는데 외부에서 접근할 수 없다면 무슨 소용이 있으랴. 헛수고한 셈이다.

 

이러한 파드 네트워크 통신 문제를 해결하기 위해 쿠버네티스는 Service[2]라는 리소스를 제공한다. 서비스는 파드를 통해 실행되는 애플리케이션을 노출하는 추상화된 방법으로, 파드의 주소가 가상 주소이며 항상 변할 수 있기에 도입된 개념이다. 파드와 통신이 필요할 시 파드와 직접 통신하는 것이 아닌 서비스를 거쳐 통신하도록 하면, 파드 수정없이 파드 간 혹은 파드와 외부 간 통신을 쉽게 구현할 수 있다. (후에 정리하겠지만 서비스는 추상적 개념으로 kube-proxy와 iptables, ipvs를 통해 구현된다.)

 

 

 

Service 개념

 

Fig 2. Kubernetes Service 리소스 개념 [3]

 

Fig 2.는 파드 간 혹은 파드와 유저(클라이언트) 사이에서 서비스 리소스가 어떻게 사용되는 지를 잘 보여주는 그림이다. 서비스는 하나의 deployment를 네트워크에 대표하여 공개한다. Deployment는 하나의 로직을 수행하는 파드 한개 혹은 여러 replica들을 생성하는데 이들의 IP는 계속 변한다. 서비스 리소스는 이 deployment에 의해 배포된 파드들을 하나로 묶어 변하지 않는 하나의 IP를 제공한다.

 

예를 들어 3개의 replica로 배포된 stateless [이미지 처리] 파드들과, 이들을 사용하는 [이미지 생성] 파드 하나가 있다고 가정하자. 이 파드들은 각자의 IP를 가지고 있는데 이 IP들은 계속 변할 수 있다. 또한 [이미지 생성] 파드가 [이미지 처리] 파드들에 접근하고자 할때, 사실 3개의 [이미지 처리] 파드들 중 아무 파드에나 접근해도 상관없다. 서비스는 3개의 [이미지 처리] 파드들에 접근 가능한 하나의 변하지 않는 IP를 제공한다. [이미지 생성] 파드는 서비스 IP를 통해 [이미지 처리] 파드에 접근할 수 있다. 

 

[이미지 생성] 파드는 변할 수 있는 [이미지 처리] 파드들의 IP 주소를 계속 추적할 필요 없이, 변하지 않는 서비스 IP 하나만 기억하고 있으면 된다. 서비스는 또한 [이미지 처리] 파드들 사이에 로드 밸런싱 기능을 제공한다. 이를 통해 [이미지 생성] 파드는 3개 중 여유로운 [이미지 처리] 파드에 연결된다. (로드 밸런싱 알고리즘 따라 연결되는 파드는 달라진다)

 

외부로 부터 접근이 가능하게 서비스를 설정할 수 있다. 밑에서 정리하겠지만 서비스는 노드의 IP를 빌리거나(NodePort 타입 서비스) 외부 Load Balancer(LoadBalancer 타입 서비스)를 이용해 외부 네트워크에 공개된다. 이를 통해 드디어 외부 사용자가 애플리케이션에 접근할 수 있다. 반대로 파드가 클러스터 외부 애플리케이션에 접근할 때에도 서비스가 사용될 수도 있다. (이 경우에는 서비스를 꼭 사용하지 않아도 된다.)

 

서비스를 통해 파드들을 네크워크에 공개하기 위해서는 누군가가 끊임없이 파드들의 IP를 추적해야 할 것이다(파드의 IP는 변할 수 있기에). 쿠버네티스는 서비스에 의해 공개되는 파드들의 IP를 endpoints라는 리소스로 관리한다., 서비스는 endpoints로 등록된 파드들로 트래픽을 보낸다. 쿠버네티스 컨트롤 플레인의 Endpoints Controller가 이 endpoints 관리를 담당한다. 새로운 파드의 endpoint 추가 혹은 기존 파드의 endpoint 제거 등이 필요할 경우 이를 수행하며, service의 endpoints가 유효하도록 관리한다.

 

 

 

Service 종류

쿠버네티스에는 ClusterIP, NodePort, LoadBalancer, ExternalName 총  4가지 유형의 Service가 제공된다. 이 중 ClusterIP, NodePort, LoadBalancer는 파드로의 접근을 쉽게 해주는 서비스이며, ExternalName은 파드가 외부로 쉽게 접근 할 수 있게 해주는 서비스이다.

 

ClusterIP 유형 서비스는 클러스터 내부에서만 접근 가능한 서비스이다. 클러스터 내의 파드들은 이 서비스를 통해 서비스에 의해 관리되는 파드들에 접근할 수 있다. 파드들이 서로 다른 워커노드에 위치하여도 트래픽이 정상적으로 전달된다. Fig 2.는 ClusterIP 유형의 트래픽 전달을 보여주는 그림으로, 한 노드 내부의 Client의 트래픽을 kube-proxy(iptables)을 통해 클러스터 내의 Pod에 전달한다. kube-proxy가 트래픽을 원하는 파드로 전달하는 역할을 수행한다. ClusterIP 유형 서비스는 외부에서는 접근할 수 없고, 내부 파드간 통신에 사용되는 서비스 유형이다.

 

Fig 3. ClusterIP 유형 서비스 [4]

 

NodePort 유형 서비스는 클러스터의 모든 워커 노드(컴퓨터,서버)의 고정 포트에 자신을 노출시킨다. 워커 노드들의 IP를 빌려 외부 네트워크와 연결되는 유형으로 port forwarding 개념과 원리가 같다. 외부(공용) 네트워크에 연결된 워커노드의 특정포트(ex, 30562, etc.)로 트래픽이 들어오면 서비스에 의해 관리되는 파드들에게 전달된다. (Fig 4.) NodePort는 내부적으로 ClusterIP 유형의 서비스를 이용하므로, 클러스터에 속한 아무 워커노드의 특정포트로 트래픽이 들어와도 정상적으로 원하는 파드로 전달된다.

 

NodePort 유형의 단점으로는 외부에서 워커노드의 IP주소를 알고 있어야 한다는 것이다. 파드와 비슷한 문제가 발생하는데, IP를 알고 있는 워커노드가 고장나면 클러스터에 더이상 접근할 수 없다. 또한 워커노드 간의 로드 밸런싱 과정이 없기에, 한 워커노드로 많은 사용자가 몰릴 수도 있다.

 

Fig 4. NodePort 유형 서비스 [4]

 

LoadBalancer 유형의 서비스는 NodePort 유형의 단점을 극복할 수 있다. LoadBalancer 유형은 내부적으로는 NodePort 유형을 사용하는데, 여기에 외부 Load balancer (스위치) 혹은 MetalLB와 같은 소프트웨어 레이어를 추가한 것이다. LoadBalancer는 외부에서 접근가능한 유일한 IP 하나를 제공해주고, 이 IP로 들어온 트래픽을 내부적으로 사용되는 NodePort 서비스로 전달한다. NodePort는 들어온 트래픽을 C다시 내부의 lusterIP 서비스를 통해 최종적으로 파드에게 전달한다.

 

LoadBalancer 유형은 모든 워커노드의 IP를 추적하는 역할을 사용자 대신한다. (어떻게 관리하는 지에 대해서는 공부가 추가적인 필요하다) 또한 로드 밸런싱 기능 또한 수행하여, 외부 로드 밸런서는 여유로운 워커노드에 트래픽을 전달한다.

 

 

 

Reference

[1] https://stackoverflow.com/questions/58859875/kubernetes-pod-communication-across-nodes-how-does-it-work

[2] https://kubernetes.io/ko/docs/concepts/services-networking/service/

[3] https://www.densify.com/kubernetes-autoscaling/kubernetes-service-load-balancer

[4] https://projectcalico.docs.tigera.io/about/about-kubernetes-services