본문 바로가기

쿠버네티스 Pod 네트워크 (이전 완료)

쿠버네티스는 Pod라는 컨테이너의 집합으로 서비스를 관리한다. Pod는 하나 이상의 컨테이너들로 이루어진 단위이며, 쿠버네티스에서 가장 작은 단위이다. 이러한 Pod는 하나의 서비스 컨테이너를 감싸는 Wrapper 형태로 사용할수도, 하나의 컨테이너와 그 컨테이너를 보조하는 사이드카 패턴으로 사용하거나, 두개 이상의 컨테이너가 조합된 형식으로도 사용될 수 있다.

 

파드

운영 수준의 컨테이너 오케스트레이션

kubernetes.io

쿠버네티스 클러스터 내에서는 이러한 Pod들이 여러개 생성되어 동작하게 되며, 이러한 Pod들이 가지는 네트워크 이슈로는 4가지 이슈가 있다.

1. 동일 Pod내 컨테이너끼리 네트워크

2. 동일 노드 내 Pod끼리 네트워크

3. 동일 클러스터내 다른 노드간의 Pod끼리 네트워크

4. 외부 인터넷과 네트워크

 

 

1. 동일 Pod내 컨테이너끼리 네트워크

파드는 기본적으로 파드에 속한 컨테이너에 네트워킹과 스토리지라는 두 가지 종류의 공유 리소스를 제공한다.
 

파드

운영 수준의 컨테이너 오케스트레이션

kubernetes.io

동일한 Pod내에는 여러개의 컨테이너가 존재할 수 있으며, 같은 Pod 내의 컨테이너들은 네트워크와 스토리지를 공유하는 특성을 가진다. 여기서는 공유되는 네트워크에 대해 다뤄본다. 

 

Pod는 생성시 pause 컨테이너라는 특별한 컨테이너를 먼저 생성하게 된다. pause 컨테이너의 역할은 해당 Pod 내의 컨테이너들을 묶는 역할을 한다.

어떻게 이런 역할을 수행할까??

 

우선 리눅스 네임 스페이스에 대해 알아야 한다.

 

Linux namespaces - Wikipedia

Feature of the Linux kernel that partitions kernel resources Namespaces are a feature of the Linux kernel that partitions kernel resources such that one set of processes sees one set of resources while another set of processes sees a different set of resou

en.wikipedia.org

네임스페이스를 통해 프로세스를 격리시키게 되고, 동일한 네임스페이스로 격리된 프로세스끼리는 해당 네임스페이스의 특징을 공유하게 된다. 그 중 네트워크 네임스페이스의 경우 Ip, 인터페이스 등을 정의하는 네임스페이스다.

 

쿠버네티스는 Pod 생성시 내부적으로 pause 컨테이너라는 특수한 컨테이너를 생성하게 되고, 이 pause컨테이너는 여러 네임스페이스등을 만들어 컨테이너들에게 공유해주게 된다. 

 

다음은 그림과 같이 두개의 컨테이너가 들어있는 Pod의 예시다.

busybox 컨테이너와 nginx 컨테이너

이렇게 생성된 두개의 컨테이너들에 접속하여 네임 스페이스를 확인하여 본다.

nginx 컨테이너의 네트워크 네임스페이스
busybox 컨테이너의 네트워크 네임스페이스

두 컨테이너 모두 동일한 네임스페이스를 가지는것을 확인할 수 있다.

 

이후 ifconfig 명령을 통해 두 컨테이너의 인터페이스를 확인해 본다.

 

nginx 컨테이너의 인터페이스
busybox 컨테이너의 인터페이스

두 컨테이너 모두 동일한 eth0 인터페이스에, 172.16.189.67 IP를 가지는것을 알 수 있다.

이를 통해 두 컨테이너에서 모두 loopback 인터페이스를 사용하여 해당 네임스페이스의 다른 컨테이너  

busybox -> nginx

nginx -> busybox

로 127.0.0.1 또는 localhsot를 통해 접근이 가능해지게 된다

 

busybox에서 curl localhsot:80 명령을 사용하게 된다면, 동일한 인터페이스를 사용하는 nginx컨테이너의 80포트로부터 데이터를 받아오게 된다.

 

결론 : 동일 Pod내 컨테이너들은 동일한 네임 스페이스로 묶여있어, 서로 loopback 인터페이스를 통해 통신이 가능하다. 하지만, 여러 컨테이너가 동일한 포트를 여는것에는 제약이 될 수 있다. 

 

 

2. 동일 노드 내 Pod끼리 네트워크

 

동일 노드내에도 여러개의 Pod가 존재할 수 있다. 이러한 Pod끼리 네트워크에 대해 알아본다.

우선 쿠버네티스는 CNI라는 컨테이너 네트워크 인터페이스를 사용한다. 우리는 이 인터페이스를 만족하는 플러그인들을 설치하여 쿠버네티스 네트워크를 설정하게 된다. 그러한 서드파티 플러그인들에는 여러가지 종류들이 있지만 여기서는 Calico를 사용한 네트워크에 대해 알아본다. 

 

Project Calico

Free and open source, Project Calico is designed to simplify, scale, and secure container and Kubernetes networks. Invented and maintained by Tigera.

www.tigera.io

 

Calico에 대한 자세한 내용은 나중에 알아보도록 하고, 여기서는 어떻게 Pod끼리 통신이 되는지에 대해서만 알아본다.

우선 1. 에서 Pod는 하나의 인터페이스를 가진다는것을 알 수 있었다.

pod과 그 인터페이스 eth0

calico를 사용하게 될경우, Pod가 생성될때마다 가상 인터페이스인 calico 인터페이스가 하나씩 생기게 된다. 이러한 calico 인터페이스는 cali*****라는 이름을 가지게 되며, eth0과 쌍으로 만들어지게 된다.

 

eth0과 쌍으로 만들어진 cali인터페이스

 

실제 calico 인터페이스

 

또한 각 노드별로 vRouter 라는 가상의 라우터를 사용하게 되며, 모든 calico 패킷은 이 라우터를 시작홉과, 마지막 홉으로 거치게 된다.

 

Calico over IP fabrics

Understand considerations for implementing interconnect fabrics with Calico.

projectcalico.docs.tigera.io

이 vRouter는 실제로는 라우팅 테이블을 통해 동작하게 된다.

실제 라우팅 테이블

 

즉 다음 그림에서와 같이 두개의 Pod가 있고, IP가 다음과 같다면,

하나의 Node에서 통신하는 두개의 Pod

Pod1에서 Pod2로 가는 패킷은 [SRC: 172.16.189.71, DST: 172.16.189.70] 우선 자신의 eth0677b 인터페이스를 지나, vRouter를 지나 7dc5eth0 인터페이스로 도착하게 된다.

 

결론 : 동일 Node에서는 (CNI별로 다르지만 여기선 calico) Pod와 페어인 calico인터페이스가 생기게 되고, 이러한 calico 인터페이스는 라우팅 테이블에 등록되어, Pod간 IP를 통해 접속을 하게되면, 라우팅 테이블에 따라 상대방 인터페이스로 도달하게 된다.

 

 

3. 다른 노드간 Pod 통신

 

calico를 사용하게 되면, 다양한 네트워크 모드들을 사용할 수 있다. 여기서는 그중 default로 사용되는 IPIP 모드에 대해 다룬다.

 

IPIP모드란, IP 패킷에 IP 헤더를 덧씌워 사용하게 되는 오버레이 네트워크의 일종이다. 즉 기존 네트워크에서 가상의 네트워크를 한층 더 만들어 그 가상의 네트워크에서 데이터를 전송하는 것을 말한다.

이러한 작업은 각 노드의 tunl0 인터페이스에서 진행된다.

 

 

예를 들어 다음과 같은 상황이 있다고 한다.

각 노드의 디폴트 네트워크 인터페이스는 ens5(AWS EC2)다.

 

Pod1(172.16.189.71)에서 Pod3(172.16.70.71)로 통신을 하고자 한다면 

1. Pod1 -> Pod3로 가는 패킷을 P1라고 한다.

Source IP Destination IP
172.16.189.71 172.16.70.71

2. P1이 tunl0 인터페이스를 지나면서 노드 정보가 담긴 IP헤더가 추가됨. 이 패킷을 P2라고 한다. (IPIP)

Source IP Destination IP Source IP Destination IP
172.31.53.93 172.31.58.137 172.16.189.71 172.16.70.71

3. P2를 받은 Node2는 덧씌워진 헤더를 떼어내고, P1을 얻는다

4. P1을 Pod3에게 전달해준다.

 

이러한 과정을 거쳐 전달이 되게 된다.

 

 

이는 라우팅 테이블로도 확인이 가능하다.

Node 1(172.31.53.93) 에서 확인한 라우팅 테이블
Node 2(172.31.58.137) 에서 확인한 라우팅 테이블

 

 

결론 : 다른 노드간 Pod 통신에서는 tunl이라는 터널링 인터페이스가 사용이 되며,  기존 IP 패킷으로 새로운 IP패킷을 만드는 IPIP 터널링 기법을 사용하여 노드간 Pod 통신이 이루어진다.

 

4. 외부 인터넷과 통신

 

Pod로부터 나간 패킷이 외부 인터넷과 통신을 하려면 어떻게 해야 할까?

Pod의 src IP는 인터넷상의 public IP가 아니기 때문에 직접적인 통신은 불가하다. 때문에 리눅스의 NAT 기능중 하나인 Masquerade를 사용함으로써 이를 해결한다.

 

Linux Networking/IP Masquerade - Wikibooks, open books for an open world

Many people have a simple dialup account to connect to the Internet. Nearly everybody using this sort of configuration is allocated a single IP address by the Internet Service Provider. This is normally enough to allow only one host full access to the netw

en.wikibooks.org

 

이는 룰에 의해 패킷의 src IP를 호스트의 공인 IP로 바꿔주는 기능을 말한다.

 

다음과 같은 상황이 있다 가정해본다.

Pod1에서 외부로 가는 통신을 하고자 할때 다음 패킷이 만들어 지게 된다.

Source IP Destination IP
172.16.189.71 x.x.x.x

하지만 172.16.189.71은 클러스터내에서 할당된 IP이기 때문에 이 IP로는 통신을 할 수 없다. 때문에 iptable에 등록된  룰에 따라 해당 IP는 호스트의 public IP로 바뀌게 된다.

Source IP Destination IP
3.1.2.3 (host public ip) 172.16.70.71

 

결론 : Pod는 자신의 IP로는 외부와 통신을 할 수 없으므로, IP 마스커레이드 기능을 사용하여, 패킷의 src IP를 호스트의 public IP로 바꿔 통신을 하게된다.