본문 바로가기
Cloud Native/Kubernetes

2. Service - ClusterIP, NodePort, LoadBalancer

by jys275 2026. 1. 16.

실무에서 서비스(Service)를 바라보는 관점은 딱 하나다. "변하는 것(Pod IP) 뒤에 변하지 않는 것(Service IP)을 세우는 것"이다. 클라우드 네이티브 환경에서 이 개념을 모르면 시스템은 첫날부터 무너진다. 

 


 

 

1. 서비스가 존재하는 근본적인 이유: IP의 신뢰성

  • 파드의 한계: 파드는 장애나 스케일링 시 언제든 죽고 다시 살아난다. 이때마다 IP는 계속 변한다.
  • 서비스(Service)의 역할: 사용자가 직접 삭제하지 않는 한 변하지 않는 고정 IP(ClusterIP)를 제공한다.
    • 즉, 이렇게 파드와 서비스는 클러스터 내에서 접근할 수 있는 IP가 있는데, 굳이 서비스를 달아서 IP를 제공하는게 위의 이유에서 있는 거다.
    • 그리고 위 사진처럼 ClusterIP(기본), NodePort, Load Balancer 세가지 종류로 파드의 접근을 도와주는 방식이 나뉘는게 서비스이다.
  • 로드 밸런싱: 서비스 하나에 여러 파드를 연결하면, 서비스가 트래픽을 알아서 분산해준다.
  •  

 

2. 상황별 서비스 타입 (Service Types)

"내가 설계하는 시스템의 노출 범위에 따라 타입을 결정해라."

  • ClusterIP (기본값)
    • 클러스터 내부에서만 접근 가능하다.
      • 파드에 있는 IP와 특성이 똑같지. 그래서 Cluster내 모든 오브젝트가 접근이 가능해서 External에서는 불가능한게 보인다.
    • 파드 주소인 10.16.1.2와 10.16.1.3이 엔드포인트 리소스에 기록되는 실제 IP들이다.
      • 더보기
        # 다른 예시
        kubectl describe service kubernetes 출력 결과

        Name:                     kubernetes
        Namespace:                default
        Labels:                   component=apiserver
                                  provider=kubernetes
        Annotations:              
        Selector:                 
        Type:                     ClusterIP
        IP Family Policy:         SingleStack
        IP Families:              IPv4
        IP:                       10.43.0.1                   # Service (=ClusterIP)
        IPs:                      10.43.0.1
        Port:                     https  443/TCP                   # Service 포트
        TargetPort:               6443/TCP                    # Pod 포트
        Endpoints:                192.168.20.180:6443        # Pod의 주소와 포트
        Session Affinity:         None
        Internal Traffic Policy:  Cluster
        Events:                   
    • 여러개의 파드들이 연결될 수 있는데 Service가 알아서 모든 Pod들에게 트래픽을 분산시켜준다.
      • YAML 파일을 보면 selector, label의 매칭이 이루어졌는데, 이래야 분산이 되는거다.
      • port 9000에서 targetport 8080으로 연결이 된다는 의미이다.
    • type을 생략하면 자동으로 이 타입이 지정된다.
  •  인가된 관리자(운영자)의 디버깅이나 내부 시스템 간 통신(DB 등)에 사용한다.
    • 보다시피 ClusterIP는 외부에서 접근할 수 없고, 클러스터 내에서만 사용하기 때문이다.

ClusterIP를 사용하려면 Pod에 그럼 Label을 필수 지정해야하나?

파드 자체만 실행할 때는 라벨이 없어도 에러가 나지 않는다. 하지만 라벨이 없으면 서비스(Service)가 해당 파드를 찾을 수 있는 방법이 없는 것이다. 서비스는 오직 selector에 명시된 라벨을 가진 파드들만 골라서 트래픽을 보내기 때문이다.

  • "Loose Coupling(느슨한 결합)"의 핵심
    • 우리가 파드에 라벨을 미리 설계하는 이유는 파드와 서비스를 느슨하게 연결하기 위함이다.
      • 파드의 IP는 언제든 변한다.
      • 하지만 서비스는 특정 라벨(예: app: pod)을 가진 파드라면 IP가 무엇이든, 몇 개가 떠 있든 상관없이 고정된 통로를 유지해 주는 것이다.
      • 따라서 설계 단계에서 "이 파드들은 frontend 그룹이다"라고 라벨을 정의하고, 서비스가 그 라벨을 바라보게 만드는 것이 쿠버네티스 네트워킹의 기초다.

 

  • NodePort
    • 서비스는 기본적으로 클러스터 IP가 할당됨(171.96.10.17).
    • 큰 특징은, 클러스터에 연결되어 있는 모든 노드에게 특정 똑같은 포트(30000~32767)가 할당돼서 개방한다.
      • nodePort: 30000으로 지정한걸 볼 수 있다. (지정안하면 30000~32767 중 하나로 자동지정)
      • 즉, 웹으로부터 어느 노드던 간에 연결된 하나의 Service로 연결이 되는거다.
      • 그럼 또 서비스는 자신한테 연결되어있는 파드로 트래픽을 다시 전달해주는걸 그림에서 확인가능. 그냥 자신한테 등록된거에 다 전달하는거
        • 즉, Node1로 들어온 External 트래픽도 Node2 파드로 트래픽이 전달될 수 있다는 거임.
        • 하지만, externalTrafficPolicy: Local 설정을 쓰면 트래픽이 들어온 노드에 있는 파드로만 전달되어 홉(Hop)을 줄일 수 있다.
  • 특징이 물리적인 호스트(Node1, 2)의 IP(192.168.56.31)를 통하여 Pod에 접근할 수가 있는 거잖아.
    • 즉, 호스트 IP는 보안적으로 내부망에서만 접근할 수 있게 네트워크를 구성할 것.
    • 그래서 NodePort는 "클러스터 밖에는 있지만", 그래도 내부망 안에서 접근해야할 때 쓴다.
      • 혹은 일시적 외부 연동용, 데모용으로 보여줄 때 잠깐 뚫어놓고 쓸 수 있음

 

  • LoadBalancer
    • 잘 보면, NodePort의 성격을 그대로 가지고 있는 것을 볼 수 있다.
      • 근데, 다르게 실제 운영 환경에서 외부 서비스를 노출하는 표준이다.
    • CSP(AWS, GCP, Azure 등)의 로드 밸런서와 연동되어 있어야. 즉, 플러그인이 설치되어 있어야 외부 접속용 공인 IP를 할당받는다.
    • NodePort와 ClusterIP의 기능을 모두 포함하고 있다.

 

 

3. YAML 작성 시 주의사항 (연결의 핵심)

  • Selector와 Label의 매칭: 서비스의 spec.selector와 파드의 metadata.labels가 정확히 일치해야 트래픽이 전달된다. 이 이름이 단 한 글자라도 틀리면 서비스는 '빈 껍데기'가 된다.
  • Port vs TargetPort: port는 서비스가 사용하는 포트이고, targetPort는 파드 내부 컨테이너가 열어둔 포트다.

 

 

💡꼬리 질문

Q: "서비스의 Selector와 파드의 Label이 일치하는데도 접속이 안 된다면, 가장 먼저 확인해야 할 '추상화된 엔드포인트' 리소스의 이름은 무엇인가?"

 

A: 정답은 Endpoints (또는 EndpointSlice) 오브젝트다.

쿠버네티스 서비스는 논리적인 개념일 뿐이다. 실제로 서비스가 트래픽을 보낼 파드들의 IP 목록을 관리하는 별도의 오브젝트가 바로 Endpoints다.

  1. 확인 방법: kubectl get endpoints [서비스명] 명령어
  2. 해결 실마리: 만약 ENDPOINTS 항목이 <none>이거나 비어 있다면, 서비스의 Selector와 파드의 Label이 매칭되지 않았거나 파드가 Running 상태가 아님을 의미한다.

네트워크 트러블슈팅의 핵심은 서비스를 보기 전에 엔드포인트부터 확인하는 것이다. 명시.

 

 


 

 

쿠버네티스 네트워킹은 결국 'IP의 변화를 고정된 포트로 묶어주는 과정'일 뿐이다. 실습 스크립트와 자료를 바탕으로 명령어, 포트, IP의 흐름에만 집중해보자.

 

 

서비스 실습 핵심 요약 (명령어·포트·IP 중심)

 

 

1. ClusterIP: 클러스터 내부의 고정 대문

apiVersion: v1
kind: Pod
metadata:
  name: pod-1
  labels:
     app: pod
spec:
  nodeSelector:
    kubernetes.io/hostname: k8s-worker1
  containers:
  - name: container
    image: kubetm/app
    ports:
    - containerPort: 8080
apiVersion: v1
kind: Service
metadata:
  name: svc-1
spec:
  selector:
    app: pod
  ports:
  - port: 9000
    targetPort: 8080

인프런_대세는 쿠버네티스

  • IP 특징: 서비스 생성 시 알아서 할당되는 고정된 내부 IP(171.96.10.17) = ClusterIP 다. 파드가 죽고 살아나서 파드 IP가 변해도 이 IP는 변하지 않는다.
  • 포트 흐름: Service IP:9000 -> Pod Port:8080. 서비스의 9000번 포트로 들어가면 파드의 8080번으로 배달된다.
  • 접속시 실행 명령어: curl <ClusterIP>:9000/hostname
  • 핵심 포인트: 외부(클러스터 밖)에서는 접근 불가하며, 여러 파드에 트래픽을 랜덤하게 분산한다.

 

2. NodePort: 외부(내부망)에서 노드 IP로 진입

apiVersion: v1
kind: Service
metadata:
  name: svc-2
spec:
  selector:
    app: pod
  ports:
  - port: 9000
    targetPort: 8080
    nodePort: 30001
  type: NodePort

인프런_대세는 쿠버네티스

  • IP 특징: 실제 워커 노드의 IP(예: 192.168.56.31, 192.168.56.32)를 사용한다.
  • 포트 범위: 30000 ~ 32767 사이에서 할당된다. 실습에서는 30001번을 사용했다.
  • 포트 흐름: Node IP:30001 -> ClusterIP:9000 -> Pod Port:8080.
  • 접속시 실행 명령어: curl 192.168.56.31:30001/hostname (내 PC의 CMD에서 호출 가능)
  • 고급 설정: externalTrafficPolicy: Local 설정 시, 접속한 노드에 파드가 없으면 트래픽을 버린다. 불필요한 노드 간 홉(Hop)을 줄일 때 쓴다.

 

3. LoadBalancer: 클라우드 기반의 공인 IP 노출

apiVersion: v1
kind: Service
metadata:
  name: svc-4
spec:
  selector:
    app: pod
  ports:
  - port: 9000
    targetPort: 8080
  type: LoadBalancer

인프런_대세는 쿠버네티스

  • IP 특징: CSP(AWS, GCP 등)가 할당해주는 External IP(10.2.2.1)를 사용한다.

  • 플러그인이 없으면 위와같이 상태가 pending으로 고정되어 외부 IP가 나오지 않는다.
    • 포트 흐름: External IP -> NodePort -> Service Port -> Target Port.
    • 접속시 실행 명령어: kubectl get service svc-3 (EXTERNAL-IP 항목 확인용)
  • 핵심 포인트: 운영 환경에서 외부 서비스를 노출할 때 사용하는 가장 안정적인 방식이다.

 

 

💡 꼬리 질문

Q: "NodePort 서비스 생성 시 YAML에 nodePort 번호를 명시하지 않으면 어떻게 될까? 그리고 실무에서 수백 개의 서비스를 운영할 때 포트 충돌을 막으려면 어떤 전략을 써야 할까?"

 

1. 번호 미지정 시의 동작

  • YAML에서 nodePort를 생략하면 쿠버네티스가 30000~32767 범위 내에서 사용 가능한 포트를 랜덤하게 자동으로 할당한다. 굳이 번호를 지정하지 않아도 서비스는 정상 동작한다.

2. 실무에서의 관리 전략

  • Ingress 활용: 실무에서는 수백 개의 NodePort를 일일이 개방하지 않는다. 대신 단일 진입점인 Ingress를 앞단에 두고, 도메인 주소(L7) 기반으로 트래픽을 분산하여 포트 관리의 복잡성을 해결한다.
  • 자동 할당 권장: 특정 포트를 고수해야 하는 사유가 없다면 쿠버네티스의 자동 할당 기능을 활용하여 중복 충돌 리스크를 최소화하는 것이 정석이다.

 

 

위 학습용 정리 내용 및 사진 자료는 "인프런_대세는 쿠버네티스(https://inf.run/Lv5RV)" 강의를 소스로 작성하였습니다.