길고 길었다...

아래는 이번에 K8s를 직접 홈서버 4대에 구현하고 실험해보면서 느낀바를 정리한 내용이다
1. K8s는 nginx랑 전략이 다르다

- nginx 때는 Weighted round robin로 서버에 맞춰 튜닝했지만, K8s는 그런 식으로 튜닝할 수 없었다
- K8s의 장점은 '수평확장'
- 이 장점을 최대한 끌어내려면 그에 맞춰 구조를 변경해야했다
- 이전과 동일한 환경에서의 테스트는 불가하다는 것
- 각자의 장점과 쓰임이 다르다고 판단했음
- K8s의 최대 장점은 '수평확장'이니 이것을 극대화하기로 했다
2. 그럼에도 통일한 부분

- 다만 이전 분산 시스템 튜닝과 비슷하게 하고 싶었던 점이 몇가지 있었다
- 우선 맥미니는 Ingress-nginx만 담당하게했다
- Ingress-nginx는 쿠버네티스 전용 nginx라고 이해하면 편함
- 나머지는 worker 노드로써만 동작하게 했다
3. 맥미니가 힘들다네요

- 레플리카(replica)는 초기엔 20개로 제한되어있었지만, 성능저하가 오길래 200개까지 늘렸다
- 이때 맥미니의 I/O가 병목이 되었다 (예전에는 맥미니가 로드밸런서만을 담당했고 튜닝도 되어있어서 문제가 없었다)
- 지금의 맥미니는 LB(Load Balancer, 로드 밸런서)가 아니라 Ingress-nginx pod(파드)를 위한 Node Port Gate Way가 됐기 때문이다
- 쉽게 말해서 nginx를 담당하는 pod에 도달하기 위한 통로일 뿐 그 외 어떠한 역할도 없다


- 근데 이것을 해결하고자 하니 Ingress-nginx pod 갯수를 늘려야했다
- 근데? 지금 Ingress-nginx가 맥미니에서만 생기니까 늘려도 의미가 없음
- 하드웨어적으로 같은 노드에서 파드를 추가해봤자 병목은 해소가 안됨 -> 하드웨어 리소스 부족으로 인한 병목이라서
- 실제로 좀 공부해보니 현재의 병목은 L7(nginx)단계가 아니라 L4(커널/NIC/커넥션 단) 문제라서 단순히 맥미니 노드의 Ingress-nginx 파드를 늘린다고 해결되지 않음
- 쉽게 말해 나는 팔이 2개뿐이라, 팔이 10개 달린 옷을 입혀도 2개밖에 못 넣는다
4. 정확히 문제가 무엇일까?
- 쉽게 말하면 아래와 같다
1) nginx로 일할 애들이 부족하다? 이것은 파드 증가로 해결 가능
2) 커널의 NIC interrupt / TCP accept Queue 문제 etc? 이런 것들은 파드 증가로 해결 불가능
- 즉, 현상황에서 필요한 것은 CPU, RAM 따위가 아니다
- NIC(네트워크 인터페이스), TCP accept Queue, 커널 Interrupt 따위임
- 이런 것들은 파드를 늘린다고 늘어나는 것이 아니니 의미가 없다
- pod는 서버 자원을 공유해서 쓰고 있고, 현재 부족한 것은 하드웨어 리소스니까
- 이에 대한 증거가 K6 테스트에 떴던 에러들이다
'Cannot ssign requested address
- 이것들은 ephemered port 고갈, contact saturated, TCP Socket blocking overflow 오류 등
- 이것들은 곧 L4가 병목이라는 반증이다
5. 그럼 어떻게 해결할까?

- 이 부분을 해결하려면 K8s의 장점을 잘 살려야함
- 즉, 다른 노드(서버)들에도 Ingress-nginx 파드를 생성하는 것임
- 그렇게 되면 다른 노드들의 하드웨어 I/O를 가져다 쓸 수 있으니까
- 다만 각 서버는 하드웨어적으로 분리되어 있으니, 각 서버의 IP가 다를 수 있고, 여러 서버를 하나처럼 쓰기 위해서는 로드 밸런싱이 필요하다
- 여기서 쓰는 것이 MetalLB임
- MetalLB는 온프레미스(on-premise) 환경에서도 Kubernetes Service를 사용할 수 있게 해주는 로드밸런서 솔루션이다
6. 주의해야할 점
- 어찌됐건 맥미니는 컨트롤 플레인(Control Plane, 일종의 관리자)임
- 관리자가 최전선에서 같이 일하다가 죽으면 다 터지기 때문에 맥미니엔 필수 pod을 제외한 worker pod 생성을 막아둬야 함
- 필수는 etcd, kube-apiserver, controller, scheduler 등등 많음
- 그래서 보통 마스터 노드 taint라는 것을 설정함
- 이 상태에서 각 노드에 Ingress-nginx를 Daemonset으로 설정함 (DaemonSet은 아래에 간단히 설명)
- 각 노드의 NIC가 직접 트래픽을 받게함
- 즉, 요청을 받는 입구를 여러 개로 늘려서 대용량 트래픽에도 쉽게 터지지 않게 함
- 결국 요청받는 중계기의 성능을 높이고 튜닝을 통해 대용량 트래픽을 찍어누르던 것이 지난번의 nginx LB 기반 분산 시스템
- 모든 트래픽을 모든 노드(서버)에서 분산해서 받는 구조로 안정성을 꾀하는게 K8s 기반 분산시스템
- 이때 LB를 담당하는 'MetalLB'는 외부에 이 여러 개의 노드들이 하나의 IP를 가진 것처럼 보이게 함
- 좀 더 정확히는 VIP(Virtual IP)를 어느 노드로 보낼지 결정함
- 이후에 노드 내부에서 어떤 pod로 보낼지는 Ingress-nginx가 결정함
- MetalLB가 특정 노드를 기준으로 설치되는 것이었다면, 똑같이 NIC가 터졌겠지만, 가상 라우터라서 '모든 곳에 있으면서도 어디에도 종속되지 않는다'
- 물론 MetalLB가 모든 노드에 설치되어 있지만 특정 '노드에만' 종속되어 있진 않다는 의미
- 그러니 이전 분산시스템처럼 별도의 LB 서버는 필요 없다
- 더군다나 이런 식으로 구현하는게 아니라면 Scale Up 되었을 때, 하나의 서버처럼 유기적으로 동작할 수 없을 것이다
(nginx는 서버가 늘어날 때마다 수동으로 서버 IP를 추가해주고, 가중치가 있다면 또 계산해서 배분해야 한다)
7. DaemonSet이란 옵션에 대한 간단한 설명
- DaemonSet = speaker이며 서버 갯수만큼 생김
- Daemonset은 모든 노드에 1개씩 판드시 파드를 띄우는 방식
- pod의 스케줄링 방식 중 하나이다
- Speaker라고 모든 노드에 배치하게 하는 얘가 있음
- Speaker가 MetalLB에서는 DaemonSet임
8. 그래서 제 결론은요

- 결국 정리하면 기존의 nginx와 로드밸런스를 튜닝해서 얻은 LB 최적화 구조의 분산시스템은 K8s로 구현할 수 없었다
- 또한 Pod 생성을 서버마다 가중치를 둬서 어느쪽에 더 많이 생성할지 편차도 줄 수 없었음
- 그러나 기본적으로 네트워크나 설계된 구조에 영향을 주지 않으면서 병렬 구조로 수평 확장을 해서 순간적인 성능을 끌어올림으로써 안정성이 유지될 수 있다는 점은 굉장히 인상 깊었음
- nginx와 LB 튜닝은 결국 서버가 추가될 때마다 IP를 등록해주고 튜닝값을 매번 손봐야 한다는 단점이 있다
- 또한, LB가 설치된 중계기의 성능을 찍어누를만큼의 대용량 트래픽이 들어오면 터질 수도 있음
- 반면에 똑같은 조건(서버의 성능, 갯수)이라면 이 모든 노드(서버)들의 NIC를 하나로 묶어 쓸 수 있는 K8s의 안정성이 더 높다는 것이다
- 물론 nginx는 중계기 하나에만 돈을 쓰지만 K8s는 MetalLB로 묶은 모든 노드들의 성능에 돈을 써야하는게 단점일 수 있겠다
9. 이 다음에 시도해볼 부분은?

- 일단은 K8s의 장점을 최대로 끌어내볼 것
- metalLB를 설치해서 각 노드들에 Ingress-nginx를 띄우는 것
- 그리고 다시 K6 부하 테스트를 해보는 것이 다음 목표이다
'Infra > DevOps' 카테고리의 다른 글
| iptable-nft 환경에서 VPN 서버 구축하기 (feat. WireGuard) (0) | 2025.12.12 |
|---|---|
| Flannel이란? (feat. 쿠버네티스, Kubernetes, K8s) (2) | 2025.12.07 |
| 쿠버네티스(Kubernetes, K8s) 구축 과정에 마주한 에러들 (0) | 2025.12.03 |
| 홈서버 4대로 쿠버네티스(Kubernetes, K8s) 구축하기 (0) | 2025.12.01 |
| Prometheus, Out of Bound 해결방법 (feat. 서버 시간 통일 & TSDB 초기화) (0) | 2025.11.28 |