DevOps/K8S

Kubernetes 네트워크 동작원리

IT록흐 2025. 6. 18. 22:15
반응형

 
쿠버네티스 네트워크의 핵심 개념은 2가지이다. 
 
1) kube-proxy
2) CNI ( Container Network Interface )
 
kube-proxy는 서비스에서 파드로 트래픽을 이동시키는 역할을 하고 CNI는 서로 다른 노드 간의 트래픽 이동을 담당한다. 만약 A 노드에 배포된 kube-proxy가 B 노드에 있는 파드로 트래픽을 이동시킨다고 하면 서로 다른 노드이므로 CNI를 타고 트래픽을 이동하는 것이다. 
 
정리하면
트래픽 이동을 위한 룰은 kube-proxy가 담당하고 실제 노드 간 트래픽 이동은 CNI가 담당하는 것이다. 
 
 

kube-proxy

 
kube-proxy는 iptables라는 tool을 이용하여 netfilter가 바라보는 룰을 조작하는 프로그램이다.
 
리눅스 서버는 netfilter 모듈을 내장한다. netfilter 모듈은 리눅스 커널 내부로 들어온 패킷을 조작하는 리눅스 프레임워크이다. 리눅스 서버는 기본적으로 단말장치이다. 그래서 커널로 들어온 패킷을 밖으로 라우팅 시키지 않고 안에서 처리하도록 디폴트로 설정되어 있다. 
 
그러나 쿠버네티스 클러스터 노드로 쓰이는 리눅스 서버는 달라야 한다. 커널로 들어온 패킷이 다른 노드로 이동해야 하므로, 라우터처럼 트래픽을 라우팅 시켜야 한다.  그래서 온프레미스 환경에서 Kubernetes를 구성하면 모든 노드에 아래와 같은 설정을 한다. 
 

# sysctl params required by setup, params persist across reboots
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.ipv4.ip_forward = 1
EOF

# Apply sysctl params without reboot
sudo sysctl --system

 
 
이는 netfilter 프레임워크가 트래픽을 서버 밖으로 라우팅 하도록 커널 파라미터에 설정하는 명령어이다. sysctl.d 디렉토리에 설정을 생성하여 재부팅이 되어도 언제든 해당 설정이 활성화 되도록 한다. 
 
이제 리눅스 서버는 트래픽을 밖으로 내보낼 수 있다!
 
netfilter 프레임워크는 리눅스 커널에서 트래픽을 어디로 포워딩할지 결정한다. . Kubernetes에서 Service를 생성하면, kube-proxy가 iptables라는 CLI 도구를 이용해 netfilter가 바라보는 룰을 설정하는 것이다. 
 
 

root@kind-control-plane:/# iptables-save | grep 10.244.0

# 중략...
# Service -> 2개 EndPoint로 50% 확률로 로드밸런싱하여 포워딩시키는 룰
-A KUBE-SVC-TCOU7JCQXEZGVUNU -m comment --comment "kube-system/kube-dns:dns -> 10.244.0.3:53" -j KUBE-SEP-6E7XQMQ4RAYOWTTM
-A KUBE-SVC-TCOU7JCQXEZGVUNU -m comment --comment "kube-system/kube-dns:dns -> 10.244.0.2:53" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-YIL6JZP7A3QYXJU2

# EndPoint -> Pod 트래픽 포워딩시키는 룰
-A KUBE-SEP-6E7XQMQ4RAYOWTTM -p udp -m comment --comment "kube-system/kube-dns:dns" -m udp -j DNAT --to-destination 10.244.0.3:53
-A KUBE-SEP-YIL6JZP7A3QYXJU2 -p udp -m comment --comment "kube-system/kube-dns:dns" -m udp -j DNAT --to-destination 10.244.0.2:53
# 중략...

 
 
iptables-save 명령어로 netfilter 프레임워크가 바라보는 룰을 출력하는 명령어이다. 한 가지 예시로 coreDNS로 향하는 트래픽을 어떻게 라우팅되도록 설정되어 있는지 위에서 확인할 수 있다. 
 
Service(KUBE-SVC)에서 Endpoint(KUBE-SEP)로 향하는 트래픽이 --probability 0.50000000000, 즉 50:50 으로 로드밸런싱 되어 진행하도록 설정되어 있다. 그리고 EndPoint에서 특정 파드의 ip 및 port ( 10.244.0.3:53 )으로 트래픽을 포워딩하도록 룰이 설정되어 있다. SVC -> EndPoint -> Pod의 포워딩에 대한 룰이 이렇게 설정되는 것이다. 이렇게 우리가 생성한 서비스 매니페스트 파일은 netfilter 프레임워크가 바라보는 룰로 변경되어 적용된다.
 
 
그런데 한 가지 문제가 있다.
 
 
넷필터 프레임워크가 10.244.0.3:53으로 트래픽을 포워딩하려고 해도 10.244.0.3:53는 그저 파드 IP일 뿐이다. 트래픽은 물리적인 노드와 노드 사이를 이동해야 한다. 파드 IP만 가지고 물리적 노드로 이동할 수 없으므로 특정 노드에 배포된 파드로 트래픽을 포워딩 시킬 수 없다.
 
여기서 필요한 것이 바로 CNI ( Container Network Interface ) 이다.
 
 
CNI ( Container Network Interface )
 
CNI는 어떤 플러그인을 사용하느냐에 따라 그 원리가 다르다. 그러므로 가장 직관적으로 이해하기 쉬운 Calico를 두고 설명해보려고 한다.
 
 

https://velog.io/@hyungwook/KANS-%EC%8A%A4%ED%84%B0%EB%94%94-3%EC%A3%BC%EC%B0%A8-Calico-CNI-2%ED%8E%B8

 
 
 
Calico는 여러 방식이 있지만 디폴트로 IPIP 방식의 터널링 기술을 활용한다. 실제 도착지는 파드IP이지만 패킷 앞에 노드 IP를 가진 헤더로 캡슐화를 하는 것이다. 그럼 스위치는 해당 노드 IP와 매핑되는 MAC 주소로 트래픽을 이동시키는데, 해당 MAC 주소는 Calico 노드인 Bird(가상라우터)의 네트워크 인터페이스를 가리킨다. Bird는 캡슐화된 헤더를 제거하여 실제 파드 IP를 확인하고 트래픽을 라우팅하여 파드에게 보낸다. 
 
 
이처럼 쿠버네티스 네트워크의 핵심 개념은 2가지이다.
 
1) kube-proxy
2) CNI ( Container Network Interface )
 
kube-proxy는 서비스에서 파드로 트래픽을 이동시키는 역할을 하고 CNI는 서로 다른 노드 간의 트래픽 이동을 담당한다. 

반응형