쿠버네티스 마스터 노트 시리즈 4편. Pod IP가 변경되는 환경에서 Service가 안정적 진입점 역할을 하는 메커니즘, ClusterIP/NodePort/LoadBalancer/ExternalName 4 타입의 결정적 차이, Endpoints 자동 갱신, CoreDNS의 서비스 디스커버리, Ingress가 L7 라우팅으로 외부 노출의 표준이 된 이유, Service Mesh 등장 배경까지.
이 글은 쿠버네티스 마스터 노트 시리즈의 네 번째 편입니다. 3편(Workloads)까지 Pod 생성·관리였다면, 이번엔 그 Pod에 어떻게 접근하나 — Services·Networking·Ingress.
Pod IP는 항상 바뀝니다. 다음 Pod에 접속하려면 어떻게? Service가 그 답. 외부에서 들어오려면? NodePort·LoadBalancer·Ingress 3종.
처음 Services가 어렵게 느껴지는 이유
처음 이 단원이 어렵게 느껴지는 이유는 두 가지예요. 첫째, 타입이 4개라 헷갈립니다. ClusterIP·NodePort·LoadBalancer·ExternalName — 어느 게 어디? 둘째, Ingress와 Service의 관계가 막연합니다.
해결법은 한 가지예요. "Service = 안정적 IP·DNS / Ingress = HTTP 라우팅" 한 줄. Service는 Pod 다운돼도 IP 안 바뀜, Ingress는 도메인·경로별 라우팅. 둘 보완.
왜 Service가 필요한가
Pod nginx-1 → IP 10.244.0.5 (Pod 다운 시 사라짐)
Pod nginx-2 → IP 10.244.0.6
Pod nginx-3 → IP 10.244.0.7
다른 Pod에서 nginx 접근 — 어느 IP?
문제:
- Pod IP는 일회용
- Pod 수 변경 시 IP도 변경
- 클라이언트가 모든 IP 추적 X
Service가 답
Service "nginx" → 안정적 IP (예: 10.96.10.5)
→ 셀렉터로 매칭된 Pod들에 자동 라우팅
→ Pod 다운·교체에도 Service IP 그대로
여기서 정말 중요한 시험 함정 — Service = 가상 IP + 자동 로드밸런서. 클라이언트는 Service IP만 알면 됨. Pod 변경 자동 추적.
ClusterIP — 클러스터 내부 (기본)
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
app: nginx
ports:
- port: 80 # Service 포트
targetPort: 80 # Pod 포트
type: ClusterIP # 기본값 (생략 가능)
kubectl get svc
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
# nginx-svc ClusterIP 10.96.10.5 <none> 80/TCP
# 클러스터 안 다른 Pod에서
curl http://nginx-svc/ # DNS 자동 (CoreDNS)
curl http://10.96.10.5/ # 직접 IP
특징:
- 클러스터 내부에서만 접근 가능
- 외부 노출 X
- DNS 자동 (
<svc>.<ns>.svc.cluster.local)
여기서 시험 함정이 하나 있어요. ClusterIP는 외부 접근 X. Pod에서 또는 kubectl port-forward로만. 외부 노출은 NodePort·LoadBalancer·Ingress.
NodePort — 외부 단순 노출
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 30080 # 30000~32767 범위 (선택, 자동 할당도 가능)
# 모든 노드의 30080 포트로 접근
curl http://<node-ip>:30080
특징:
- 모든 노드의 같은 포트 열림
- 노드 IP를 알아야 함
- 운영 환경엔 부적합 (노드 IP 노출)
용도 — 개발·테스트만. 운영은 LoadBalancer 또는 Ingress.
LoadBalancer — 클라우드 로드밸런서
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 80
클라우드 환경 (AWS·GCP·Azure)에서 자동 LB 프로비저닝.
kubectl get svc
# NAME TYPE EXTERNAL-IP PORT(S)
# nginx-svc LoadBalancer 34.123.45.67 80:30080/TCP
curl http://34.123.45.67/
특징:
- 클라우드 LB 자동 생성 (AWS ELB·GCP Load Balancer)
- 공개 IP 자동 할당
- 하나의 LB = 1개 Service (비쌈)
여기서 정말 중요한 시험 함정 — LoadBalancer는 클라우드 환경에서만. 온프레미스·로컬은 MetalLB 같은 추가 도구 필요.
ExternalName — DNS 별칭
spec:
type: ExternalName
externalName: api.example.com
클러스터 내부 DNS 조회 → 외부 도메인으로 리다이렉트. 외부 서비스를 내부 이름으로.
Endpoints — Service의 비밀
각 Service에는 Endpoints 객체 자동 생성:
kubectl get endpoints nginx-svc
# NAME ENDPOINTS AGE
# nginx-svc 10.244.0.5:80,10.244.0.6:80,10.244.0.7:80
Endpoints = 셀렉터에 매칭된 Pod IP 목록. 컨트롤러가 자동 갱신.
여기서 시험 함정이 하나 있어요. Pod이 Ready 아니면 Endpoints에 X. Readiness Probe 실패 = Service 트래픽 X. 7편에서 자세히.
CoreDNS — 서비스 디스커버리
K8s 클러스터 안 자동 DNS:
Service: my-svc.my-namespace.svc.cluster.local
또는: my-svc (같은 namespace)
또는: my-svc.my-namespace
# Pod 안에서
nslookup nginx-svc
# Server: 10.96.0.10
# Address: 10.96.0.10#53
#
# Name: nginx-svc.default.svc.cluster.local
# Address: 10.96.10.5
CoreDNS = kube-system namespace의 DaemonSet (또는 Deployment).
Ingress — L7 HTTP 라우팅
여러 Service를 도메인·경로별 라우팅.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
tls:
- hosts: [example.com]
secretName: example-tls
rules:
- host: example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-svc
port:
number: 80
- path: /web
pathType: Prefix
backend:
service:
name: web-svc
port:
number: 80
흐름:
example.com/api → api-svc → API Pod
example.com/web → web-svc → Web Pod
Ingress Controller — 실제 처리자
Ingress 리소스만 정의하면 안 동작. Ingress Controller가 트래픽 처리:
| Controller | 설명 |
|---|---|
| NGINX Ingress | 가장 일반적 |
| Traefik | 자동 설정, 모던 |
| HAProxy | 고성능 |
| AWS ALB | AWS 환경 |
| Istio Gateway | Service Mesh와 함께 |
# NGINX Ingress 설치 (Helm)
helm install ingress-nginx ingress-nginx/ingress-nginx
여기서 정말 중요한 시험 함정 — Ingress 리소스 ≠ Ingress Controller. 리소스만 정의해도 Controller 없으면 안 됨. EKS·GKE는 자체 Controller 자동 설치.
Ingress vs LoadBalancer
| 측면 | LoadBalancer | Ingress |
|---|---|---|
| 계층 | L4 (TCP·UDP) | L7 (HTTP) |
| 라우팅 | 단일 Service | 여러 Service (path·host) |
| 비용 | 1 Service = 1 LB (비쌈) | 1 LB = 여러 Service |
| TLS | 클라우드 LB | Ingress 자체 |
| 사용처 | TCP·gRPC | HTTP API·웹 |
여기서 정말 중요한 시험 함정 — 다수 HTTP 서비스 = Ingress 권장 (비용·관리 효율). 단일 TCP·gRPC = LoadBalancer.
Pod 네트워크 — CNI
각 Pod이 자기 IP를 갖는 메커니즘.
[Node 1]
Pod 10.244.1.5
Pod 10.244.1.6
[Node 2]
Pod 10.244.2.7
Pod 10.244.2.8
각 Pod이 직접 통신 가능 (NAT X)
CNI 플러그인:
- Calico — BGP 기반, NetworkPolicy 강력
- Flannel — 단순, 입문용
- Cilium — eBPF 기반, 최신
- Weave — 자동 암호화
- AWS VPC CNI — AWS 네이티브
여기서 시험 함정이 하나 있어요. CNI 선택은 클러스터 생성 시 결정. 나중에 변경 매우 어려움. 운영 환경 = Calico 또는 Cilium 권장.
NetworkPolicy — 방화벽 (8편 미리보기)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-policy
spec:
podSelector:
matchLabels:
app: db
ingress:
- from:
- podSelector:
matchLabels:
app: api
ports:
- port: 5432
이 db Pod엔 api 라벨 Pod만 5432 포트 접근. 8편에서 자세히.
Service Mesh — 한 단계 더
복잡한 마이크로서비스 환경:
- 서비스 간 mTLS
- 정밀한 트래픽 제어 (canary·트래픽 미러링)
- 분산 추적·모니터링
- 회로 차단·재시도
도구:
- Istio
- Linkerd
- Consul Connect
- AWS App Mesh
여기서 시험 함정이 하나 있어요. Service Mesh는 복잡도 ↑. 작은 클러스터엔 over-engineering. 마이크로서비스 10+ 또는 보안 요구 강할 때.
디버깅
# Service 상태
kubectl get svc
kubectl describe svc <name>
# Endpoints 확인
kubectl get endpoints <name>
# Pod에서 Service 호출
kubectl run -it --rm debug --image=busybox -- wget -O- http://my-svc
# DNS 확인
kubectl run -it --rm debug --image=busybox -- nslookup my-svc
# Ingress 상태
kubectl get ingress
kubectl describe ingress <name>
# Ingress Controller 로그
kubectl logs -n ingress-nginx deploy/ingress-nginx-controller
시험 직전 한 번 더 — 자주 헷갈리는 함정 모음
여기까지가 4편의 핵심입니다. 시험 직전 또는 실무에서 헷갈릴 때 다시 펼쳐 볼 수 있게 압축 노트로 마무리할게요.
- Service = 안정적 IP + 자동 LB
- Pod IP는 일회용 → Service로 추상화
- 4 타입 — ClusterIP (기본·내부) / NodePort (개발) / LoadBalancer (클라우드) / ExternalName (DNS 별칭)
- ClusterIP = 클러스터 내부만
- NodePort = 30000~32767, 개발만
- LoadBalancer = 클라우드 LB 자동
- 1 Service = 1 LB (비쌈)
- 온프레미스 LoadBalancer = MetalLB
- Endpoints = 매칭 Pod IP 목록 (자동 갱신)
- Pod Ready 아니면 Endpoints 제외
- CoreDNS = 서비스 디스커버리 (
<svc>.<ns>.svc.cluster.local) - Ingress = L7 HTTP 라우팅
- 도메인·경로별 → 여러 Service
- TLS·rewrite·인증 등 부가 기능
- Ingress 리소스 ≠ Ingress Controller
- Controller — NGINX·Traefik·HAProxy·AWS ALB·Istio
- 다수 HTTP = Ingress 권장
- 단일 TCP·gRPC = LoadBalancer
- CNI = Pod 네트워크 (Calico·Flannel·Cilium·AWS VPC)
- 클러스터 생성 시 결정, 나중 변경 어려움
- NetworkPolicy = Pod 방화벽 (8편)
- Service Mesh = 마이크로서비스 통신 (Istio·Linkerd)
- 복잡도 ↑ — 작은 클러스터 X
시리즈 다른 편
- 1편 — 아키텍처·Control Plane
- 2편 — Pod
- 3편 — Workloads
- 4편 — Services·Networking (현재 글)
- 5편 — ConfigMap·Secret
- 6편 — Storage
- 7편 — Scaling·Scheduling
- 8편 — Security
- 9편 — Helm
- 10편 — 실전 (매니지드·GitOps·Observability)
공식 문서: Kubernetes Service / Ingress 에서 더 깊이.
다음 글(5편)에서는 ConfigMap & Secret — 설정·민감 정보 분리, Pod 주입 방식, 비밀 관리 모범 사례까지 풀어 갑니다.