전체 트래픽 흐름
예시 요청 = https://gql.api.example.com/payment. enterprise 환경에서 클라이언트 브라우저부터 RDS 까지 트래픽이 거치는 hop 들.
[Client Browser]
│ HTTPS 443
▼
[DNS — Route 53] ─── 도메인 → CloudFront/ALB 이름·IP 해석
│
▼
[CloudFront (edge)] ─── TLS termination 1차, edge cache, 글로벌 PoP
│ +
│ WAF ─── L7 필터 (SQLi·XSS·rate limit·국가 차단 등)
▼
[Public ALB] ─── Listener:443 → HTTP host/path rule
│ L7 routing
▼
[Target Group] ─── health check 통과한 target 만 등록
│ (instance mode → NodePort, ip mode → Pod IP 직접)
▼
[EKS Worker Node] ─── Linux 호스트. ENI·secondary IP·kube-proxy·CNI 다 여기서 돎
│ (instance mode 일 때만) NodePort
▼
[kube-proxy iptables/IPVS] ─── Service ClusterIP → Pod IP DNAT
│
▼
[Kong Gateway Pod (DMZ)] ─── L7 reverse proxy + plugin (auth·rate-limit·OIDC)
│ Pod-to-Pod
▼
[Kubernetes Service (ClusterIP)] ── virtual IP — 실재하지 않는 IP. iptables 가 DNAT 로 Pod 로
│
▼
[Frontend GraphQL Pod] ─── application — schema stitching, dataloader
│ (backend 호출 필요)
▼
[Internal ALB / Service Discovery] ── Frontend 클러스터 → Backend 클러스터 경계
│
▼
[Backend Service Pod] ─── business logic. DB 호출
│
▼
[RDS / Other AWS Services] ─── IRSA 로 Pod 가 IAM role assume → AWS API 호출
각 hop 의 핵심 책임 + “왜 거기 있나”:
| Hop | 누가 처리 | 왜 |
|---|---|---|
| Route 53 | AWS managed DNS | 도메인 → IP 해석. ALIAS 로 CloudFront/ALB 같은 dynamic IP 도 지원 |
| CloudFront | AWS CDN | 정적 자산 캐시, edge PoP 에서 latency 단축, TLS 1차 termination, WAF attachment point |
| WAF | AWS WAF | L7 공격 필터 — IP·헤더·URI·payload 패턴 매칭 |
| ALB | AWS Application LB | L7 routing (host·path·header). 인증서 termination, target health |
| EKS Node | EC2 + kubelet | Pod 호스트. ENI 의 secondary IP 가 Pod IP |
| kube-proxy | DaemonSet | Service ClusterIP → Pod 매핑을 iptables/IPVS rule 로 박음 |
| Kong | L7 gateway Pod | 인증·rate-limit·OIDC·canary 같은 cross-cutting policy |
| Pod | container | 실제 application |
| Internal ALB | AWS LB | VPC 내부 LB — public 노출 X. Frontend ↔ Backend 클러스터 경계 |
| RDS | AWS managed DB | IRSA 로 Pod 가 IAM role → DB IAM auth |
src/dst IP·Port 가 바뀌는 NAT 지점:
- CloudFront → ALB = 새 connection. CloudFront 가 client IP 를
X-Forwarded-For헤더에 박음 (원본 IP 보존) - ALB → Target = 새 connection. ALB src IP 가 보임. 원본 client IP 는
X-Forwarded-For - kube-proxy iptables (Service → Pod) = DNAT. dst IP 가 ClusterIP 에서 Pod IP 로
- VPC NAT Gateway (outbound) = SNAT. private subnet Pod 의 outbound 가 NAT GW 의 public IP 로
Kong / Ingress Architecture
Kong = 오픈소스 L7 API gateway (Nginx + Lua 기반). Kubernetes 환경에선 Pod 로 떠서 ingress 역할.
Kong Gateway 자체
기능:
- L7 reverse proxy + load balancing
- 플러그인 = rate-limit, OIDC/JWT auth, request transformer, prometheus 메트릭, 로깅, IP restriction, canary 분배
- Admin API 또는 declarative config
kong-ingress-controller (KIC)
K8s Ingress·Gateway API 리소스를 watch → Kong 의 declarative config 로 번역 → Kong Pod 에 sync.
→ 결과: 개발자는 평범한 Ingress 리소스만 작성, Kong 이 자동 라우팅·플러그인 적용.
ingressClass — 세 종류 비교
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: kong-external # 또는 kong-internal, alb| ingressClass | 누가 처리 | 어디서 | 용도 |
|---|---|---|---|
kong-external | Kong (external 인스턴스) | DMZ 클러스터 | 외부 트래픽. Public ALB 뒤에서 받음 |
kong-internal | Kong (internal 인스턴스) | Trust 영역 | Frontend → Backend 내부 트래픽 |
alb | aws-load-balancer-controller | AWS 인프라 | Kong 거치지 않고 AWS ALB 직접 생성 |
같은 클러스터에 두 Kong (external / internal) 인스턴스를 띄우는 게 흔한 패턴. 하나는 인터넷 향, 하나는 사내 backend 향.
Public Kong vs Internal Kong — DMZ 경계
[Internet]
│
▼
[Public ALB]
│
▼
[External Kong Pod] ──── 인증·WAF 비슷 정책·request shaping
│
▼
[Frontend GraphQL Pod] (DMZ EKS 클러스터)
│ (Backend 호출)
▼
[Internal Kong Pod] ──── service mesh-like, auth re-check, mTLS
│
▼
[Backend Pod] (Trust EKS 클러스터)
External Kong = DMZ 의 진입점. 인터넷에서 들어오는 모든 요청 거름. Internal Kong = 내부 트래픽도 똑같이 게이트로 통과 — zero-trust 패턴 (내부도 무신뢰).
Frontend / Backend 클러스터 분리 이유
- 보안 zone 분리 = DMZ 가 뚫려도 backend 직접 노출 안 됨
- blast radius = 한 클러스터의 etcd·apiserver 문제가 다른 쪽 안 건드림
- 권한 모델 = backend 클러스터 access 는 더 엄격하게
- 컴플라이언스 = 금융권 PCI·ISMS 가 DMZ/Trust 분리 요구
깊은 운영 사례 = 13. EKS Baseline App Upgrade (Kong·ALB Controller·ArgoCD 운영).
AWS Load Balancer Controller
AWS Load Balancer Controller (ALB Controller) = K8s 안 Pod 로 떠서 Ingress·Service 리소스를 watch → AWS API 호출해 ALB/NLB 를 선언적으로 관리.
동작 메커니즘
[user]
│ kubectl apply -f ingress.yaml
▼
[K8s API Server]
│ Ingress 리소스 저장
▼
[ALB Controller Pod] ── Ingress watch (informer)
│ annotation 파싱
▼
[AWS API] ── ALB·Target Group·Listener·Rule·SG 생성·갱신
│
▼
[AWS ALB 인스턴스]
IRSA — controller 의 AWS 권한
ALB Controller 가 AWS API 부르려면 IAM permission 필요. EKS 의 IRSA (IAM Roles for Service Accounts):
- ServiceAccount 에 annotation
eks.amazonaws.com/role-arn: arn:aws:iam::ACCOUNT:role/... - OIDC provider 가 K8s SA token 을 STS 에 제출
- STS 가 IAM role assume → temporary credentials 발급
- controller pod 의 AWS SDK 가 자동으로 token → assume → API 호출
→ 노드 IAM role 에 의존 X. Pod 단위 fine-grained 권한.
instance mode vs ip mode
ALB 가 backend target 으로 무엇을 등록하나의 차이.
Instance mode (legacy / default 가 종종)
[ALB]
│ TCP 443 → 노드의 NodePort (예: 31234)
▼
[EKS Node:31234]
│ iptables DNAT (kube-proxy 가 박은 rule)
▼
[Pod:8080]
Ip mode (권장)
[ALB]
│ TCP 443 → Pod IP 직접 (예: 10.0.5.42:8080)
▼
[Pod:8080]
비교:
| instance mode | ip mode | |
|---|---|---|
| Target 등록 | EC2 instance + NodePort | Pod IP + Port |
| Hop 수 | ALB → NodePort → Pod (2) | ALB → Pod (1) |
| client IP 보존 | 어려움 (kube-proxy 가 SNAT 종종) | externalTrafficPolicy 무관, 자연 보존 |
| latency | 한 hop 더 + iptables 처리 | 더 짧음 |
| Pod IP 가 VPC routable 필요? | X | O (aws-vpc-cni 가 보장) |
| ALB 가 무거운 트래픽 처리 | 노드 분산 | Pod 분산 — 정확 |
ip mode 가 가능한 이유 = aws-vpc-cni 로 Pod IP 가 VPC subnet CIDR 의 routable IP. ALB 가 VPC 안에서 Pod IP 로 직접 도달 가능. (다른 CNI 의 overlay 면 ALB 가 overlay IP 못 봄.)
설정:
metadata:
annotations:
alb.ingress.kubernetes.io/target-type: ip운영 권장 = ip mode. instance mode 는 legacy.
Kubernetes Service 종류
Service = Pod 그룹에 안정적인 endpoint (IP·DNS) 부여. Pod 는 죽고 재생성되며 IP 가 바뀌니까.
| Type | 외부 노출 | IP | 동작 |
|---|---|---|---|
ClusterIP | X (클러스터 내부만) | virtual IP (VIP) | kube-proxy 가 iptables 로 DNAT |
NodePort | 모든 노드의 :nodePort | NodePort + ClusterIP | 외부 → 노드 IP:port → kube-proxy → Pod |
LoadBalancer | cloud LB 통해 외부 | LB IP + NodePort + ClusterIP | cloud controller 가 LB 프로비저닝 |
ExternalName | DNS 만 | (없음) | CoreDNS 가 CNAME 으로 alias |
ClusterIP 의 핵심 — virtual IP
apiVersion: v1
kind: Service
metadata: { name: payment }
spec:
type: ClusterIP
clusterIP: 10.96.50.10 # 이게 VIP
selector: { app: payment }
ports:
- port: 80
targetPort: 808010.96.50.10 은 어떤 노드의 NIC 에도 안 박힌 가짜 IP. ping 도 안 됨. 그런데 curl http://10.96.50.10:80 은 동작 — 왜?
답 = kube-proxy 가 모든 노드의 iptables 에 다음 rule 박음:
-A KUBE-SERVICES -d 10.96.50.10/32 -p tcp --dport 80 -j KUBE-SVC-payment
-A KUBE-SVC-payment -j KUBE-SEP-pod1 (random)
-A KUBE-SVC-payment -j KUBE-SEP-pod2
-A KUBE-SEP-pod1 -j DNAT --to 10.0.5.10:8080
→ ClusterIP 로 가는 모든 packet 이 iptables NAT chain 에서 backend Pod IP 로 DNAT. NIC 에 IP 가 없어도 routing 됨 (iptables 가 가로채니까).
NodePort
type: NodePort 면 ClusterIP + 모든 노드의 :nodePort (보통 30000-32767 범위) 에 listen. 외부 → 노드 IP:31234 → iptables → Pod.
옛 패턴. 요즘은 LoadBalancer 또는 Ingress 가 위에 얹힘.
LoadBalancer
type: LoadBalancer 면 NodePort 기능 + cloud provider 가 외부 LB (AWS = NLB 또는 ALB) 자동 생성. 단 LoadBalancer Service 1 개 = LB 1 개라 비용·관리 부담 → 보통 Ingress (LB 하나에 다중 host/path) 가 권장.
ExternalName
type: ExternalName
externalName: rds.production.svc.example.com→ CoreDNS 가 payment-db.default.svc.cluster.local 쿼리에 rds.production.svc.example.com CNAME 응답. proxy 없음, 그냥 DNS alias.
용도 = 외부 DNS (RDS endpoint·third-party API) 를 클러스터 내부 이름으로 추상화. 환경 (dev/staging/prod) 마다 ExternalName 만 바꿔서 코드는 그대로.
cross-ref 깊이 = 02. K8s Objects > Service, 09. K8s Networking > Service Networking.
kube-proxy / CNI / Pod Networking
EKS Pod 가 어떻게 IP 받고 통신하는지의 핵심.
kube-proxy
DaemonSet — 모든 노드에 떠 있는 Pod. 역할 = Service IP·Port → Pod IP·Port 매핑을 노드 OS 의 packet filter rule 로 박음.
두 모드:
| 모드 | 구현 | 특징 |
|---|---|---|
iptables | netfilter NAT chain | 기본. connection 마다 random backend. rule 수 = Service × backend 라 large cluster 에선 갱신 느림 |
IPVS | 커널 IPVS 모듈 | Hash table 기반. 더 효율적. rr·lc·sh 같은 LB 알고리즘 |
→ Service connection 이 들어오면 iptables/IPVS rule 이 DNAT 로 Pod IP 골라줌. 이게 ClusterIP·NodePort 양쪽 다의 mechanism.
aws-vpc-cni (Amazon VPC CNI)
EKS 의 기본 CNI. 컴포넌트:
aws-node= DaemonSet. 각 노드에서 ENI 관리·secondary IP 할당.amazon-k8s-cni= CNI binary. Pod 생성 시 kubelet 이 호출 → ENI 의 secondary IP 하나를 Pod 의 NIC 에 부여.aws-network-policy-agent= NetworkPolicy 를 eBPF 로 적용 (v1.14+). 옛날엔 별도 CNI (Calico) 필요했음.
ENI 기반 = Pod IP 가 VPC routable
- EC2 instance 는 ENI 여러 개 가질 수 있고, 각 ENI 는 primary + 다수 secondary IP 보유.
- Pod 가 뜨면 = ENI 의 secondary IP 하나를 Pod 에 할당.
- 그 IP = VPC subnet CIDR 의 진짜 IP. VPC routing table·SG·NACL 의 1급 시민.
결과:
- ALB ip mode = ALB 가 Pod IP 로 직접 연결 가능 (overlay 라면 불가)
- SG 직접 = Pod 트래픽도 SG 로 필터 가능
- VPC peering·Transit Gateway 로 cross-cluster·cross-VPC 통신 직접
- service mesh (Istio·App Mesh) 가 sidecar 로 mTLS 끼우기도 자연
단점:
- IP 고갈 = subnet 의 IP 가 한정. m5.large 한 대가 수십~수백 secondary IP 쓸 수 있어 큰 subnet 필요.
- 대응 = Custom networking, prefix delegation (
/28단위 할당) 으로 IP 효율 ↑
Overlay 네트워크와의 차이
| overlay (Flannel VXLAN, Calico IPIP) | aws-vpc-cni | |
|---|---|---|
| Pod IP | 클러스터 내부 가상 대역 | VPC subnet CIDR |
| encapsulation | VXLAN/IPIP 헤더 (오버헤드) | 없음 |
| 외부에서 라우팅 | 불가 (gateway 필요) | 가능 |
| SG 적용 | 불가 (overlay 라 SG 가 못 봄) | 가능 |
| IP 고갈 | X (큰 가상 대역) | 위험 |
| 성능 | 약간 낮음 (encap) | native |
→ EKS = “Pod 가 VPC 1급 시민” 모델. 단순함·성능·AWS 통합 ↑, IP 관리 부담 ↑.
깊이 = 09. K8s Networking > Service Networking, 09. K8s Networking > Pod Networking, 09. K8s Networking > CNI in K8s.
Cross-node Pod-to-Pod
Pod A (Node1) → Pod B (Node2) — overlay 없으니 그냥 VPC routing.
[Node 1]
Pod A (10.0.5.10)
└─ veth pair → 노드 root netns
└─ ENI eth1 (10.0.5.0/24)
│
▼
[VPC routing]
│
▼
ENI eth1 (10.0.6.0/24)
Pod B (10.0.6.20)
[Node 2]
VPC 가 두 ENI 사이의 packet 을 자동 라우팅. AWS Hypervisor·Nitro 의 SDN 이 처리.
Kubernetes Probe
Pod 의 컨테이너 상태 검진. 3 종.
| Probe | 누가 호출 | 실패 시 영향 | 언제 |
|---|---|---|---|
livenessProbe | kubelet | 컨테이너 restart | 무한 루프·deadlock 감지 |
readinessProbe | kubelet | Endpoint 에서 Pod 제거 → kube-proxy rule 갱신 → 트래픽 차단 | warm-up·일시 의존 down |
startupProbe | kubelet | startup 단계 동안 다른 probe 무효화 | slow-start app 보호 |
readiness 실패의 packet flow 영향
정상:
[Service ClusterIP] ── iptables DNAT ──→ [Pod A, B, C]
readiness 실패 (Pod B):
1. kubelet → API server: "Pod B Not Ready"
2. EndpointSlice 컨트롤러 → Endpoints 에서 Pod B 제거
3. kube-proxy 가 Endpoint 변경 감지 → 모든 노드 iptables rule 갱신
4. 새 connection 은 Pod B 로 안 감 (rule 에 없음)
5. 기존 connection 은 그대로 유지 (NAT 는 connection 단위)
회복 시 역순.
→ readiness = “지금 트래픽 받기 안전한가” 의 single source of truth.
startup probe 의 의미
slow-starting app (Java JVM warmup 30 초·DB connection pool 초기화 등) 에 liveness probe 를 빡빡하게 걸면 startup 중에 죽임 → 영구 restart loop.
해결 = startupProbe 로 startup 단계만 별도 검진. startup 끝날 때까지 liveness/readiness 안 돌림.
깊이 = 05. K8s Application Lifecycle Management > Self-Healing Applications.
AWS Networking
EKS 가 얹히는 AWS 네트워크 토대.
기본 빌딩 블록 (짧은 정의)
VPC= 가상 사설 네트워크. region 단위. CIDR (10.0.0.0/16등) 으로 IP 대역 정의Subnet= VPC 안의 IP 대역 일부. AZ 단위. public/private 구분Route Table= subnet 의 외부 라우팅 규칙.0.0.0.0/0 → IGW(public),→ NAT GW(private)Internet Gateway (IGW)= VPC ↔ 인터넷 게이트웨이. public subnet 만 사용NAT Gateway= private subnet 의 outbound 만 인터넷 향. inbound 차단. managed serviceENI= Elastic Network Interface. 가상 NIC. EC2 에 attach. primary IP + secondary IP 들
깊이 = 04. Amazon VPC.
Security Group vs NACL
| Security Group | NACL | |
|---|---|---|
| 적용 단위 | ENI (instance·Pod) | Subnet |
| 평가 방향 | inbound + outbound 별도 | inbound + outbound 별도 |
| 상태 | stateful — outbound 허용 시 return inbound 자동 허용 | stateless — return 도 명시 필요 |
| 규칙 | allow 만 (deny 없음) | allow + deny, 순서 의미 (번호 순) |
| 기본값 | 새 SG = 모든 outbound 허용, inbound 차단 | 새 NACL = 모든 트래픽 허용 (default), custom 은 모두 차단 |
→ 대부분 SG 만 사용. NACL 은 broad subnet-level 차단·compliance 요건 (예: 특정 IP 전체 차단) 일 때.
SG 가 OS iptables 가 아니다
흔한 오해 — “SG 가 EC2 안의 iptables 같은 거 아닌가?”
실제 = AWS 가상화·SDN 레이어 (Nitro) 에서 동작. EC2 의 OS 가 모르는 사이에 Hypervisor·전용 chip 이 packet filtering.
[Pod]
│ packet 송신
▼
[EC2 OS — Linux 커널·iptables] ── OS 가 보는 마지막 지점
│
▼
[Hypervisor / Nitro Card] ── 여기서 SG 평가 (OS 모름)
│
▼
[VPC 가상 네트워크]
→ SG 변경 즉시 적용 — OS restart 불필요. OS 안의 iptables 와 무관.
Pod IP 와 SG 의 관계
Pod IP = ENI 의 secondary IP. ENI 에 attach 된 SG 가 그 Pod 트래픽도 필터.
- 한 노드에 ENI 여러 개 → 노드 단위 SG 가 모든 Pod 트래픽 cover
- Security Group for Pods (SGP, v1.20+) = Pod 마다 다른 SG 부여 가능. branch ENI 사용
- 결과 = Pod 수준 fine-grained 보안 정책 가능 (예: payment Pod 만 RDS 접근)
Nitro / Hypervisor / SDN 짧게
- Nitro = AWS 의 hypervisor + 전용 ASIC. 가상화 오버헤드 거의 제거.
- VPC SDN = software-defined network. routing·SG·flow log 다 SDN layer 에서.
- 결과 = 사용자는 “물리 네트워크 장비” 안 만짐. 다 API 로 정의.
DMZ Architecture
금융권·enterprise 의 표준 패턴. EKS 두 클러스터로 trust zone 분리.
[Internet]
│
▼
[Route 53 (Public Hosted Zone)]
│ ALIAS → CloudFront
▼
[CloudFront edge + WAF]
│
▼
[Public ALB] ┐
│ │ DMZ subnet (public)
▼ │
[Frontend EKS Cluster (DMZ)] │
├─ External Kong (kong-external) │
├─ Frontend GraphQL / BFF │
└─ readonly/aggregator services │
│ ┘
│ Internal ALB (VPC 내부 only)
▼
[Internal ALB] ┐
│ │ Trust subnet (private)
▼ │
[Backend EKS Cluster (Trust)] │
├─ Internal Kong (kong-internal) │
├─ Backend Services (payment·order) │
└─ Domain microservices │
│ ┘
▼ ┐
[RDS / ElastiCache / SQS] │ Restricted subnet
┘
왜 frontend / backend 분리
- 공격면 분리 = DMZ 가 뚫려도 backend·DB 직접 노출 X
- 권한 모델 = backend 클러스터 접근은 더 엄격한 IAM·VPN
- blast radius = etcd·apiserver·cluster autoscaler 문제가 다른 쪽 안 건드림
- compliance = PCI-DSS·ISMS·금융감독원 가이드라인 = trust zone 분리 요구
- 독립 scaling·릴리즈 = frontend 의 트래픽 spike 가 backend 클러스터 영향 X
Public ingress vs Private (Internal) ingress
| Public Ingress | Internal Ingress | |
|---|---|---|
| ALB scheme | internet-facing | internal |
| Route 53 | Public Hosted Zone | Private Hosted Zone (VPC scope) |
| DNS 노출 | 인터넷 resolve 가능 | VPC 내부 resolve 만 |
| 클라이언트 | 외부 사용자·앱 | 내부 서비스·BFF |
| 보안 | WAF + Kong external + SG | SG·NACL 만 (이미 trusted 영역) |
Internal ALB 가 필요한 이유
Frontend 클러스터의 Pod 가 Backend 클러스터의 Pod 직접 호출? = 안 됨 (다른 클러스터·다른 VPC 가능).
Internal ALB:
- VPC 내부 LB. public IP 없음
- Backend 클러스터의 Pod 들을 target group 으로
- Frontend 가 Backend 의 internal ALB 의 endpoint (private DNS) 로 호출
- Frontend 가 Backend cluster 의 K8s API 모르고도 통신 가능
- mTLS·인증서 termination 한 곳에 집중
대안 = Service mesh (Istio·App Mesh) 의 cross-cluster gateway, 또는 VPC peering + ClusterIP. 트레이드오프 따라 선택.
cross-ref = 02. Amazon CloudFront, 12. AWS WAF & Shield, 03. Amazon Route 53, 04. Amazon VPC.
전체 요청 흐름 요약
한 페이지짜리 packet 추적. https://gql.api.example.com/payment 가 RDS 까지 가는 동안 src/dst 가 어떻게 변하나.
| Step | src | dst | 동작 |
|---|---|---|---|
| 1 | client IP (203.0.113.50) | DNS resolver | A record query for gql.api.example.com |
| 2 | client IP | CloudFront edge IP | TCP 443 connect (TLS 1차 termination) |
| 3 | client IP | CloudFront → WAF | L7 검사 |
| 4 | CloudFront IP | Public ALB IP | 새 connection. X-Forwarded-For: <client IP> |
| 5 | ALB IP | Pod IP (ip mode) 또는 Node IP:NodePort | target health check 통과한 곳 |
| 6 (ip mode 끝) | ALB IP | Pod IP 10.0.5.42:8080 | Kong Pod 에 직접 |
| 6 (instance mode) | ALB IP | Node IP:31234 | iptables DNAT → Pod IP |
| 7 | Kong Pod IP | Frontend Service ClusterIP 10.96.50.10:80 | iptables DNAT → Frontend Pod IP |
| 8 | Kong Pod IP | Frontend Pod IP 10.0.6.20:8080 | actual delivery |
| 9 | Frontend Pod IP | Internal ALB IP | 새 connection (cross-cluster) |
| 10 | Internal ALB IP | Backend Pod IP | ip mode |
| 11 | Backend Pod IP (private subnet) | NAT GW IP | SNAT (outbound 만) |
| 12 | NAT GW IP | RDS endpoint IP | TCP 5432 (PostgreSQL) |
| 13 | Pod (IRSA token) | STS → IAM role → RDS IAM auth | 인증 |
핵심 변환:
- Cloud edge 까지 = client IP. CloudFront 가 X-Forwarded-For 헤더로 보존
- ALB·kube-proxy DNAT = dst IP 변환 — 응답 시 자동 역변환 (SNAT/DNAT 가 connection state)
- 외부 인터넷 향 = NAT GW SNAT
핵심 컴포넌트 책임 정리
| 컴포넌트 | 책임 | layer | 대체·비교 |
|---|---|---|---|
| Route 53 | DNS resolve, health check, weighted/latency routing | DNS | NS1·Cloudflare DNS |
| CloudFront | edge cache, TLS termination, WAF 부착점 | CDN (L7) | Cloudflare·Akamai |
| WAF | L7 공격 필터 (SQLi·XSS·rate) | L7 보안 | Cloudflare WAF·F5 |
| ALB | L7 routing (host·path·header), 인증서 termination | L7 LB | Nginx LB·Envoy |
| NLB | L4 routing, 고성능·정적 IP, source IP 보존 | L4 LB | HAProxy |
| Kong | API gateway — auth·rate-limit·plugin | L7 gateway | Nginx Ingress·Envoy·Apigee |
| ALB Controller | K8s Ingress → AWS ALB 자동 관리 | K8s controller | nginx-ingress controller |
| kube-proxy | Service IP → Pod IP iptables rule | K8s control | Cilium kube-proxy replacement |
| aws-vpc-cni | Pod IP 할당 (ENI secondary) | K8s CNI | Calico·Cilium·Flannel |
| NetworkPolicy | Pod 간 L3/L4 ACL | K8s policy | Calico·Cilium (eBPF) |
| Security Group | ENI 단위 stateful 필터 | AWS SDN | NSG (Azure)·VPC firewall (GCP) |
| NACL | Subnet 단위 stateless 필터 | AWS SDN | Azure NSG (rule만)·GCP 없음 |
| IRSA | Pod → IAM role temporary credentials | AWS IAM + OIDC | Workload Identity (GCP)·Managed Identity (Azure) |
면접에서 자주 나오는 포인트
Q. ALB ip mode vs instance mode 차이는? A. instance = ALB → NodePort → kube-proxy → Pod (2 hop, kube-proxy SNAT 로 client IP 손실 위험). ip = ALB → Pod 직접 (1 hop, client IP 자연 보존). ip mode 권장. 가능 이유 = aws-vpc-cni 로 Pod IP 가 VPC routable.
Q. ClusterIP 가 virtual IP 라는데, 실제 NIC 에 없는 IP 가 어떻게 통신하나?
A. kube-proxy 가 모든 노드 iptables 에 dst IP = ClusterIP → backend Pod IP 로 DNAT 하는 rule 박음. packet 이 NIC 도달 전에 iptables 가 가로채서 Pod IP 로 바꿔치기. NIC 에 IP 없어도 routing 됨.
Q. EKS Pod IP 가 VPC routable 인 이유? A. aws-vpc-cni 가 각 노드의 ENI 에 secondary IP 다수 붙임. Pod 생성 시 그 secondary IP 하나를 Pod 에 부여. 즉 Pod IP = VPC subnet CIDR 의 진짜 IP. overlay 안 씀.
Q. SG 가 stateful 이라는 게 무슨 뜻? A. outbound 허용 시 그 connection 의 return 트래픽이 inbound rule 에 없어도 자동 허용. NACL 은 stateless 라 return 도 명시 필요.
Q. SG 는 EC2 안의 iptables 처럼 동작하나? A. 아니. AWS Nitro·Hypervisor·SDN 레이어에서 동작. EC2 OS 의 iptables 와 무관. SG 변경 즉시 적용 (OS restart 불필요).
Q. Service Discovery 가 어떻게 동작?
A. CoreDNS — <svc>.<ns>.svc.cluster.local 쿼리에 ClusterIP 응답. 그 ClusterIP 가 kube-proxy iptables 통해 Pod IP 로.
Q. readiness 실패하면 트래픽이 어떻게 끊기나? A. kubelet 이 API server 에 Not Ready 보고 → EndpointSlice 에서 그 Pod 제거 → kube-proxy 가 모든 노드 iptables rule 갱신 → 새 connection 은 그 Pod 로 안 감. 기존 connection 은 NAT state 유지.
Q. Kong vs Nginx Ingress Controller 차이? A. 둘 다 K8s Ingress 처리. Kong = 플러그인 ecosystem (rate-limit·auth·OIDC) + 자체 Admin API + DB 모드(Postgres)/DB-less. Nginx Ingress = 단순·가볍지만 고급 기능은 Annotation 또는 ConfigMap 으로 제한적. 금융권·플랫폼 팀은 Kong, 단순 서비스는 Nginx 가 흔함.
Q. 왜 Internal ALB 쓰나? A. VPC 내부 LB. public IP·DNS 없음. cross-cluster·cross-VPC 통신을 IAM·SG·private subnet 안에서. public 노출 안 함.
Q. IRSA 동작?
A. ServiceAccount annotation eks.amazonaws.com/role-arn → Pod SA token → STS AssumeRoleWithWebIdentity (OIDC) → temporary IAM credentials. Pod 단위 fine-grained AWS 권한. Node IAM role 의존 X.
Q. instance mode 에서 client IP 가 손실되는 이유?
A. kube-proxy 의 iptables 가 cross-node 라우팅 시 SNAT (source IP 를 노드 IP 로 변경) 함. externalTrafficPolicy: Local 로 해결 가능하나 traffic balance 불균등 위험.
Q. NodePort 와 LoadBalancer 의 관계? A. LoadBalancer = NodePort 위에 cloud LB 가 자동 프로비저닝. 즉 LoadBalancer 는 내부적으로 NodePort 도 같이 만듦.
Q. Pod 가 인터넷 outbound 할 때 IP 변환? A. private subnet Pod = NAT Gateway 의 public IP 로 SNAT. ALB inbound 와 별개 흐름. NAT GW 가 AWS managed 라 가용성·throughput 보장.
Q. cross-AZ 트래픽 비용·latency 어떻게 줄이나? A. Topology Aware Hints (K8s 1.21+) — kube-proxy 가 같은 AZ 의 Pod 우선 선택. 또는 service mesh 의 locality-aware LB. 그래도 HA 위해 cross-AZ 가 필수.
References
- Amazon EKS Best Practices Guides | aws.github.io
- AWS Load Balancer Controller | kubernetes-sigs
- Amazon VPC CNI plugin | github.com/aws/amazon-vpc-cni-k8s
- Kong Ingress Controller | github.com/Kong/kubernetes-ingress-controller
- Kong Gateway docs | docs.konghq.com
- IRSA — IAM Roles for Service Accounts | AWS docs
- kube-proxy modes | kubernetes.io
- Configure Liveness, Readiness and Startup Probes | kubernetes.io
- Security groups for your VPC | AWS docs
- Security groups for Pods | AWS docs
- AWS Nitro System | AWS
- 13. EKS Baseline App Upgrade — 운영 사례 (Kong·ALB Controller·ArgoCD)
- 09. K8s Networking — Service Networking·Pod Networking·CNI 기초
- 02. K8s Objects — Service·Deployment·Pod 기초
- 05. K8s Application Lifecycle Management — Probe·Self-Healing
- 16. Pod Disruption Budget — eviction·drain (architecture 의 가용성 측면)
- 09. AL2023 EKS Worker AMI Migration — Worker AMI 빌드·OS 튜닝
- 01. DogStatsD UDP 처리 — DaemonSet 모니터링 패턴
- 04. Amazon VPC — VPC·Subnet·SG·NACL 깊이
- 02. Amazon CloudFront, 03. Amazon Route 53, 12. AWS WAF & Shield, 03. Amazon IAM
- 07. Linux Networking — TCP buffer·소켓·packet flow 커널 관점
- 04. TCP & UDP — TCP 프로토콜·encapsulation