Kubernetes 서비스와 네트워킹: Service·Ingress·Gateway API·NetworkPolicy
개요
Kubernetes에서 Pod는 언제든 죽고 새 IP로 되살아나는 일시적 존재다(Kubernetes - Pod와 워크로드). 그래서 Pod의 IP를 직접 부르면 곧 깨진다. Service는 변하는 Pod 집합 앞에 고정된 가상 IP와 DNS 이름을 두어 이 문제를 해결하고, Ingress/Gateway API는 외부 HTTP 트래픽을 클러스터 내부 Service로 라우팅한다. 여기에 NetworkPolicy로 Pod 간 통신을 방화벽처럼 제어한다. 이 계층 구조를 이해하면 “왜 접속이 안 되는가”의 대부분을 진단할 수 있다.
핵심 개념과 원리
Service의 네 가지 타입
Service는 label selector로 대상 Pod 집합(엔드포인트)을 찾아 트래픽을 로드밸런싱한다. 노출 범위에 따라 타입이 나뉜다.
| 타입 | 노출 범위 | 용도 |
|---|---|---|
| ClusterIP | 클러스터 내부 전용(기본값) | 내부 마이크로서비스 간 통신 |
| NodePort | 각 노드의 고정 포트(30000~32767) | 간단한 외부 노출, 개발/테스트 |
| LoadBalancer | 클라우드 LB로 외부 IP 할당 | 프로덕션 외부 노출(클라우드 환경) |
| ExternalName | DNS CNAME으로 외부 서비스 매핑 | 클러스터 밖 서비스 추상화 |
ClusterIP가 기본이자 가장 중요하다. NodePort는 그 위에, LoadBalancer는 다시 그 위에 쌓이는 계층 구조다. 즉 LoadBalancer를 만들면 내부적으로 NodePort와 ClusterIP도 함께 생성된다.
클러스터 DNS와 서비스 디스커버리
클러스터에는 CoreDNS가 돌며, 모든 Service에 예측 가능한 DNS 이름을 부여한다. 형식은 다음과 같다.
<service-name>.<namespace>.svc.cluster.local
같은 네임스페이스에서는 payment처럼 짧은 이름으로, 다른 네임스페이스는 payment.billing으로 접근한다. 애플리케이션은 IP 대신 이 이름을 사용하므로 Pod가 교체돼도 코드를 바꿀 필요가 없다. 이것이 서비스 디스커버리의 핵심이다.
kube-proxy: 가상 IP의 실체
ClusterIP는 실제로 어떤 네트워크 인터페이스에도 존재하지 않는 가상 IP다. 각 노드의 kube-proxy가 Service와 엔드포인트 변화를 감시하며 노드의 패킷 처리 규칙(iptables 또는 IPVS 모드)을 갱신한다. Pod가 ClusterIP로 패킷을 보내면 이 규칙이 목적지를 실제 Pod IP 중 하나로 DNAT(주소 변환)한다. 즉 로드밸런싱은 중앙 프록시가 아니라 각 노드의 커널 수준에서 분산 처리된다.
헤드리스 Service
clusterIP: None으로 지정하면 가상 IP 없이 DNS가 개별 Pod IP를 직접 반환하는 헤드리스 Service가 된다. StatefulSet의 각 Pod(db-0, db-1)에 안정적 DNS를 부여하거나, 클라이언트가 직접 특정 인스턴스를 골라야 하는 경우에 쓴다.
Ingress: L7 HTTP 라우팅
Service만으로 여러 서비스를 하나의 도메인/IP로 노출하려면 서비스마다 LoadBalancer가 필요해 비효율적이다. Ingress는 하나의 진입점에서 호스트·경로 기반으로 여러 Service에 HTTP(S) 트래픽을 분배하고, TLS 종료(termination)를 담당한다. Ingress는 규칙 선언일 뿐이고, 실제 처리는 Ingress Controller(NGINX Ingress, Traefik 등)가 한다. 컨트롤러가 없으면 Ingress 리소스는 아무 동작도 하지 않는다.
Gateway API: Ingress의 후계
Ingress는 표현력이 제한적이고 벤더별 어노테이션에 의존하는 문제가 있었다. Gateway API는 이를 대체하기 위한 차세대 표준으로, 역할을 분리한 여러 리소스로 구성된다.
| 리소스 | 담당자 | 역할 |
|---|---|---|
GatewayClass | 인프라 제공자 | 구현체 정의(NGINX, Istio 등) |
Gateway | 클러스터 운영자 | 리스너·포트·TLS 등 진입점 |
HTTPRoute | 앱 개발자 | 호스트·경로·헤더 기반 라우팅 규칙 |
역할이 분리돼 있어 운영자와 개발자의 권한 경계가 명확하고, 트래픽 가중치 분배(canary)·헤더 기반 라우팅 등을 표준 스펙으로 표현한다.
NetworkPolicy: Pod 간 방화벽
기본적으로 Kubernetes의 모든 Pod는 서로 통신할 수 있다(all-allow). NetworkPolicy는 label selector로 특정 Pod 그룹의 ingress(수신)·egress(송신) 트래픽을 허용/차단하는 규칙이다. 단, NetworkPolicy는 이를 지원하는 CNI 플러그인(Calico, Cilium 등)이 있어야 실제로 강제된다. 한 네임스페이스에 “기본 차단(default deny)” 정책을 걸고 필요한 통신만 열어주는 것이 보안 모범 사례다.
실전
ClusterIP + LoadBalancer
apiVersion: v1
kind: Service
metadata:
name: payment
spec:
type: ClusterIP # 내부 전용
selector:
app: payment # 이 라벨을 가진 Pod로 로드밸런싱
ports:
- port: 80 # Service 포트
targetPort: 8080 # Pod 컨테이너 포트kubectl get endpoints payment # Service가 잡은 실제 Pod IP 확인
kubectl get svc # ClusterIP/External-IP 확인Ingress로 경로 기반 라우팅
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
tls:
- hosts: [shop.example.com]
secretName: shop-tls
rules:
- host: shop.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service: { name: api, port: { number: 80 } }
- path: /
pathType: Prefix
backend:
service: { name: web, port: { number: 80 } }NetworkPolicy 기본 차단
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: billing
spec:
podSelector: {} # 네임스페이스 내 모든 Pod
policyTypes: [Ingress] # 수신 트래픽 전부 차단(허용 규칙 없음)함정과 베스트 프랙티스
- selector·label 불일치가 “연결 안 됨”의 1순위 원인.
kubectl get endpoints <svc>가 비어 있으면 selector가 어떤 Pod도 못 잡은 것이다. targetPort혼동:port(Service)와targetPort(컨테이너)를 헷갈리면 트래픽이 도달하지 않는다.- Ingress Controller 미설치: Ingress 리소스만 만들고 컨트롤러가 없으면 아무 일도 안 일어난다.
ingressClassName도 맞춰야 한다. - NodePort 프로덕션 직접 노출 지양: 포트 관리·보안 부담이 크다. 클라우드는 LoadBalancer/Ingress를 쓴다.
- NetworkPolicy는 CNI 의존: Calico/Cilium 같은 지원 CNI가 없으면 정책이 무시된다.
- DNS 캐싱 주의: 애플리케이션이 DNS 결과를 오래 캐시하면 Pod 교체 후에도 옛 IP를 부를 수 있다.
정리
Service(ClusterIP·NodePort·LoadBalancer)는 일시적인 Pod 앞에 고정 IP/DNS를 두어 안정적 접근을 제공하고, kube-proxy가 각 노드 커널 수준에서 이를 실제 Pod로 라우팅한다. 외부 HTTP는 Ingress 또는 차세대 표준인 Gateway API로 L7 라우팅하고, NetworkPolicy로 Pod 간 통신을 통제한다. 워크로드 정의는 Kubernetes - Pod와 워크로드, 설정·비밀 주입은 Kubernetes - 설정과 스토리지, 클러스터 전체 구조는 Kubernetes - 개요와 아키텍처를 참고한다.