서비스는 파드 집합을 길게 지속되는 안정적인 IP와 포트로 노출시킨다.
서비스에 대한 개념을 알고싶으신 분은 아래 포스팅은 보시길 추천드립니다.
https://velog.io/@baeyuna97/K8s-%EC%84%9C%EB%B9%84%EC%8A%A4-%EA%B5%AC%ED%98%84-%EB%B0%A9%EC%8B%9D
해당 포스팅은 서비스가 어떻게 구현되는 지를 알아보고자 합니다.
서비스와 관련된 모든 것은 각 노드에서 동작하는 kube-proxy 프로세스에 의해 처리된다.
서비스는 단지 네트워크 레벨에서 일관된 인터페이스를 제공하는 가상 IP 주소를 할당하는 역할만 수행하지 cpu나 메모리 등 리소스를 직접 소유하지 않습니다. (서비스 객체가 pod로 뜨지않는 점!)
결국 실제 service로 들어오는 요청을 로드밸런싱하는 작업을 Kube-proxy 컴포넌트가 수행합니다.
Kube-proxy는 service를 통해 동작하는 네트워크에 대한 처리를 담당하는 단어 그대로 proxy 역할을 관장하는 애플리케이션입니다.
1. 쿠버네티스 컨트롤 플레인의 서비스 및 엔드포인트 오브젝트 변경사항 감시
2. 요청이 service로 인입 시 네트워크 처리
클러스터의 모든 노드에서 서비스 기반으로 통신되어야하기 때문에 kube-proxy는 데몬셋으로 배포됩니다.
초기에는 kube-proxy가 실제 프록시로서 연결을 기다리다가, 들어온 연결을 위해 해당 파드로 가는 새로운 연결을 생성했다. 이것을 userspace 프록시 모드라고 한다.
kube-proxy가 직접 프록시 서버 역할
이 모드에서는 Linux의 IPtables 기능을 이용합니다. 하지만 NAT 룰을 통해 local Kube-Proxy에 redirect 시키고 Kube-Proxy가 직접 이 요청을 포워딩하게 합니다.
즉.. 트래픽이 두 번 리디렉션되고 이는 지연 시간과 처리량에 부정적인 영향을 미치게 됩니다.
위의 방식은 성능이 더 우수한 iptables 프록시 모드로 대체되었습니다.
이게 현재 기본값이지만 원한다면 userspace 프록시 모드를 사용하도록 설정할 수 있다.
이 모드도 UserSpace 모드와 동일하게 Linux 커널의 IPtables를 사용하고 있습니다.
하지만 Kube-Proxy로 요청을 보내는 것이 아닌 바로 대상 Pod로 트래픽을 전달합니다.
Kube-Proxy가 기존의 Proxy 역할을 하는 대신, IPTables에 Rule을 넣어주는 역할을 하게 되면서 traffic을 처리하는 것에 대한 부담이 없어지게 되었고(실제 트래픽 처리를 커널 단위에서 처리) UserSpace 모드와 비교하여 레이턴시가 줄어들었습니다.
iptables를 이용하여 서비스로 오고 나가는 패킷을 제어하는 방식
Kube-proxy는 api server를 통해 service와 pod 정보를 업데이트하고 iptables 규칙만을 업데이트합니다.
이로 인해 kube-proxy의 역할은 더 이상 proxy가 아닌 installer에 가까워졌습니다.
해당 모드도 단점은 존재하는데요.
기존 IPtables의 알고리즘은 lookup시에 순차적으로 규칙을 조회합니다.
이는 O(n) 성능을 가진다는 것을 말하며, 규칙의 수가 많아지면 조회 횟수가 선형적으로 증가한다는 것을 의미합니다.
또한, IPtables가 로드 밸런싱 알고리즘을 지원하지 않는다는 점 또한 단점으로 작용할 수 있습니다.
API 서버에서 서비스를 생성하면, 가상 IP 주소가 바로 할당됩니다.
곧이어 API 서버는 워커 노드에서 실행 중인 모든 kube-proxy 에이전트에 새로운 서비스가 생성되었음을 통보합니다.
각 kube-proxy는 실행중인 노드에 해당 서비스 주소로 접근할 수 있도록 만듭니다.
이것은 서비스의 IP/포트 쌍으로 향하는 패킷을 가로채서,
목적지 주소를 변경해 패킷이 서비스를 지원하는 여러 파드 중 하나로 리디렉션되도록 하는 몇개의 iptables 규칙을 설정함으로써 이뤄진다.
Kube-proxy는 API 서버에서 서비스가 변경되는 것을 감지하는 것 외에도, 엔드포인트 오브젝트가 변경되는 것을 같이 감시한다.
요청 시, 리눅스 IPVS를 이용하여 서비스로 오고 나가는 패킷을 제어하는 방식
Iptables와 유사하지만 IPVS라는 리눅스 커널 기능을 사용합니다.
쉽게, 클라이언트 요청을 가상 서버 IP 주소로 전달하고, IPVS가 로드 밸런싱 알고리즘에 따라 요청을 올바른 pod로 전달한다.
이 IPVS라는 기능이 해시 테이블을 기본 데이터 구조로 사용하고 커널 스페이스에서 동작하기 때문에, iptables 대비하여 성능 및 확장성에서 강점을 가집니다.
다만 해당 모드를 사용하기 위해서는 노드의 커널 모듈 설정에서 IPVS 모듈이 활성화 되어 있어야 합니다.
Kube-proxy는 k8s 클러스터 내의 네트워킹에 기본 요소입니다.
하지만 한계점으로 인해 e-BPF 기반의 cilium 등의 오픈소스로 대체되고 있습니다.
따라서, cilium을 다음 포스팅에서 알아보도록 하겠습니다.