본문으로 건너뛰기
김신건의 로그

[K8s] Service: ClusterIP / NodePort / LoadBalancer / ExternalName

· 수정 · 📖 약 2분 · 653자/단어 #kubernetes #service #network #k8s
Kubernetes Service, K8s Service, ClusterIP, NodePort, LoadBalancer, ExternalName, Headless Service, kube-proxy, iptables, IPVS

정의

Service = Pod 집합에 안정 가상 IP + DNS 부여. Pod 가 죽고 다시 만들어져도 Service IP 는 그대로.

4가지 타입

flowchart TB
    Q{Service 종류}
    Q --> CIP["ClusterIP<br/>(기본)<br/>클러스터 안에서만"]
    Q --> NP[NodePort<br/>각 노드의 포트 노출]
    Q --> LB[LoadBalancer<br/>클라우드 LB 자동 생성]
    Q --> EN[ExternalName<br/>외부 DNS 별칭]

1. ClusterIP (기본)

apiVersion: v1
kind: Service
metadata:
  name: api
spec:
  type: ClusterIP
  selector: { app: api }
  ports:
    - port: 80
      targetPort: 8080
  • 클러스터 안에서만 접근.
  • 다른 pod 가 http://api:80 로 호출.
  • DNS: <service>.<namespace>.svc.cluster.local.

2. NodePort

spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 8080
      nodePort: 30080   # 옵션
  • 모든 노드의 30000-32767 포트 에서 접근.
  • http://<any-node>:30080.
  • 보통 개발용. 프로덕션은 LoadBalancer 또는 Ingress.

3. LoadBalancer

spec:
  type: LoadBalancer
  selector: { app: api }
  ports: [{ port: 80, targetPort: 8080 }]
  • 클라우드 (AWS, GCP) 가 자동으로 LB 생성 + 외부 IP.
  • AWS = ALB / NLB.
  • Service 당 LB 하나 → 많으면 비싸다. Ingress 가 대안.

4. ExternalName

spec:
  type: ExternalName
  externalName: api.external.com
  • DNS CNAME 처럼 외부 호스트 별칭.
  • 기존 외부 service 와 통합 용.

Headless Service

spec:
  clusterIP: None    # ← Headless
  • Service IP 없음.
  • DNS 가 모든 pod IP 직접 반환.
  • StatefulSet 의 peer discovery 에 필수.

DNS 와 Service Discovery

nslookup api
→ api.default.svc.cluster.local
→ 10.96.0.42 (ClusterIP)

nslookup api-headless
→ 10.244.0.5  (pod-1)
→ 10.244.0.6  (pod-2)
→ 10.244.0.7  (pod-3)

내부 동작: kube-proxy

flowchart LR
    Client[Client pod] -->|Service IP| KP["kube-proxy<br/>(node)"]
    KP -->|iptables / IPVS rule| P1[pod 1]
    KP -->|iptables / IPVS rule| P2[pod 2]
    KP -->|iptables / IPVS rule| P3[pod 3]
모드특징
iptables (기본)nat 규칙. 수천 Service 까지 OK
IPVS더 빠름, 더 큰 규모
nftables (1.31+)iptables 대체, 더 빠름

트래픽 분배

Service → endpoints (Pod IP 목록)
kube-proxy → random pick (iptables) 또는 알고리즘 (IPVS)

L4 round-robin. 세션 sticky 가 필요하면 service.spec.sessionAffinity: ClientIP.

Service 와 Endpoints

kubectl get endpoints api
NAME   ENDPOINTS                                AGE
api    10.244.0.5:8080,10.244.0.6:8080,...      5m
  • Service = 추상.
  • Endpoints = 실제 pod IP.
  • Pod 의 readiness 가 OK 인 것만 endpoint 에 포함.

EndpointSlice (1.21+)

큰 클러스터에서 Endpoints 의 확장. 1000+ pod 의 Service 에 효율적.

흔한 함정

WARNING

  1. LoadBalancer 남발 = AWS 1 LB = 시간당 비용 + LCU. Ingress 로 통합 권장.
  2. Service IP 변경 시도 = ClusterIP 는 immutable. 변경하려면 삭제 + 재생성.
  3. Headless 잘못 사용 = LB 동작 없음. StatefulSet 만.
  4. selector label 오타 = endpoints 0개. Service 동작 안 함.

Multi-Port Service

한 Service 에서 여러 포트 노출 시 이름 필수.

spec:
  type: ClusterIP
  selector: { app: api }
  ports:
    - name: http
      port: 80
      targetPort: 8080
    - name: grpc
      port: 9090
      targetPort: 9090
    - name: metrics
      port: 9100
      targetPort: 9100

Port Naming 컨벤션

Ingress, Istio, Prometheus 가 이름으로 프로토콜 자동 감지.

Port 이름프로토콜
httpHTTP/1.1
httpsHTTPS/TLS
grpcgRPC
http2HTTP/2 평문
metricsPrometheus scrape

Session Affinity 상세

spec:
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 3600

같은 ClientIP 의 요청을 동일 Pod 으로 고정. None (기본) = 무작위. L7 쿠키 sticky 는 Ingress 레벨.

External Traffic Policy

외부 트래픽 (NodePort / LoadBalancer) 의 라우팅 전략.

spec:
  type: LoadBalancer
  externalTrafficPolicy: Local
Policy동작트레이드오프
Cluster모든 노드 경유, SNAT균등 분배, 클라이언트 IP 유실
Local같은 노드 Pod 만소스 IP 보존, Pod 없는 노드에서 드롭

Service + NetworkPolicy 연계

flowchart LR
    FE["frontend Pod"] -->|"port 80"| SVC["api Service"]
    SVC --> API["api Pod"]
    NP["NetworkPolicy"] -.->|"허용 제어"| API

NetworkPolicy 는 Service IP 가 아니라 최종 Pod IP 에 적용. Service 는 변환 중간점.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-allow-frontend
spec:
  podSelector:
    matchLabels:
      app: api
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend
      ports:
        - port: 8080

Service vs Ingress 비교

flowchart TB
    Ext["외부 트래픽"]
    Ext -->|"LoadBalancer (L4)"| SVC["Service (LB)"]
    Ext -->|"HTTP (L7)"| ING["Ingress Controller"]
    ING -->|"host/path 라우팅"| S1["Service A"]
    ING --> S2["Service B"]
    SVC --> P1["Pod"]
항목Service LoadBalancerIngress
레이어L4L7
LB 개수Service 당 1개1개로 N 서비스
비용높음낮음
기능포트 포워딩호스트/경로 라우팅, TLS, 재작성

트러블슈팅

# Endpoint 확인 (0 이면 selector 불일치)
kubectl get endpoints <svc-name>

# Pod label 확인
kubectl get pods --show-labels -l app=<name>

# Service 상세 (Selector, Port, Endpoints 포함)
kubectl describe service <svc-name>

# DNS 조회 (파드 내부에서)
kubectl exec -it <pod> -- nslookup <svc>.<ns>.svc.cluster.local

# ClusterIP 직접 접근 테스트
kubectl exec -it <pod> -- curl http://<cluster-ip>:<port>

TIP

Endpoints 가 0 이면 selector label 불일치. kubectl describe serviceSelector 와 Pod 의 실제 label 을 비교.

관련 위키

이 글의 용어 (7개)
[K8s] Ingress: L7 라우팅, TLS termination, Gateway APIkubernetes
정의 Ingress = 클러스터 외부 HTTP/HTTPS 트래픽 → 내부 Service 라우팅. L7 LB 역할. Service 의 LoadBalancer 다수 대안. [!IMP…
[K8s] NetworkPolicy: pod 간 네트워크 차단kubernetes
정의 NetworkPolicy = pod 간 허용된 트래픽만 통과. 없으면 모든 pod ↔ pod 가 허용 (기본 open). [!IMPORTANT] NetworkPolicy 는…
[K8s] Pod: 컨테이너의 최소 단위, sidecar, lifecyclekubernetes
정의 Pod = K8s 의 가장 작은 배포 단위. 1개 이상의 컨테이너 + 공유 네트워크 + 공유 스토리지. [!IMPORTANT] Pod 는 컨테이너의 wrapping 이 아니…
[K8s] StatefulSet: 순서 보장, 고유 ID, 영속 스토리지kubernetes
정의 StatefulSet = 상태 있는 워크로드를 위한 컨트롤러. Deployment 와의 차이: | 항목 | Deployment | StatefulSet | |---|---|…
[Kubernetes] Service Mesh (Istio, Linkerd, Cilium)kubernetes
정의 Service Mesh 는 마이크로서비스 간 통신에 L7 정책, mTLS 암호화, 트래픽 관리, 관측성 을 제공하는 인프라 계층입니다. 앱 코드를 바꾸지 않고 프록시 (si…
[Network] CORS: Same-Origin Policy, preflight, credentialsnetwork
정의 CORS (Cross-Origin Resource Sharing) 는 Same-Origin Policy (SOP) 의 완화 메커니즘. 브라우저가 origin 이 다른 리소스…
[Network] Load Balancer: L4 vs L7, 알고리즘, sticky sessionnetwork
정의 Load Balancer 는 트래픽을 여러 백엔드로 분산 하는 인프라. 수평 확장 + 가용성 + 무중단 배포 의 토대. L4 vs L7 | 구분 | L4 (Transport…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기