Kubernetes 개발·운영 실전 4편 — 네트워크 설계 실전 (Service / Ingress / NetworkPolicy)
Kubernetes Service 타입별 차이, Ingress 구성, NetworkPolicy로 Pod 간 통신을 제어하는 실전 가이드. 클러스터 내부/외부 트래픽 흐름을 설계하는 방법.
TestForge Team ·
Kubernetes 네트워크의 기본 원칙
Kubernetes 네트워크는 두 가지 기본 규칙을 따릅니다.
- 모든 Pod는 서로 통신 가능 — 기본적으로 클러스터 내 모든 Pod가 직접 통신
- Pod IP는 재시작 시 바뀜 — Service가 고정 엔드포인트를 제공
이 구조를 이해하면 Service, Ingress, NetworkPolicy가 왜 필요한지 명확해집니다.
1. Service 타입 선택
ClusterIP — 클러스터 내부 통신 (기본)
apiVersion: v1
kind: Service
metadata:
name: api-service
namespace: production
spec:
type: ClusterIP # 기본값
selector:
app: api-server
ports:
- port: 80 # 서비스 포트
targetPort: 8080 # Pod 포트
protocol: TCP
클러스터 내부에서만 접근 가능합니다. 외부 노출이 필요 없는 모든 서비스에 사용합니다.
NodePort — 노드 포트로 외부 노출 (개발/테스트 한정)
spec:
type: NodePort
ports:
- port: 80
targetPort: 8080
nodePort: 30080 # 30000-32767 범위
모든 노드의 30080 포트로 접근 가능합니다. 프로덕션에서는 Ingress를 사용하고, NodePort는 로컬 테스트 또는 로드 밸런서 없는 온프레미스 환경에만 사용합니다.
LoadBalancer — 클라우드 로드 밸런서 연결
spec:
type: LoadBalancer
ports:
- port: 443
targetPort: 8443
클라우드 프로바이더(AWS ELB, GCP LB 등)가 자동으로 로드 밸런서를 생성합니다. 서비스마다 별도 로드 밸런서가 생성되어 비용이 높아질 수 있으므로, 여러 서비스를 노출할 때는 Ingress를 사용합니다.
Service 타입 선택 기준
외부 노출 불필요 → ClusterIP
HTTP/HTTPS 다중 서비스 → Ingress + ClusterIP
TCP/UDP 단일 서비스 → LoadBalancer
로컬 개발/테스트 → NodePort
2. Ingress — HTTP 트래픽 라우팅
Ingress는 하나의 로드 밸런서로 여러 서비스를 라우팅하는 L7 게이트웨이입니다.
기본 Ingress 설정 (nginx)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
namespace: production
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- api.example.com
secretName: api-tls-secret # cert-manager가 자동 발급
rules:
- host: api.example.com
http:
paths:
- path: /api/v1
pathType: Prefix
backend:
service:
name: api-v1-service
port:
number: 80
- path: /api/v2
pathType: Prefix
backend:
service:
name: api-v2-service
port:
number: 80
cert-manager로 TLS 자동화
# ClusterIssuer 설정 (Let's Encrypt)
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
ingressClassName: nginx
# Ingress에 자동 인증서 발급 annotation 추가
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- api.example.com
secretName: api-tls # cert-manager가 자동 생성
Ingress 고급 설정 — Rate Limiting, 타임아웃
metadata:
annotations:
# Rate Limiting
nginx.ingress.kubernetes.io/limit-rps: "100"
nginx.ingress.kubernetes.io/limit-connections: "20"
# 타임아웃
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
# 요청 크기 제한
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
3. NetworkPolicy — Pod 간 통신 제어
기본적으로 Kubernetes는 모든 Pod 간 통신을 허용합니다. NetworkPolicy를 적용하면 명시적으로 허용한 트래픽만 통과시킵니다.
기본 정책 — 모든 인바운드 차단
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {} # 네임스페이스 내 모든 Pod
policyTypes:
- Ingress # 인바운드만 차단 (아웃바운드는 허용 유지)
API 서버 — 특정 소스만 허용
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-server-policy
namespace: production
spec:
podSelector:
matchLabels:
app: api-server
policyTypes:
- Ingress
- Egress
ingress:
# Ingress 컨트롤러에서만 인바운드 허용
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
ports:
- protocol: TCP
port: 8080
egress:
# DB 접근 허용
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
# Redis 접근 허용
- to:
- podSelector:
matchLabels:
app: redis
ports:
- protocol: TCP
port: 6379
# DNS 허용 (없으면 도메인 조회 불가)
- to:
- namespaceSelector: {}
ports:
- protocol: UDP
port: 53
네임스페이스 간 통신 제어
# payment-service → auth-service 통신 허용
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-payment
namespace: auth-service
spec:
podSelector:
matchLabels:
app: auth-api
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: payment-service
podSelector:
matchLabels:
app: payment-api
ports:
- port: 8080
4. DNS와 서비스 디스커버리
Kubernetes는 CoreDNS로 서비스 디스커버리를 제공합니다.
<service-name>.<namespace>.svc.cluster.local
# 같은 네임스페이스: 서비스 이름만으로 접근 가능
curl http://api-service/health
# 다른 네임스페이스: FQDN 사용
curl http://api-service.production.svc.cluster.local/health
# StatefulSet Pod 직접 접근
curl http://redis-0.redis-headless.production.svc.cluster.local:6379
ndots 설정 — DNS 성능 최적화
spec:
dnsConfig:
options:
- name: ndots
value: "2" # 기본 5에서 낮춰 불필요한 DNS 조회 감소
5. 트래픽 흐름 전체 그림
외부 요청
↓
[Cloud Load Balancer]
↓
[Ingress Controller (nginx)]
↓ (TLS 종료, 라우팅)
[ClusterIP Service]
↓
[Pod] → [NetworkPolicy 체크] → [DB Service] → [DB Pod]
실전 체크리스트
# Service 엔드포인트 확인 (Pod가 연결됐는지)
kubectl get endpoints api-service -n production
# Ingress 상태 확인
kubectl describe ingress api-ingress -n production
# NetworkPolicy 목록
kubectl get networkpolicy -n production
# DNS 조회 테스트
kubectl run -it --rm dns-test --image=busybox --restart=Never -- \
nslookup api-service.production.svc.cluster.local
# 서비스 간 통신 테스트
kubectl run -it --rm curl-test --image=curlimages/curl --restart=Never -- \
curl http://api-service.production.svc.cluster.local/health
정리
| 컴포넌트 | 역할 | 사용 기준 |
|---|---|---|
| ClusterIP | 내부 통신 고정 엔드포인트 | 모든 내부 서비스 기본 |
| LoadBalancer | 클라우드 LB 연결 | TCP/UDP 단일 서비스 외부 노출 |
| Ingress | HTTP 라우팅 + TLS | 다중 HTTP 서비스 외부 노출 |
| NetworkPolicy | 트래픽 화이트리스트 | 서비스 간 통신 명시적 제어 |
다음 편에서는 Helm 실전 관리를 다룹니다. Chart 구조 설계, values 파일로 환경 분리, 배포 전략을 정리합니다.