파드는 서로를 어떻게 찾는가
앞 장에서 이미지를 바꾸면 새 ReplicaSet이 새 Pod들을 만든다고 했습니다. 이 새 Pod들은 옛 Pod과 IP 주소가 다릅니다. Pod의 IP는 애초에 영구적이지 않습니다 — 죽었다 다시 뜨기만 해도 IP가 바뀝니다. 그런데 만약 프론트엔드 서버가 백엔드 API의 IP를 직접 하드코딩하고 있었다면, 배포 한 번에 그 주소가 통째로 못 쓰게 됩니다. Service는 이 문제, 오직 이 문제 하나를 풀기 위해 존재합니다.
Service는 "고정된 주소로 뒤에 있는 Pod들을 가리키는 이정표"다
Service를 만들면 절대 바뀌지 않는 IP와 DNS 이름이 하나 생깁니다. 이 Service는 label selector로 지정된 Pod들에게 트래픽을 나눠 보냅니다. Pod이 새로 생기거나 죽어도, 그 Pod의 label만 맞으면 자동으로 Service의 대상에 포함되거나 빠집니다.
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-api
spec:
selector:
app: my-api # 5장의 Deployment가 만드는 Pod들이 정확히 이 label을 갖고 있다
ports:
- port: 80
targetPort: 8080kubectl apply -f service.yaml
kubectl get service my-api
# NAME TYPE CLUSTER-IP PORT(S)
# my-api ClusterIP 10.96.45.201 80/TCP
kubectl get endpoints my-api
# my-api 10.244.0.5:8080,10.244.0.6:8080,10.244.0.7:8080get endpoints로 확인한 이 IP 목록이 바로 selector에 매칭된 실제 Pod들입니다. Deployment의 복제본을 5개로 늘리면 이 목록도 자동으로 5개가 됩니다. selector와 label이 한 글자라도 어긋나면 이 목록이 텅 비는데, "Service는 만들었는데 트래픽이 하나도 안 간다"는 문제의 9할은 이 오타 때문입니다.
클러스터 안에서는 DNS 이름으로 부른다
Service를 만들면 클러스터 내부 DNS에 자동으로 이름이 등록됩니다. 프론트엔드 Pod에서 백엔드를 부를 때 IP를 알 필요가 전혀 없습니다.
# 같은 네임스페이스 안이라면
curl http://my-api/
# 다른 네임스페이스에서는 이렇게
curl http://my-api.default.svc.cluster.local/Service 타입 세 가지, 그리고 각각을 언제 쓰는가
같은 Service 리소스라도 type 값에 따라 클러스터 밖 노출 범위가 완전히 달라집니다.
| 타입 | 노출 범위 | 주로 쓰는 곳 |
|---|---|---|
| ClusterIP (기본값) | 클러스터 내부에서만 접근 가능 | 백엔드끼리 통신 (DB, 내부 API) |
| NodePort | 각 노드의 고정 포트(30000-32767)로 외부 접근 가능 | 로컬 테스트, 임시 노출 |
| LoadBalancer | 클라우드 제공자가 실제 로드밸런서를 만들어줌 | 클라우드에서 외부 트래픽을 직접 받을 때 |
NodePort는 로컬 kind 클러스터에서 빠르게 확인해볼 때는 유용하지만, 30000번대 포트를 사용자에게 그대로 노출하는 서비스는 실무에서 거의 본 적이 없습니다. LoadBalancer는 클라우드 로드밸런서 하나를 그대로 프로비저닝하기 때문에 편리하지만, Service마다 하나씩 만들면 그만큼 클라우드 비용이 붙습니다. 도메인 기반으로 여러 서비스를 하나의 진입점으로 묶고 싶다면 Ingress를 쓰는 게 낫습니다 — 이건 9장에서 다룹니다.
kube-proxy는 로드밸런서처럼 보이지만 로드밸런서가 아니다
Service로 들어온 트래픽이 실제로 어느 Pod에 도착할지는 각 노드에 떠 있는 kube-proxy가 관리하는 iptables(또는 IPVS) 규칙이 결정합니다. 이 방식의 흥미로운 점은, 트래픽이 어떤 중앙 로드밸런서 프로세스를 거치는 게 아니라 커널 레벨에서 곧바로 라우팅된다는 것입니다. 그래서 Service 자체는 어떤 프로세스가 떠서 트래픽을 처리하는 게 아니라, 커널 규칙을 만드는 신호에 가깝습니다. 이 사실이 실무에 미치는 영향은 크지 않지만, "Service가 다운되면 어떻게 되나요"라는 질문에 대한 답은 "Service라는 게 애초에 떠 있는 프로세스가 아니라서 그 자체로는 다운될 게 없다"입니다.