Backend

Kubernetes 심화 시리즈 #2: 서비스 네트워킹의 내부 동작 원리

2026-01-038 min read

Kubernetes 심화 시리즈 #2: 서비스 네트워킹의 내부 동작 원리

시리즈 개요

#주제핵심 내용
1워크로드 컨트롤러 심화Deployment, StatefulSet, DaemonSet, CronJob
2서비스 네트워킹 심화Service 타입, kube-proxy, AWS ALB/NLB
3설정 및 시크릿 관리ConfigMap, Secrets, AWS Secrets Manager CSI Driver
4Istio 서비스 메시VirtualService, DestinationRule, 와일드카드 서브도메인
5오토스케일링 심화HPA, VPA, Cluster Autoscaler, Karpenter, KEDA
6보안 심화RBAC, NetworkPolicy, Pod Security Standards

Service의 본질: Pod 추상화

Pod는 생성될 때마다 IP가 바뀝니다. Service는 이 변화하는 Pod들 앞에 안정적인 엔드포인트를 제공합니다.


Service 타입별 동작 원리

ClusterIP (기본값): 클러스터 내부 통신

apiVersion: v1
kind: Service
metadata:
  name: backend-api
spec:
  type: ClusterIP  # 기본값, 생략 가능
  selector:
    app: backend
  ports:
  - port: 80         # Service 포트
    targetPort: 8080 # Pod 포트

동작 원리:

  1. Service 생성 시 ClusterIP 할당 (예: 10.96.0.100)
  2. Endpoints 객체 자동 생성 (selector와 일치하는 Pod IP 목록)
  3. kube-proxy가 iptables/IPVS 규칙 생성
  4. ClusterIP로 오는 트래픽을 Pod IP로 로드밸런싱
# Endpoints 확인 (실제 Pod IP 목록)
kubectl get endpoints backend-api

# 출력 예시:
# NAME          ENDPOINTS                                   AGE
# backend-api   10.0.1.5:8080,10.0.1.6:8080,10.0.1.7:8080   1h

NodePort: 외부에서 노드 IP로 접근

apiVersion: v1
kind: Service
metadata:
  name: backend-api
spec:
  type: NodePort
  selector:
    app: backend
  ports:
  - port: 80
    targetPort: 8080
    nodePort: 30080  # 30000-32767 범위, 생략 시 자동 할당

[!IMPORTANT] NodePort는 모든 노드에서 열립니다. Node3에 Pod가 없어도 30080 포트로 접근하면 다른 노드의 Pod로 트래픽이 전달됩니다.

externalTrafficPolicy: 트래픽 경로 제어

spec:
  type: NodePort
  externalTrafficPolicy: Local  # 기본값: Cluster
정책동작장점단점
Cluster다른 노드 Pod로도 전달균등한 로드밸런싱추가 홉, 클라이언트 IP 손실
Local해당 노드의 Pod로만 전달클라이언트 IP 보존, 낮은 지연불균등 분배 가능

LoadBalancer: 클라우드 로드밸런서 통합

apiVersion: v1
kind: Service
metadata:
  name: backend-api
  annotations:
    # AWS NLB 사용 (기본은 CLB)
    service.beta.kubernetes.io/aws-load-balancer-type: nlb
    # 인터널 LB
    service.beta.kubernetes.io/aws-load-balancer-internal: "true"
spec:
  type: LoadBalancer
  selector:
    app: backend
  ports:
  - port: 80
    targetPort: 8080

LoadBalancer = NodePort + 클라우드 LB 자동 프로비저닝

ExternalName: 외부 서비스 CNAME

apiVersion: v1
kind: Service
metadata:
  name: external-db
spec:
  type: ExternalName
  externalName: mydb.us-east-1.rds.amazonaws.com

클러스터 내에서 external-db로 DNS 조회하면 RDS 주소가 반환됩니다.

# 클러스터 포드 내에서
nslookup external-db.default.svc.cluster.local
# → mydb.us-east-1.rds.amazonaws.com

kube-proxy: Service 구현체

모드 비교: iptables vs IPVS vs nftables

특성iptablesIPVSnftables
조회 시간O(n)O(1)O(1)
권장 여부안정적⚠️ Deprecated 예정권장
로드밸런싱랜덤rr, lc, dh 등다양
성능개선됨양호최고
최소 버전모든 버전-K8s 1.31+ (1.33 Stable)

[!WARNING] IPVS 모드 Deprecated 예정: Kubernetes 공식 문서에 따르면 IPVS 모드는 Kubernetes Services API와의 불일치로 인해 향후 deprecated될 예정입니다. 새로운 클러스터에서는 nftables 모드(K8s 1.33+ stable) 또는 iptables 모드를 권장합니다.

kube-proxy 모드 설정

# nftables 모드 (K8s 1.31+, 권장)
apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-proxy
  namespace: kube-system
data:
  config.conf: |
    mode: "nftables"
# IPVS 모드 (⚠️ deprecated 예정)
apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-proxy
  namespace: kube-system
data:
  config.conf: |
    mode: "ipvs"
    ipvs:
      scheduler: "rr"  # round-robin

AWS Load Balancer Controller

개요

AWS Load Balancer Controller는 Ingress와 Service를 ALB/NLB로 프로비저닝합니다.

Ingress로 ALB 생성

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    # ALB Ingress Controller
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip  # Pod IP 직접 연결
    
    # SSL/TLS
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:...
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
    alb.ingress.kubernetes.io/ssl-redirect: '443'
    
    # 헬스체크
    alb.ingress.kubernetes.io/healthcheck-path: /health
    alb.ingress.kubernetes.io/healthcheck-interval-seconds: '15'
spec:
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: backend-api
            port:
              number: 80

target-type: ip vs instance

target-type경로장점단점
instanceALB → NodePort → Pod간단, 모든 네트워크에서 동작추가 홉, 지연
ipALB → Pod (직접)낮은 지연, 효율적VPC CNI 필요, ENI 제한

NLB for TCP/UDP

apiVersion: v1
kind: Service
metadata:
  name: tcp-service
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: "external"
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip"
    service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
spec:
  type: LoadBalancer
  selector:
    app: my-app
  ports:
  - port: 9000
    targetPort: 9000
    protocol: TCP

Headless Service 심화

Selector가 있지만 ClusterIP가 없는 Service입니다. DNS 조회 시 Service IP가 아닌 Pod IP 목록을 직접 반환합니다.

apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  clusterIP: None  # Headless!
  selector:
    app: mysql
  ports:
  - port: 3306

DNS 해석 차이

# 일반 Service: ClusterIP 반환
nslookup backend-api.default.svc.cluster.local
# → 10.96.0.100

# Headless Service: 모든 Pod IP 반환
nslookup mysql.default.svc.cluster.local
# → 10.0.1.5
# → 10.0.1.6
# → 10.0.1.7

사용 사례

사용 사례이유
StatefulSet각 Pod에 고유 DNS 필요 (mysql-0.mysql.svc)
클라이언트 측 로드밸런싱gRPC, 커스텀 LB 알고리즘
서비스 디스커버리Consul, etcd 같은 클러스터

EndpointSlices: 대규모 클러스터 최적화

Endpoints 객체는 Service당 하나이며, 모든 Pod IP를 담습니다. Pod가 수천 개면 문제가 됩니다.

EndpointSlices 장점:

  • 최대 100개 엔드포인트씩 분할
  • 변경 시 해당 슬라이스만 업데이트
  • etcd 부하 감소
# EndpointSlices 확인
kubectl get endpointslices -l kubernetes.io/service-name=my-service

트러블슈팅 가이드

Service에 연결되지 않음

# 1. Endpoints 확인 (비어있으면 selector 문제)
kubectl get endpoints my-service

# 2. Pod label 확인
kubectl get pods --show-labels

# 3. Pod readiness 확인
kubectl get pods -o wide

NodePort로 외부 접속 불가

# 1. NodePort 확인
kubectl get svc my-service

# 2. 방화벽/Security Group 확인
# AWS: EC2 Security Group에서 NodePort 범위 허용

# 3. iptables 규칙 확인
sudo iptables -t nat -L KUBE-SERVICES -n

LoadBalancer EXTERNAL-IP가 <pending>

# 1. AWS Load Balancer Controller 로그 확인
kubectl logs -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller

# 2. 서비스 이벤트 확인
kubectl describe svc my-service

# 3. IAM 권한 확인 (IRSA)

흔한 원인:

  1. Cloud Controller Manager 미설치 (On-prem)
  2. IAM 권한 부족
  3. 서브넷 태그 누락 (kubernetes.io/role/elb)

정리

구성요소역할
ClusterIP클러스터 내부 가상 IP
NodePort모든 노드에서 고정 포트 노출
LoadBalancer클라우드 LB 자동 프로비저닝
ExternalName외부 서비스 DNS CNAME
kube-proxyiptables/IPVS로 패킷 라우팅
AWS LB ControllerIngress → ALB, Service → NLB
Headless Service각 Pod에 직접 DNS 접근

다음 편 예고

3편: 설정 및 시크릿 관리에서는 다음을 다룹니다:

  • ConfigMap과 Secrets의 내부 동작
  • Secrets at Rest Encryption
  • AWS Secrets Manager + CSI Driver 통합
  • External Secrets Operator

참고 자료

Share

Related Articles

Comments

이 블로그는 제가 알고 있는 것들을 잊지 않기 위해 기록하는 공간입니다.
직접 작성한 글도 있고, AI의 도움을 받아 정리한 글도 있습니다.
정확하지 않은 내용이 있을 수 있으니 참고용으로 봐주세요.

© 2026 Seogyu Kim