[Kubernetes] 18. 서비스와 네트워크 (4편) - NodePort, ExternalIP, LoadBalancer, MetalLB

JIWON·2025년 7월 7일

Kubernetes

목록 보기
18/32
post-thumbnail

외부로 서비스 노출하기 (External Access)

앞서 다룬 ClusterIP 가 클러스터 내부 통신을 위한 것이었다면, 이번에는 클러스터 외부의 트래픽을 파드로 연결하는 방법들에 대해 알아본다. 쿠버네티스에서 서비스를 외부로 노출하는 방식은 크게 NodePort, ExternalIP, LoadBalancer가 있다.


1. NodePort

1) 개요

NodePort 서비스는 외부에서 접근할 수 있는 가장 기본적인 방식이다. 이름 그대로 모든 노드(Node)의 특정 포트(Port)를 개방하여 트래픽을 수신한다.

  • 동작 방식: 서비스 생성 시 포트를 할당하면, 클러스터의 모든 노드가 해당 포트(예: 30080)를 개방한다. 외부에서 어떤_노드의_IP:30080 으로 접근하든, 해당 트래픽은 서비스로 연결된 파드로 라우팅된다.

  • 내부 구조: 내부적으로는 0.0.0.0:<nodePort> 형태로 바인딩되어 모든 네트워크 인터페이스의 트래픽을 수신한다.

2) 작성법 및 포트 범위

  • type: NodePort로 설정한다.

  • spec.ports :

    • port: 서비스(ClusterIP) 내부에서 사용할 포트

    • targetPort: 실제 컨테이너가 사용하는 포트

    • nodePort: 외부 노드에서 개방할 포트 (생략 시 자동 할당)

  • 포트 범위: 기본적으로 30000 ~ 32767 범위 내에서 할당된다.

3) 실습: NodePort 생성

sample-nodeport.yaml

apiVersion: v1
kind: Service
metadata:
  name: sample-nodeport
spec:
  type: NodePort
  ports:
  - name: "http-port"
    protocol: "TCP"
    port: 8080        # ClusterIP 내부 포트
    targetPort: 80    # 파드 내부 포트
    nodePort: 30080   # 외부 노출 포트 (30000-32767)
  selector:
    app: sample-app

확인

# 리소스 생성
kubectl apply -f sample-nodeport.yaml

# 리소스 확인
kubectl get service sample-nodeport

NAME              TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
sample-nodeport   NodePort   10.96.160.113   <none>        8080:30080/TCP   10s

이제 클러스터 내의 아무 노드 IP나 잡고 30080 포트로 요청을 보내면 파드에 접속할 수 있다. NodePort 역시 내부 통신용 ClusterIP 를 자동으로 가지므로 내부 DNS 조회도 가능하다.

내부 DNS 주소 확인

kubectl run --image=amsy810/tools:v2.0 --restart=Never --rm -i testpod --command -- dig sample-nodeport.default.svc.cluster.local

2. ExternalIP

1) 개요

ExternalIP 는 별도의 서비스 타입(Type)이라기보다는, ClusterIP 등의 타입에서 사용할 수 있는 설정에 가깝다. 지정된 특정 노드의 IP 주소로 들어오는 트래픽만 허용하여 파드로 전달한다.

  • 특징: NodePort 가 모든 노드의 포트를 여는 것과 달리, 특정 IP(주로 특정 노드의 인터페이스)를 리스닝한다.

  • 권장 사항: 최근에는 관리의 복잡성과 가용성 문제로 인해 잘 사용되지 않으며, NodePortLoadBalancer 사용이 권장되는 추세이다.

2) 실습: ExternalIP 설정

type 은 기본값인 ClusterIP로 두고, externalIPs 필드를 추가한다.

sample-externalIP.yaml

apiVersion: v1
kind: Service
metadata:
  name: sample-externalip
spec:
  type: ClusterIP
  externalIPs:
  - 192.168.200.11 # 외부로 노출할 특정 노드의 IP
  ports:
  - name: "http-port"
    protocol: "TCP"
    port: 8080
    targetPort: 80
  selector:
    app: sample-app

외부에서는 externalIPs에 지정한 노드 IP(192.168.200.11)와 서비스 포트(8080)를 통해 파드에 접근할 수 있다.

이 경우 192.168.200.11:8080 으로 들어오는 트래픽만 처리가 가능하며, 해당 노드가 다운되면 서비스 접속이 불가능해진다.


3. LoadBalancer

1) 개요 및 특징

LoadBalancer 타입은 클라우드 환경(AWS, GCP, Azure 등)에서 가장 표준적으로 사용되는 외부 노출 방식이다.

  • 자동 프로비저닝: 서비스를 생성하면 클라우드 공급자(CSP)의 로드 밸런서(L4)가 자동으로 생성된다.

  • 동작 구조: 외부 로드 밸런서 -> 모든 노드의 NodePort -> 파드(Pod) 순서로 트래픽이 전달된다.

  • 고가용성: NodePortExternalIP 는 특정 노드에 장애가 생기면 접근이 제한될 수 있지만(클라이언트가 죽은 노드 IP를 보고 있을 경우), LoadBalancer 는 헬스 체크를 통해 살아있는 노드로만 트래픽을 보내므로 단일 장애점(SPOF) 문제를 해결한다.

2) 주의사항

  • 비용: 퍼블릭 클라우드에서 LoadBalancer 서비스를 생성할 때마다 별도의 로드 밸런서 리소스가 생성되므로 추가 비용이 과금된다.

  • IP 할당: 클라우드 환경이 아닌 경우(온프레미스 등), EXTERNAL-IP가 영원히 <pending> 상태로 남을 수 있다. 이를 해결하기 위해 MetalLB 같은 솔루션이 필요하다.

3) 작성법

apiVersion: v1
kind: Service
metadata:
  name: sample-lb
spec:
  type: LoadBalancer
  ports:
  - name: "http-port"
    protocol: "TCP"
    port: 8080         # 로드밸런서가 수신할 포트
    targetPort: 80     # 컨테이너의 포트
    nodePort: 30082    # 노드에서 열릴 포트
  selector:
    app: sample-app

4) 부가 설정

  • 가상 IP 정적 지정: 일부 환경에서는 spec.loadBalancerIP 속성을 통해 외부 IP를 정적으로 지정할 수 있지만, GKE(Google Kubernetes Engine) 등에서는 지원하지 않는다.

  • 방화벽 정책: spec.loadBalancerSourceRanges 필드에 CIDR 형식으로 IP 대역을 지정하여 접속을 허용할 소스 IP를 제한할 수 있다. 기본값은 0.0.0.0/0(전체 허용)이다. 더 세밀한 제어가 필요하면 NetworkPolicy 리소스를 사용한다.


4. MetalLB (온프레미스 LoadBalancer)

앞서 언급했듯, AWS나 GCP 같은 클라우드 환경이 아닌 베어메탈(Bare-metal)이나 온프레미스 환경에서는 LoadBalancer 타입의 서비스를 만들어도 외부 IP를 할당해 줄 로드 밸런서가 없다. 이 문제를 해결해 주는 오픈소스 프로젝트가 MetalLB이다.

1) MetalLB의 특징

MetalLB는 쿠버네티스 클러스터 내에서 소프트웨어적으로 로드 밸런서 역할을 수행한다.

  • L2 모드 (ARP): 동일한 서브넷 내에서 ARP(Address Resolution Protocol)를 사용하여 "이 IP는 내가 처리하겠다"고 알리는 방식. 소규모 클러스터나 홈랩에 적합하다.

  • BGP 모드: 라우터와 BGP 프로토콜로 경로 정보를 교환하는 방식. 대규모 네트워크에 적합하다.

  • External IP 전파: 데몬셋(DaemonSet)으로 speaker라는 파드를 각 노드에 생성하여 External IP를 전파한다.

  • 지원 환경: VMware, VirtualBox 등 가상 환경이나 Ubuntu + kubeadm으로 구성된 클러스터에 매우 적합하다. 단, AWS(EKS), GCP(GKE) 등 대부분의 퍼블릭 클라우드 환경은 자체 로드밸런서를 사용하므로 MetalLB를 지원하지 않는다.

2) 실습: MetalLB 설치 및 구성

① MetalLB 설치

매니페스트를 이용해 MetalLB 컨트롤러와 스피커(Speaker) 파드를 설치한다.

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.10/config/manifests/metallb-native.yaml

설치 후 metallb-system 네임스페이스의 파드들이 모두 Running 상태인지 확인한다.

② IP 주소 풀(Pool) 설정 (IPAddressPool)

LoadBalancer 가 사용할 수 있는 IP 대역을 지정한다. (자신의 네트워크 환경에 맞는 유휴 IP 대역이어야 한다.)

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: my-ippool
  namespace: metallb-system
spec:
  addresses:
  - 192.168.11.100-192.168.11.102  # 할당 가능한 IP 범위

③ L2 광고 설정 (L2Advertisement)

위에서 설정한 IP 풀을 네트워크에 알리기(Advertise) 위한 설정이다.

apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: my-l2-advertise
  namespace: metallb-system
spec:
  ipAddressPools:
  - my-ippool

④ LoadBalancer 서비스 생성 및 확인

MetalLB 설정이 완료된 상태에서 type: LoadBalancer 서비스를 생성하면, pending 상태였던 EXTERNAL-IP 가 지정한 풀 내의 IP(예: 192.168.11.100)로 즉시 할당된다.

$ kubectl get svc sample-lb
NAME        TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)
sample-lb   LoadBalancer   10.107.243.177   192.168.11.100   8080:30082/TCP

이제 외부(같은 네트워크 대역)에서 curl 192.168.11.100:8080 명령어로 접속하면, 트래픽이 로드 밸런싱되어 파드로 전달되는 것을 확인할 수 있다.

0개의 댓글