92. NodePort - K8s 서비스 외부 노출 라우팅

⚠️ 이 문서는 오직 쿠버네티스 클러스터 내부망에서만 통신할 수 있는 기본 서비스인 'ClusterIP'의 한계를 깨고, **클러스터를 구성하는 모든 물리적/가상 '워커 노드(서버)'의 똑같은 포트 번호(예: 30000~32767)에 구멍을 뚫어 외부 인터넷이나 사내망에서 내부 파드(Pod)로 직접 접속할 수 있는 길을 열어주는 중간 단계의 네트워킹 리소스인 'NodePort'**를 다룹니다.

핵심 인사이트 (3줄 요약)

  1. 본질: 쿠버네티스 클러스터의 벽에 뚫어놓은 수동 개구멍이다. 클러스터 안의 수십 대 서버 중 어느 서버의 공인 IP를 치고 들어오든, 뒤에 붙은 특정 포트 번호(예: :31234)만 같으면 쿠버네티스가 내부적으로 목적지 파드를 찾아 알아서 연결해 준다.
  2. 가치: 비싼 비용을 내고 클라우드 벤더의 전용 로드밸런서(AWS ALB 등)를 사지 않아도, 온프레미스 환경이나 개발/테스트 환경에서 가장 쉽고 빠르게 외부 접속을 테스트해 볼 수 있는 직관적인 방법이다.
  3. 기술 체계: NodePort는 독립적인 서비스가 아니라, 내부적으로 ClusterIP를 감싸안고 만들어진다. 외부(IP:NodePort) -> NodePort 기능 -> ClusterIP 가상 주소 -> 실제 Pod로 이어지는 깔때기 라우팅 구조를 갖는다.

Ⅰ. ClusterIP의 밀실과 세상 밖으로의 구멍

안전한 내선 전화망을 밖에서 걸 수 있게 확장해야 한다.

  1. ClusterIP의 폐쇄성:
    • nginx 웹 서버를 띄우고 기본 서비스(ClusterIP)를 붙였다. 가상 IP 10.96.1.5를 얻었다.
    • 내 PC 브라우저에서 http://10.96.1.5를 치면 절대 접속이 안 된다. 이 IP는 쿠버네티스 마을 안에서만 통하는 가짜 화폐(내부 IP)이기 때문이다.
  2. NodePort의 등장 (벽에 구멍 뚫기):
    • 서비스 타입을 NodePort로 변경해서 배포한다.
    • 쿠버네티스는 기존 ClusterIP 기능은 그대로 유지한 채, 클러스터에 묶여있는 모든 노드(워커 서버)의 껍데기30000~32767 사이의 꽤 큰 포트 번호(예: 31000)를 강제로 똑같이 뚫어버린다.
  3. 접속의 마법:
    • 노드 1번의 IP가 203.0.113.1이고, 노드 2번의 IP가 203.0.113.2라고 하자.
    • 고객이 브라우저에서 http://203.0.113.1:31000 을 치든, http://203.0.113.2:31000 을 치든 둘 다 똑같이 내 nginx 웹 서버 화면으로 쏙 연결된다. 어느 서버를 찔러도 상관없다.

📢 섹션 요약 비유: 쿠버네티스 마을(클러스터)은 높은 담장으로 둘러싸여 외부인이 절대 들어갈 수 없습니다(ClusterIP). NodePort는 마을을 둘러싼 모든 외벽의 정확히 '31000번 위치'에 쥐구멍을 똑같이 뚫어놓는 작업입니다. 외부인이 어느 벽면에 서 있든 31000번 구멍으로만 편지를 밀어 넣으면, 마을 안의 경비원(kube-proxy)이 그 편지를 낚아채어 목표물(Pod)에게 정확히 배달해 줍니다.


Ⅱ. NodePort의 내부 작동 원리 (Kube-proxy의 중계)

어떤 서버를 찔러도 똑같은 결과가 나오는 비밀은 보이지 않는 프록시에 있다.

  1. 상황 가정:
    • 노드 1번에는 nginx 파드가 떠 있지만, 노드 2번에는 파드가 하나도 안 떠 있다.
  2. Kube-proxy의 라우팅:
    • 고객이 하필 파드가 1개도 없는 '노드 2번 IP의 31000 포트'를 찌르고 들어왔다. 에러가 날까? 나지 않는다.
    • 모든 노드의 바닥에 깔려 숨어있는 **kube-proxy (네트워크 대리인)**가 이 트래픽을 가로챈다.
    • kube-proxy는 31000번으로 들어온 요청을 보고, "아, 이건 1번 노드에 떠 있는 nginx 파드로 가야 하는 거네?" 라며 클러스터 내부망을 통해 1번 노드로 휙 던져준다.
  3. 계층적 구조 (NodePort $\supset$ ClusterIP):
    • NodePort 서비스는 1층을 건너뛰고 세워진 게 아니다.
    • 외부에서 노드IP:NodePort 로 들어오면 $\rightarrow$ 내부적으로 ClusterIP 로 토스되고 $\rightarrow$ 다시 실제 Pod IP 로 라우팅되는 3단계 매트료시카 구조로 작동한다.

📢 섹션 요약 비유: 아파트(클러스터) 101동 1층과 102동 1층에 똑같은 무인 편지함(NodePort)을 놔뒀습니다. 실제 택배를 받을 사람(파드)은 101동에만 살고 있습니다. 우체부가 멍청하게 빈 동인 102동 편지함에 편지를 쑤셔 넣더라도, 숨어있던 아파트 통합 경비원(Kube-proxy)이 재빨리 나타나 "이건 101동 주민 거네"라며 지하 통로를 통해 101동으로 순간이동 시켜 배달을 완벽히 마쳐주는 기적의 릴레이 시스템입니다.


Ⅲ. 치명적인 단점과 상용 서비스에서의 한계

NodePort는 테스트용으론 최고지만, 실전에 투입하기엔 모양이 너무 빠진다.

  1. 못생긴 포트 번호 (포트 고갈):
    • 네이버나 구글에 접속할 때 naver.com:31245 라고 치고 들어가는 고객은 없다. 무조건 80이나 443 포트를 써야 하지만, NodePort는 OS 충돌을 막기 위해 강제로 30000번대 이상의 높은 포트만 열어주므로 상용 웹 서비스(B2C)에 바로 쓰기엔 실격이다.
  2. 로드밸런싱의 부재 (단일 장애점):
    • 고객이 노드 1번 IP로만 계속 들어오다 노드 1번 서버가 죽어버리면, 고객이 수동으로 노드 2번 IP로 주소를 바꿔 쳐야 한다. 외부에서 여러 노드의 IP를 공평하게 묶어주는 윗단의 우산(로드밸런서)이 없다.
  3. 보안 인바운드 방화벽의 복잡성:
    • 외부에서 접근하게 하려면 클러스터의 '모든 서버' 방화벽에서 30000번대 포트를 활짝 다 열어줘야 하므로(Open to Public), 보안팀(SecOps)이 극도로 싫어하는 끔찍한 아키텍처다.
    • 결론: 그래서 실무에서는 이 NodePort를 직접 고객에게 노출하지 않고, 이 앞에 AWS ALB 같은 **진짜 L4/L7 로드밸런서(LoadBalancer 타입이나 Ingress)**를 하나 더 붙여 포트를 80/443으로 예쁘게 포장하고 보안을 챙기는 구조로 덮어버린다.

📢 섹션 요약 비유: NodePort는 집 벽에 뚫어놓은 '개구멍'과 같습니다. 손님(고객)에게 대문(80 포트)이 아니라 "우리 집 벽면 31245번 위치에 있는 개구멍으로 기어들어 오세요"라고 하는 꼴이니 장사가 될 리 없습니다. 게다가 모든 벽면에 구멍을 다 뚫어놓으니 도둑(해커)이 들기 딱 좋습니다. 결국 이 개구멍들 앞에 커다랗고 멋진 '정식 고객 센터(LoadBalancer)' 건물을 하나 따로 세워 트래픽을 세련되게 받아야만 비즈니스가 완성됩니다.