data engineering

kubernetes how to communicate between pods or nodes

qkqhxla1 2021. 2. 12. 20:06

matthewpalmer.net/kubernetes-app-developer/articles/kubernetes-networking-guide-beginners.html

 

Kubernetes Networking Guide for Beginners - Kubernetes Book

Kubernetes Networking Guide for Beginners One of the hardest things to learn about Kubernetes as a software developer is how the networking works. I had never done anything with networks prior to learning Kubernetes – I just wanted to deploy my code! I s

matthewpalmer.net

을 번역함. k8s의 네트워크에 대해 이해가 많이 부족했는데 도움이 많이 되었다.

 

1. 동일한 pod안에서의 Container끼리의 통신.

 

동일한 팟 안에서 돌아가는 두개의 컨테이너가 있으면 둘은 어떻게 통신할까요?

내 컴퓨터에서 여러 서버를 돌리는것처럼 localhost와 port로 통신합니다.

이게 가능한 이유는 동일한 팟 내의 컨테이너들이 동일한 network namespace를 갖기 때문입니다. 동일한 팟 내의 컨테이너들은 네트워크 자원을 공유합니다.

 

network namespace란 무엇인가요?

network namespace란 네트워크 인터페이스, 라우팅 테이블의 모음집입니다. 

namespace는 한 가상머신안에 많은 namespace들을 가졌을경우에 충돌이나 간섭 없이 통신하기 위해서 사용됩니다.

(모든 팟들에 각각 3000포트로 listen을 하고있는 서비스를 실행시키기를 원하지 않을겁니다. 충돌이 날 것이기 때문이죠.)

 

쿠버네티스의 모든 팟에는 우리가 모르는 컨테이너가 하나씩 있습니다. 이 컨테이너의 가장 중요한 일은 팟 내의 다른 컨테이너들이 죽었을 때를 대비해 namespace를 열어놓는 것입니다. 이 컨테이너를 pause 컨테이너라고 부릅니다.

 

그러니까, 모든 팟은 각각의 network namespace를 갖고 있고, 동일한 팟 내의 컨테이너는 모두 동일한 network namespace 안에 있습니다. 이런 구조를 가짐으로써 팟 내의 컨테이너가 서로 localhost를 통해서 통신하고, 동일한 팟 내에서 여러 컨테이너를 돌릴 경우 port conflict를 주의해야 합니다.

 

2. 동일한 노드 내의 다른 pod끼리의 통신

 

노드 내의 각각의 팟은 모두 각각의 network namespace를 가지고 있습니다. 그리고 각각의 팟은 각각의 ip주소를 가지고 있습니다.

그리고 각각의 팟은 모두 자신이 평범한 eth0이라는 네트워크 인터페이스를 통해서 통신한다고 생각합니다. 그런데 이건 쿠버네티스가 가상의 환경으로 그렇게 생각하게끔 만든 겁니다.

 

각각의 팟의 eth0은 실제로 노드에 있는 가상의 이더넷과 연결되어 있습니다.

가상의 이더넷은 팟의 네트워크와 노드를 연결해주는 통로입니다. 연결은 두 방향이 있습니다. 팟쪽에서는 eth0이고, 노드쪽에서는 vethX입니다.

왜 X가 붙는걸까요? 그 이유는 한 노드의 모든 팟들에 대해 vethX가 붙기 때문입니다. 예로 3개의 팟이 있으면 veth1, veth2, veth3이 되겠네요.

팟이 다른 노드로 요청을 보낼때, 팟쪽에서는 eth0을 통해서 나가고, 노드쪽에서는 vethX로 나가게 됩니다.

그러면 어떻게 다른 팟으로 요청을 보낼까요? 노드는 network bridge를 사용합니다.

 

Network Bridge가 뭔가요?

network bridge는 두개의 네트워크를 연결합니다. 요청이 network bridge로 오면 bridge는 원래 요청을 처리하기 위해 연결된 모든 디바이스(veth1, veth2 .... vethn)에게 물어봅니다. 이 요청을 처리할 ip 주소가 있냐고 말이죠.

(각각의 팟은 각각의 ip주소를 갖고 있고, 본인의 ip주소를 알고 있다는걸 기억합시다.)

디바이스중 하나가 요청을 처리할 ip주소를 갖고 있다고 답하면 브리지는 이 정보를 원래 요청을 보냈던 곳으로 보내고, 그러면 네트워크 연결이 끝납니다.

쿠버네티스에서는 이러한 bridge를 cbr0이라고 부릅니다. 노드의 모든 팟은 bridge의 일부이고, bridge는 한 노드 내의 모든 팟을 연결합니다.

 

3. 다른 노드 사이의 pod들끼리의 통신

 

다른 노드 사이의 팟들끼리는 어떨까요?

network bridge가 연결된 모든 디바이스에게 요청을 처리할 ip주소가 있냐고 물어보고, 아마 처리할수 있는곳이 없을겁니다.(다른 노드 사이의 통신인데 bridge는 한 노드 내에서 처리하므로 처리할수 있는 곳이 없음. 이 파트는 cloud provider나 networking plugins에 따라 달라질 수 있음.)

그 후에 bridge는 default gateway로 돌아갑니다. 이 요청은 cluster level까지 올라가서 ip주소를 찾습니다.

cluster level에서는 다양한 노드들에 대해 ip주소가 맵핑된 테이블이 있습니다. 노드들의 팟들은 특정 범위 내에서의 ip주소를 할당받습니다.

 

예로 쿠버네티스가 노드 1의 팟들에 대해 주소를 100.96.1.1, 100.96.1.2라고 줬다고 가정해봅시다.

노드 2에는 100.96.2.1, 100.96.2.2같은 식으로 주소를 줄겁니다.

테이블에는 ip주소가 100.96.1로 시작하는 것들은 노드 1로, 100.96.2로 시작하는 것들은 노드 2로 가라고 저장되어있습니다.

 

패킷이 어떤 노드로 가야하는지 정해지고 나서는 위의 2번. 동일한 노드 내에서의 다른 pod끼리의 통신과 거의 비슷합니다.

 

4. pod들과 service들 사이에서의 통신

 

쿠버네티스에서는 이 부분이 중요합니다.

쿠버네티스에서 service는 하나의 ip주소를 여러 팟들에 맵핑합니다. 서비스의 endpoint(도메인이나 ip주소)로 요청을 보내면 service의 프록시가 service의 맞는 팟으로 요청을 보냅니다.

쿠버네티스가 모든 노드에서 돌리는 kube-proxy라는 작은 프로세스를 통해 이런 일들이 일어납니다.

kube-proxy는 가상의 ip주소를 여러 개의 팟의 ip주소로 맵핑해줍니다.(service인 경우 여러 팟이 안에서 돌으니까.)

kube-proxy가 service의 가상 아이피를 실제의 팟의 ip주소로 매핑하면 요청이 위에서 설명한것처럼 갑니다.

 

DNS는 어떻게 작동하고 ip주소는 어떻게 발견하나요?

 

DNS는 도메인 주소를 ip주소로 변경해줍니다.

쿠버네티스는 DNS 주소를 변환해주는 서비스를 가지고 있습니다.

클러스터의 모든 서비스가 my-service.my-namespace.svc.cluster.local과 같은 도메인을 할당받습니다.

팟들은 자동으로 DNS가 주어지며 YAML config에서 hostname과 subdomain을 설정함으로써 변경할수 있습니다.

그러니까 서비스의 도메인으로 요청이 가면 DNS는 그것들을 서비스에 맞는 ip주소로 변경해줍니다.

그러면 kube-proxy가 그 서비스에 맞는 ip주소들을 팟의 ip주소로 바꾸어줍니다.

그리고 팟이 같은 노드 안에있는지 다른 노드 안에있는지 등등에 따라 위에서 설명한 과정으로 통신이 진행됩니다.