본문 바로가기
Linux & Kubernetes

Kubernetes Network

by 탁종민 2021. 6. 23.

POD network

POD 의 기본 네트워크

POD는 하나의 namespace를 공유하는 여러개의 container로 이루어진 단위이다. 아래에서 POD1을 보면 puase, container1, container2가 하나의 POD를 이루는걸 볼 수 있다. 모든 process가 죽어버리면 network namespace도 사라져버리는데 이를 방지하기 위해 pause container가 따로 존재한다. pause container는 sleep을 주구장창하면서 pod를 위한 network namespace를 유지해준다.

그림에서 보듯 2개의 POD가 있다고 하자. 왼쪽을 POD1 이라 하고 오른쪽을 POD2 라고 하자. POD1이 POD2에 패킷을 보내고 싶다면 어떻게든 dest IP가 10.0.2.2인 패킷을 Node2의 eth0(10.100.0.3) 으로 보내주기만 하면 된다. 그러면 Node2의 routing rule로 인해 dest ip 10.0.2.2 Packet을 cbr0 브릿지를 통해 veth0로 흘려보내 줄 것이다. 

그렇다는 건 결국 중간에 존재하는 라우터가 dest IP address 10.0.2.2 패킷의 destination이 Node2(10.100.0.3)인 걸 알고 있어야 한다는 걸 뜻한다.

 

 

가설을 하나 세워서 중간에 단 하나의 특별한 라우터가 존재하며 이 라우터는 각 노드들의 내부 POD에 가기 위해 어떻게 라우팅해야 하는지 rule을 유지하고 있다고 하자. 즉 gateway router인데 각 노드들이 어떤 POD IP를 가지고 있는지 다 알고 routing해주는 router이다.

이런 특별한 라우터 역할을 누가할까?

 

Overlay Network

앞에서 말한 특별한 라우터는 사실 모든 각 노드에 존재한다. kubernetes에선 각 워커노드는 만약 특정 POD가 다른 노드에 있다면 패킷을 encapsulation해서 tunneling을 이용해 전달한다.

그림: https://techcommunity.microsoft.com/t5/networking-blog/introducing-kubernetes-overlay-networking-for-windows/ba-p/363082

아래에서 노드1( public IP 10.100.0.2) 에서  pod2 ( veth 10.0.2.2 ) 로 패킷을 보내려고 한다고 하자. 쿠버네티스는 pod를 생성하면서 pod들의 Cloud-IP가 무엇이고 해당 pod가 어디 node에 속해있는지를 모두 기록해 관리한다. 그리고 각 노드에서 특정 pod로 패킷을 보내야 할 때는 어느 노드로 보내야 하는지 역시 모두 관리한다. 쿠버네티스의 각 워커 노드들은 해당 정보를 이용해 packet을 encapsulation하고 지정된 노드로 정확히 패킷을 보낸 후 다시 de-encapsulation을 진행해 각자 IP를 가진 노드들이 세계에 어느곳에 있든간에 마치 하나의 subnet에 존재하는 것처럼 Overlay network를 구성한다.

 

Service : ClusterIP

pod의 IP는 Overlay Network를 이용한 routing rule로 인해  클러스터 내에서 언제나 reachable 하다. 하지만 pod는 언제든지 자원을 뺏겨 해당 IP를 다른 pod에게 넘겨줄 수 있는 인스턴스이다. 이런 휘발성인 pod의 IP말고 고정적으로 사용할 수 있는 cluster IP 혹은 public IP가 필요한데 이를 위해 service가 존재한다.

 

ClsuterIP 타입의 service는 클러스터 내의 고정된 또 다른 IP를 통해 pod에 접근 가능하게 해준다. 이런 고정된 주소는 사실 쿠버네티스의 kube-proxy와  kube-proxy가 관리하는 netfilter에서 존재하는 가상의 주소이다. netfilter은 리눅스 커널의 network packet을 다루는 모듈이다. netfilter은 rule을 통해 rule에 matching 되는 패킷의 Dest IP, Dest Port등을 수정할 수 있다. ( DROP 하거나 REJECT 등등도 할 수 있다. )

이 netfilter를 이용해 각 노드의 kube-proxy는 master-node로부터 service와 pod에 대한 정보를 받으면 해당 노드의 netfilter에 rule을 추가한다. 추가된 rule은 각 노드의 netfilter에서 특정 service로의 packet이 감지되면 해당 packet의 dest-IP:port를 service의 실제 pod들이 사용하는 IP:port로 rewrite 하는 rule이다.

 

Service : NodePort, LoadBalancer

NodePort와 LoadBalancer 모두 특정한 외부 IP를 가지는 Service이다. 둘 다 클러스터용 IP를 부여 받고 netfilter에 의해  클러스터용 IP가 관리 된다는 점에서는 Cluster IP 타입과 똑같다. 하지만 둘 다 추가기능을 갖고 있다.

NodePort는 모든 노드에 특정 외부 포트를 열게 된다. 그래서 netfilter는 이를 처리하기 위한 rule을 추가한다. 추가된 rule은 NodePort의 외부 포트로 들어오는 패킷의 dest-IP를 NodePort의 pod중 하나의 IP로 바꿔서 터널링해 내보내 버린다.

LoadBalancer는 특정 노드를 (해당 노드의 IP가 external-ip가 된다) 하나 골라 외부 포트를 열게 된다. 마찬가지로 netfilter는 이를 처리하기 위한 rule을 추가한다. 추가된 rule은 선택된 노드의 LoadBalancer 포트로 들어온 패킷의 Dest-IP를 다시 LoadBalancer의 pod중 하나의 IP로 바꿔서 터널링해 내보낸다.

 

ref:

https://medium.com/@arpitkh96/basics-of-container-networking-with-linux-part-1-3a3cdc64c87a

https://medium.com/google-cloud/understanding-kubernetes-networking-pods-7117dd28727

'Linux & Kubernetes' 카테고리의 다른 글

Docker's Internal  (0) 2021.01.07

댓글