본문 바로가기
컨테이너/쿠버네티스

[K8S] 쿠버네티스 네트워킹의 이해

by sangyeon 2022. 12. 6.
728x90

쿠버네티스의 네트워킹에 대해 간단하게 이해한 내용을 정리하고자 한다.

- 개인적으로 쉽게 이해하기 위해 혼자 공부한 내용 + 블로그 내용을 참고하여 정리한 글입니다. 틀린 부분이 있을 수 있습니다.

 

1. pause 컨테이너란?

: 하나의 파드를 생성하게 되면 해당 파드 하위의 컨테이너들은 pause 컨테이너의 네트워크 네임스페이스(veth0) IP를 갖게된다.   따라서 동일한 파드 내의 컨테이너 끼리는 하나의 파드 안에서 가상 인터페이스(veth0)를 공유하여 127.0.0.1 (localhost)로 포트를 구분하여 통신할 수 있다. -> Pod는 pause 컨테이너를 통해 네트워크 스택을 공유한다. 

허나 위에 그림처럼 도커 네트워크 구조로 여러 노드를 구성할 경우 각각의 파드의 네트워크가 연결되어 있지 않기 때문에 파드 사이의 통신이 불가능하다.

각 노드가 docker0 브릿지에서 동일한 IP로 할당이 되어 서로의 고유한 주소로 통신할 수 없다.

쿠버네티스는 자체적으로 네트워크 구성을 해주지 않기 때문에 클러스터를 구성할 때 CNI 규약을 구현한 CNI Plugin을 함께 설치해야 한다.

( 여러 개의 노드 내의 파드간의 통신이 필요한 경우에는 통신을 위한 별도의 오버레이 네트워크를 구성해주어야 한다.)

-> 네트워크 인터페이스(오버레이 네트워크, CNI)를 통해 파드에 할당되어 있는 고유한 IP주소로 통신할 수 있다. (아래 그림 참조)

※ 오버레이 네트워크 : 실제 노드 간의 네트워크 위에 별도 flat한 네트워크를 구성이며 CNI(Container Network Interface)라고도 부른다.

2. CNI Plugin의 역할

 - CNI는 쿠버네티스 네트워크 Addon으로 VPC 내에서 ENI를 통해 할당 가능한 IP대역을 확인해 파드에 고유한 IP를 할당하는 역할을 한다. 

- CNI는 IPAM(IP 할당관리)에 대한 책임을 갖고 있으며 적절한 라우팅 정보를 입력하는 것까지 포함한다. 

- Routing 테이블 설정 (커널 라우팅/ 동적 라우팅 기능으로 외부 라우터(VPC)에 각 호스트 사이 라우팅을 정의)   

   .라우터의 라우팅 테이블에 노드 끼리의 Rule이 추가되고 이를 통해 서로 간의 파드끼리 통신이 가능하도록 한다.

- Proxy ARP 기능 제공

 

※ CNI는 다음과 같은 통신을 지원한다.   

- 단일 호스트 내의 Pod간 통신 

- 서로 다른 호스트 내 존재하는 Pod간 통신   

- Pod와 다른 AWS 서비스 간의 통신 

- Pod와 온프레미스 데이터센터 간 통신   

- Pod와 인터넷 간의 통신

 

 

3. 멀티 노드에서 Pod간 통신 예시

: 아래 그림은 client pod -> veth1 -> CNI -> eth0 -> 라우터(VPC) -> eth0 -> CNI -> veth0 -> server pod 의 흐름을 보여주고 있으며

여기서 오버레이 네트워크 기능에는 가상 네트워크 인터페이스(veth), 브릿지 네트워크(cbr0), 라우터의 라우팅 Rule(destination rule)의 조합을 일컫는다.

1. client pod에서 server pod1의 서비스(service)로 요청

2. CoreDNS가 해당 서비스 이름(serverpod-svc)을 IP(10.3.241.152)로 매핑시켜줌

3. client pod(web pod)는10.3.241.152:80으로 패킷 요청

4. veth1은 해당 IP를 모르기 때문에 상위 게이트웨이로 패킷을 전달

5. cni0에서도 해당 IP를 모르기 때문에 상위 게이트웨이로 패킷을 전달

6. eth0도 해당 IP를 모르기 때문에 상위 게이트웨이로 패킷을 전달

    .여기서 kube-proxy의 netfilter에 정의되어 있는 Chain Rule에 의해 요청을 포워딩함.

7. 라우터에 정의되어 있는 라우팅 테이블에 의해 worker node2로 포워딩

8. eth1의 kube-proxy에서 netfilter 패킷을 Listening 중이고 패킷이 들어오면 cni1로 포워딩해줌

9. cni1은 단순 브릿지 네트워크이므로 하위 계층으로 패킷을 전달

10. 패킷은 server-svc에 도달하고 맵핑된 Pod에 패킷을 넘긴다.

 

 

4. CoreDNS란?

: CoreDNS는 쿠버네티스 클러스터의 DNS 서버 역할을 한다. CoreDNS는 쿠버네티스 API를 통해 Service를 관찰하고 있다가 새로운 Service가 생기면 해당하는 DNS record를 생성하여 (Service Name : IP) 맵핑 테이블을 만든다.

 

※ CoreDNS의 역할

- Pod, Service 도메인을 관리하고 외부 도메인 서버(ex. google.com) 연결이 필요한 경우 통로 역할을 수행한다.

   . 클러스터 외부로 나가는 DNS쿼리(google.com)도 CoreDNS가 담당하여 구글 IP주소를 구하여 전달해준다.

   . Pod 도메인 : <Pod-ip>.<namespace>.pod.cluster.local

   . Service 도메인 : <Service-name>.<namespace>.svc.cluster.local

- CoreDNS는 Pod 또는 Service를 도메인으로 접근할 수 있기 때문에 재기동 이후 변경되는 IP로 인한 불편함을 해결해준다.

- CoreDNS는 Deployment로 관리되고 kube-dns 서비스(service) 타입을 갖는다.

- Pod는 기본적으로 DNS 질의를 할 때 kube-dns 서비스를 찾는다. (/etc/resolv.conf의 kube-dns ClusterIP 확인)

 

 

5. kube-proxy란?

- 쿠버네티스 클러스터 내부 네트워크 요청을 전달하는 역할을 수행한다.

   .각 EC2 노드(Worker)에서 네트워크 규칙(iptables의 chain rule)을 관리하여 Pod와의 네트워크 통신을 가능하도록 한다.

- kube-proxy는 클라이언트가 k8s API로 정의한 서비스(Service)에 연결할 수있도록 해주는데, 서비스의 IP와 포트로 들어온 접속을 서비스를 지원하는    파드 중 하나와 연결시켜준다.

- 새로운 Service(Cluster IP)가 생성되거나 Pod가 추가될 때 트래픽을 정상적으로 보낼 수 있도록 Node의 iptables 룰을 추가한다.

   (iptables의 chain rule 규칙을 지정하여 패킷을 프록싱하도록 설정)

 

※ kube-proxy 동작방식 예시

- API 서버에서 CLI로 서비스를 생성하면 가상의 IP주소가 바로 할당된다.

- API 서버는 워커노드에 실행 중인 모든 kube-proxy에 새로운 서비스가 생성되었음을 통보한다.

- 각 kube-proxy는 실행 중인 노드에 해당 서비스 주소로 접근할 수 있도록 만든다.

  (이는 서비스의 IP/Port 쌍으로 향하는 패킷을 가로채서 목적지 주소를 변경해 패킷이 서비스에 딸린 여러 파드 중 하나로 리디렉션되도록 iptables 규칙     을 설정함으로 이루어진다.)

- kube-proxy는 API 서버에서 서비스가 변경되는 것을 감지하는 것 외에도 엔드포인트 오브젝트가 변경되는 것을 감시한다.

  (ex. 서비스의 ClusterIP가 변경되거나 서비스에 딸린 Pod 정보가 변경되는 경우를 감지하여 iptables 규칙을 업데이트한다.)

   .엔드포인트는 서비스를 지원하는 모든 Pod의 IP/Port 쌍을 가지고 있다.

위 그림처럼 kube-proxy는 1) 서비스와 엔드포인트(Pod의 IP/Port 쌍) 변경을 감시하고 변경되면 iptables 설정을 업데이트한다.

 2) 파드 A가 목적지(172.30.0.1:80) 패킷을 보내기 전에 노드A의 커널이 노드에 설정된 iptables 규칙에 따라 172.30.0.1:80 -> 임의로 선택된 파드의 10.1.2.1:8080으로 교체해야한다고 알려준다. 이후에는 서비스를 통하지 않고 파드A가 파드 B2로 직접 패킷을 보내게 된다.

(당연하겠지만, 위에서 배웠듯이 목적지(서비스)의 IP는 CoreDNS로부터 받았을 것이다.)

728x90