본문 바로가기

Troubleshooting

EKS Pod가 외부 인터넷에 접근하지 못하는 경우

반응형

EKS 클러스터에 애플리케이션을 배포했는데, Pod에서 외부 API를 호출하면 타임아웃이 발생합니다. curl https://api.example.com이 응답 없이 멈추고, 컨테이너 이미지를 pull하는 것도 실패합니다. Node는 정상인데 Pod만 외부 통신이 안 됩니다. EKS에서 Pod의 외부 인터넷 접근은 VPC 네트워크 경로(Route Table → NAT Gateway → Internet Gateway)와 보안 규칙(Security Group, NACL)이 모두 정상이어야 동작합니다.

Troubleshooting EKS / AWS Level 2 18분

핵심 요약

원인 증상 확인 방법
NAT Gateway 미설정 / 장애 모든 Pod에서 외부 타임아웃 VPC 콘솔에서 NAT GW 상태, Route Table 확인
Route Table에 NAT 경로 누락 특정 Subnet의 Pod만 실패 aws ec2 describe-route-tables
Security Group Outbound 차단 특정 포트만 실패 Worker Node SG의 Outbound 규칙 확인
NACL Outbound/Inbound 차단 특정 Subnet에서만 실패 Subnet에 연결된 NACL 규칙 확인
DNS 해석 실패 도메인 이름은 안 되고 IP 직접 접근은 됨 nslookup, CoreDNS Pod 상태 확인
VPC CNI IP 고갈 새 Pod만 실패, 기존 Pod는 정상 kubectl describe node — Allocatable pods
Pod가 Public Subnet에 배치됨 Public IP 미할당 시 외부 통신 불가 Subnet 유형과 Pod IP 대역 확인

1. EKS Pod의 외부 인터넷 통신 경로

EKS에서 Pod가 외부 인터넷에 접근하려면 다음 경로를 거칩니다.

EKS Pod 외부 인터넷 통신 경로
EKS Pod 외부 인터넷 통신 경로

통신 경로 (Private Subnet 기준):

  1. Pod가 외부 IP로 패킷을 전송합니다.
  2. VPC CNI 플러그인이 Pod에 VPC 서브넷의 실제 IP를 할당하므로, Pod의 트래픽은 별도 NAT 없이 VPC 네트워크에 직접 참여합니다.
  3. Route Table에서 0.0.0.0/0 → NAT Gateway 경로를 따라 NAT Gateway로 전달됩니다.
  4. NAT Gateway가 Private IP를 Elastic IP로 변환(SNAT)하여 Internet Gateway로 전달합니다.
  5. Internet Gateway를 통해 외부 인터넷에 도달합니다.

핵심 포인트:

  • EKS의 VPC CNI는 Pod에 VPC 서브넷의 실제 IP를 할당합니다. 따라서 Pod의 네트워크 동작은 해당 서브넷의 EC2 인스턴스와 동일합니다.
  • Worker Node가 Private Subnet에 있으면 NAT Gateway가 필수입니다. Public Subnet에 있으면 Node에 Public IP가 있어야 합니다.
  • Pod → 외부 경로에서 Security Group, NACL, Route Table 중 하나라도 차단하면 통신이 실패합니다.

2. 진단 순서: 5단계 체크

외부 인터넷 접근이 안 될 때, 아래 순서로 원인을 좁힙니다. 가장 흔한 원인(NAT Gateway, Route Table)부터 시작하여 점점 세부적인 항목으로 진행합니다.

EKS Pod 외부 인터넷 접근 진단 흐름
EKS Pod 외부 인터넷 접근 진단 흐름

2-1. Pod에서 외부 연결 테스트

먼저 Pod 내부에서 외부 접근이 실제로 안 되는지 확인합니다.

# 디버그 Pod 생성하여 테스트
kubectl run test-net --rm -it --image=busybox:1.36 -- sh

# IP 직접 접근 테스트 (DNS 제외)
wget -qO- --timeout=5 http://1.1.1.1
# 또는
nc -zv -w 5 1.1.1.1 80

# DNS 해석 테스트
nslookup google.com

# HTTPS 외부 API 테스트
wget -qO- --timeout=5 https://httpbin.org/ip

판단 기준:

결과 의미 다음 단계
IP 직접 접근 실패 + DNS 실패 네트워크 경로 문제 (NAT/Route/SG) 2-2로 이동
IP 직접 접근 성공 + DNS 실패 DNS 해석 문제 섹션 3-5로 이동
IP 직접 접근 성공 + DNS 성공 특정 대상만 차단됨 SG/NACL에서 특정 포트 차단 확인
기존 Pod 성공 + 새 Pod 실패 IP 고갈 가능성 섹션 3-6으로 이동

2-2. Worker Node의 Subnet 유형 확인

# Worker Node가 속한 Subnet 확인
kubectl get nodes -o wide
# INTERNAL-IP 칼럼의 IP로 Subnet 식별

# AWS CLI로 Subnet 정보 확인
aws ec2 describe-subnets --subnet-ids <subnet-id> \
  --query 'Subnets[].{ID:SubnetId, AZ:AvailabilityZone, CIDR:CidrBlock, MapPublicIP:MapPublicIpOnLaunch}'

판단 기준:

  • MapPublicIpOnLaunch: false → Private Subnet → NAT Gateway 필요
  • MapPublicIpOnLaunch: true → Public Subnet → Node에 Public IP 확인 필요

2-3. Route Table 확인

# Subnet에 연결된 Route Table 확인
aws ec2 describe-route-tables \
  --filters "Name=association.subnet-id,Values=<subnet-id>" \
  --query 'RouteTables[].Routes[?DestinationCidrBlock==`0.0.0.0/0`]'

정상 상태 (Private Subnet):

{
  "DestinationCidrBlock": "0.0.0.0/0",
  "NatGatewayId": "nat-0abc1234def56789",
  "State": "active"
}

비정상 패턴:

상태 의미
0.0.0.0/0 경로 자체가 없음 NAT Gateway 경로 미설정
State: blackhole NAT Gateway가 삭제되었거나 장애
GatewayId: igw-xxx Internet Gateway 직접 연결 (Public Subnet 설정)

2-4. NAT Gateway 상태 확인

# NAT Gateway 상태 확인
aws ec2 describe-nat-gateways \
  --filter "Name=state,Values=available,failed,deleting" \
  --query 'NatGateways[].{ID:NatGatewayId, State:State, SubnetId:SubnetId, ConnType:ConnectivityType}'

NAT Gateway 상태별 의미:

상태 의미 조치
available 정상 다른 원인 확인
failed 생성 실패 Elastic IP 한도, Subnet에 IGW 연결 여부 확인
deleting / 존재하지 않음 삭제됨 재생성 필요

2-5. Security Group 확인

# Worker Node의 Security Group 확인
aws ec2 describe-instances \
  --filters "Name=tag:eks:cluster-name,Values=<cluster-name>" \
  --query 'Reservations[].Instances[].{ID:InstanceId, SG:SecurityGroups[].GroupId}'

# Outbound 규칙 확인
aws ec2 describe-security-groups \
  --group-ids <sg-id> \
  --query 'SecurityGroups[].IpPermissionsEgress[]'

3. 원인별 분석

3-1. NAT Gateway 미설정 또는 장애

가장 흔한 원인입니다. Private Subnet의 Worker Node에서 외부 인터넷에 접근하려면 NAT Gateway가 필수입니다.

증상:

  • 클러스터 내 모든 Pod에서 외부 접근 타임아웃
  • Node 자체에서도 외부 접근 불가 (SSM Session Manager로 접속 시 확인 가능)
  • ECR에서 이미지 pull 실패 (ImagePullBackOff 동반 가능)

실무 시나리오:

EKS 클러스터를 Terraform으로 구성했습니다. 비용 절감을 위해 개발 환경에서 NAT Gateway를 삭제했다가 복원하는 것을 잊었습니다. 또는 NAT Gateway를 AZ당 1개씩 운영하는 고가용성 구성에서, 특정 AZ의 NAT Gateway가 삭제되면 해당 AZ의 Pod만 외부 통신이 끊깁니다.

확인 방법:

# 1. Route Table에서 NAT Gateway 경로 확인
aws ec2 describe-route-tables \
  --filters "Name=association.subnet-id,Values=<subnet-id>" \
  --query 'RouteTables[].Routes[?DestinationCidrBlock==`0.0.0.0/0`]'

# 2. NAT Gateway 상태 확인
aws ec2 describe-nat-gateways \
  --filter "Name=nat-gateway-id,Values=<nat-gw-id>" \
  --query 'NatGateways[].State'

# 3. NAT Gateway의 CloudWatch 메트릭 확인
# - ErrorPortAllocation: 포트 고갈 (동시 연결 55,000개 초과)
# - PacketsDropCount: 패킷 드롭 발생

해결:

# NAT Gateway가 없으면 생성
aws ec2 create-nat-gateway \
  --subnet-id <public-subnet-id> \
  --allocation-id <elastic-ip-alloc-id>

# Route Table에 경로 추가
aws ec2 create-route \
  --route-table-id <rtb-id> \
  --destination-cidr-block 0.0.0.0/0 \
  --nat-gateway-id <nat-gw-id>
비용 고려사항
NAT Gateway는 시간당 약 $0.045 + 데이터 처리 비용($0.045/GB)이 발생합니다. 개발/테스트 환경에서 비용이 부담되면 NAT Instance(t3.nano)를 대안으로 고려할 수 있습니다. 다만 NAT Instance는 가용성과 대역폭이 낮으므로 프로덕션에는 권장되지 않습니다.

3-2. Route Table에 NAT Gateway 경로 누락

NAT Gateway는 존재하지만, Worker Node가 있는 Subnet의 Route Table에 해당 NAT Gateway로의 경로가 없는 경우입니다.

증상:

  • 특정 Subnet(AZ)의 Pod만 외부 접근 실패
  • 다른 AZ의 Pod는 정상 동작

실무 시나리오:

EKS 클러스터에 새로운 AZ를 추가하면서 Private Subnet을 생성했습니다. Subnet은 만들었지만, Route Table 연결(Association)을 잊어서 기본(Main) Route Table이 적용됩니다. Main Route Table에는 NAT Gateway 경로가 없어서 해당 Subnet의 Pod만 외부 통신이 불가능합니다.

확인 방법:

# 1. 각 Subnet의 Route Table 연결 확인
aws ec2 describe-route-tables \
  --query 'RouteTables[].{RTB:RouteTableId, Associations:Associations[].SubnetId, Routes:Routes[?DestinationCidrBlock==`0.0.0.0/0`].{Dst:DestinationCidrBlock,Target:NatGatewayId,State:State}}'

# 2. Main Route Table 여부 확인 (명시적 연결이 없으면 Main이 적용됨)
aws ec2 describe-route-tables \
  --filters "Name=association.main,Values=true" "Name=vpc-id,Values=<vpc-id>"

해결:

# Subnet에 올바른 Route Table 연결
aws ec2 associate-route-table \
  --route-table-id <private-rtb-id> \
  --subnet-id <new-subnet-id>

설계 권장사항:

  • AZ당 Private Subnet용 Route Table을 분리하고, 각각 해당 AZ의 NAT Gateway를 가리키도록 설정합니다.
  • Terraform이나 CloudFormation으로 Subnet과 Route Table Association을 함께 관리하면 누락을 방지할 수 있습니다.

3-3. Security Group Outbound 규칙 차단

EKS Worker Node의 Security Group에서 Outbound(Egress) 트래픽이 제한된 경우입니다. EKS 기본 설정에서는 Outbound All Traffic을 허용하지만, 보안 강화를 위해 Outbound를 제한한 경우 외부 통신이 차단될 수 있습니다.

증상:

  • 특정 포트(예: 443)는 되는데 다른 포트는 안 됨
  • 또는 모든 외부 통신이 차단됨
  • 클러스터 내부 통신(Pod 간, Service 간)은 정상

실무 시나리오:

보안팀의 요구사항으로 Worker Node Security Group의 Outbound를 "All Traffic Allow"에서 필요한 포트만 허용하는 방식으로 변경했습니다. HTTPS(443)만 열었는데, 애플리케이션이 외부 API를 8080 포트로 호출하거나 SMTP(587)를 사용하는 경우 해당 통신만 차단됩니다.

확인 방법:

# Worker Node SG의 Outbound 규칙 확인
aws ec2 describe-security-groups \
  --group-ids <node-sg-id> \
  --query 'SecurityGroups[].IpPermissionsEgress[]'

# EKS 관리형 SG도 확인 (eks-cluster-sg-xxx)
aws ec2 describe-security-groups \
  --filters "Name=tag:aws:eks:cluster-name,Values=<cluster-name>" \
  --query 'SecurityGroups[].{ID:GroupId, Name:GroupName, Egress:IpPermissionsEgress}'

해결:

# 필요한 Outbound 규칙 추가
aws ec2 authorize-security-group-egress \
  --group-id <sg-id> \
  --protocol tcp \
  --port 443 \
  --cidr 0.0.0.0/0

# 또는 전체 Outbound 허용 (보안 요건에 따라 판단)
aws ec2 authorize-security-group-egress \
  --group-id <sg-id> \
  --protocol -1 \
  --cidr 0.0.0.0/0

EKS에서 필수로 열어야 하는 Outbound 포트:

포트 대상 용도
443 0.0.0.0/0 EKS API Server, ECR, CloudWatch, STS
10250 클러스터 SG kubelet 통신
53 (TCP/UDP) VPC DNS (x.x.x.2) DNS 해석
앱 의존 포트 외부 API 애플리케이션 요구사항
Tip
Security Group은 Stateful이므로 Outbound를 허용하면 응답 트래픽(Inbound)은 자동 허용됩니다. 반면 NACL은 Stateless이므로 양방향 모두 명시적 허용이 필요합니다.

3-4. NACL(Network ACL) 규칙 차단

NACL은 Subnet 수준에서 동작하며, Security Group보다 먼저 평가됩니다. 기본 NACL은 모든 트래픽을 허용하지만, 커스텀 NACL을 적용한 경우 Outbound 또는 Return 트래픽이 차단될 수 있습니다.

증상:

  • 특정 Subnet에서만 외부 접근 실패
  • Security Group은 정상인데도 통신 불가
  • 간헐적 실패 (Ephemeral Port 범위가 부분 차단된 경우)

실무 시나리오:

네트워크 팀이 Subnet에 커스텀 NACL을 적용하면서 Outbound는 열었지만, Inbound의 Ephemeral Port(1024-65535)를 허용하지 않았습니다. TCP 연결은 성립하지만 응답 패킷이 NACL에서 차단되어 타임아웃이 발생합니다.

확인 방법:

# Subnet에 연결된 NACL 확인
aws ec2 describe-network-acls \
  --filters "Name=association.subnet-id,Values=<subnet-id>" \
  --query 'NetworkAcls[].{ID:NetworkAclId, Entries:Entries}'

정상 NACL 설정 (Private Subnet):

방향 규칙 번호 프로토콜 포트 범위 대상 동작
Outbound 100 TCP 443 0.0.0.0/0 ALLOW
Outbound 110 TCP 80 0.0.0.0/0 ALLOW
Outbound 120 UDP 53 VPC CIDR ALLOW
Inbound 100 TCP 1024-65535 0.0.0.0/0 ALLOW
Inbound 110 UDP 1024-65535 0.0.0.0/0 ALLOW

해결:

# Inbound Ephemeral Port 허용 추가
aws ec2 create-network-acl-entry \
  --network-acl-id <nacl-id> \
  --rule-number 100 \
  --protocol tcp \
  --port-range From=1024,To=65535 \
  --cidr-block 0.0.0.0/0 \
  --rule-action allow \
  --ingress
NACL vs Security Group 차이
NACL은 Stateless이므로 Outbound를 허용해도 응답 트래픽을 별도로 Inbound에서 허용해야 합니다. 이 점을 놓치면 "보내는 건 되는데 응답이 안 온다"는 증상이 나타납니다. 대부분의 경우 기본 NACL(All Allow)을 사용하고, 추가 제어가 필요한 경우에만 커스텀 NACL을 적용하는 것이 운영 복잡도를 줄입니다.

3-5. DNS 해석 실패

IP 직접 접근은 되지만 도메인 이름으로 접근하면 실패하는 경우입니다. CoreDNS Pod의 문제이거나, VPC DNS 설정 문제일 수 있습니다.

증상:

  • wget http://1.1.1.1 → 성공
  • wget http://google.com → 실패 (Name or service not known)
  • nslookup google.com → timeout 또는 SERVFAIL

실무 시나리오:

EKS 클러스터의 CoreDNS Pod가 Pending 또는 CrashLoopBackOff 상태입니다. 또는 VPC의 enableDnsSupport가 비활성화되어 VPC DNS 서버(x.x.x.2)에 질의할 수 없습니다. CoreDNS가 외부 도메인을 resolve할 때 VPC DNS 서버로 포워딩하는데, 이 경로가 막히면 모든 외부 도메인 해석이 실패합니다.

확인 방법:

# 1. CoreDNS Pod 상태 확인
kubectl get pods -n kube-system -l k8s-app=kube-dns

# 2. Pod에서 DNS 서버 설정 확인
kubectl run test-dns --rm -it --image=busybox:1.36 -- cat /etc/resolv.conf
# nameserver 10.100.0.10 (CoreDNS Service ClusterIP)

# 3. CoreDNS로 직접 질의
kubectl run test-dns --rm -it --image=busybox:1.36 -- nslookup google.com 10.100.0.10

# 4. VPC DNS 설정 확인
aws ec2 describe-vpc-attribute --vpc-id <vpc-id> --attribute enableDnsSupport
aws ec2 describe-vpc-attribute --vpc-id <vpc-id> --attribute enableDnsHostnames

해결:

# CoreDNS가 비정상이면 재시작
kubectl rollout restart deployment/coredns -n kube-system

# VPC DNS 지원 활성화
aws ec2 modify-vpc-attribute --vpc-id <vpc-id> --enable-dns-support

# CoreDNS 로그 확인 (포워딩 실패 원인 파악)
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50

CoreDNS 문제의 근본 원인 후보:

원인 확인 방법
CoreDNS Pod 리소스 부족 kubectl top pod -n kube-system -l k8s-app=kube-dns
CoreDNS Pod가 스케줄링 안 됨 Node의 리소스 여유, Taint/Toleration 확인
VPC DNS 속도 제한 (1024 패킷/초/인터페이스) 대규모 클러스터에서 DNS 쿼리 급증 시
Security Group에서 UDP 53 차단 Node SG에서 VPC CIDR로의 UDP 53 Outbound 확인

3-6. VPC CNI IP 주소 고갈

EKS의 VPC CNI 플러그인은 Pod에 VPC Subnet의 실제 IP를 할당합니다. Subnet의 가용 IP가 소진되면 새 Pod에 IP를 할당할 수 없어 네트워크 인터페이스 없이 시작됩니다.

증상:

  • 기존 Pod는 정상 동작하지만 새 Pod가 생성되면 외부 통신 불가
  • Pod가 ContainerCreating 상태에서 멈춤
  • Node Events에 InsufficientFreeAddresses 또는 failed to assign an IP address to pod 메시지

실무 시나리오:

/24 Subnet(가용 IP 251개)에 Worker Node 5대를 운영합니다. 각 Node가 ENI를 통해 미리 IP를 확보(Warm Pool)하면서 실제 Pod 수보다 많은 IP를 점유합니다. Node당 최대 Pod 수는 인스턴스 타입에 따라 다르며(예: m5.large는 최대 29개), 전체 Subnet IP가 모자라면 새 Pod 생성이 실패합니다.

확인 방법:

# 1. Subnet의 가용 IP 수 확인
aws ec2 describe-subnets \
  --subnet-ids <subnet-id> \
  --query 'Subnets[].{CIDR:CidrBlock, AvailableIPs:AvailableIpAddressCount}'

# 2. Node별 할당 가능 Pod 수 확인
kubectl describe node <node-name> | grep -A 5 "Allocatable"
# pods: 29 (인스턴스 타입별로 다름)

# 3. CNI 로그에서 IP 할당 실패 확인
kubectl logs -n kube-system -l k8s-app=aws-node --tail=50

# 4. 현재 ENI 및 IP 할당 상태 확인
kubectl get eniconfigs  # Custom Networking 사용 시

해결:

# 방법 1: Subnet CIDR 확장 (Secondary CIDR 추가)
aws ec2 associate-vpc-cidr-block --vpc-id <vpc-id> --cidr-block 100.64.0.0/16
aws ec2 create-subnet --vpc-id <vpc-id> --cidr-block 100.64.1.0/24 --availability-zone ap-northeast-2a

# 방법 2: VPC CNI Prefix Delegation 활성화
kubectl set env daemonset aws-node -n kube-system ENABLE_PREFIX_DELEGATION=true
# /28 prefix 단위로 할당하여 Node당 할당 가능 IP를 대폭 증가

# 방법 3: Custom Networking으로 Pod 전용 Subnet 분리
kubectl set env daemonset aws-node -n kube-system AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG=true
Prefix Delegation
Prefix Delegation을 활성화하면 ENI당 할당 가능한 IP가 대폭 증가합니다. 예를 들어 m5.large는 기존 최대 29개에서 최대 110개까지 늘어날 수 있습니다. 다만 Subnet에 /28 블록 단위의 연속 IP가 필요하므로, 이미 IP가 파편화된 Subnet에서는 효과가 제한적일 수 있습니다.

3-7. Pod가 Public Subnet에 배치되었으나 Public IP 미할당

EKS Worker Node가 Public Subnet에 있지만 Node에 Public IP가 할당되지 않은 경우입니다. Public Subnet은 Internet Gateway로의 경로가 있지만, 소스 IP가 Private IP이면 응답이 돌아올 수 없습니다.

증상:

  • NAT Gateway도 없고, Node에 Public IP도 없음
  • Route Table에 0.0.0.0/0 → igw-xxx는 있지만 통신 불가

실무 시나리오:

EKS Managed Node Group을 생성할 때 Public Subnet을 지정했지만, Launch Template에서 AssociatePublicIpAddress: false로 설정했습니다. 또는 Subnet의 MapPublicIpOnLaunch가 false인 Public Subnet에 Node를 배치했습니다.

확인 방법:

# Node의 Public IP 확인
aws ec2 describe-instances \
  --filters "Name=tag:eks:cluster-name,Values=<cluster-name>" \
  --query 'Reservations[].Instances[].{ID:InstanceId, PrivateIP:PrivateIpAddress, PublicIP:PublicIpAddress, SubnetId:SubnetId}'

해결:

  1. 권장: Worker Node를 Private Subnet으로 이동하고 NAT Gateway 사용
  2. 대안: Subnet의 자동 Public IP 할당 활성화
# Subnet의 자동 Public IP 할당 활성화
aws ec2 modify-subnet-attribute \
  --subnet-id <subnet-id> \
  --map-public-ip-on-launch

설계 권장사항:

구성 Worker Node 위치 외부 인터넷 경로 권장 환경
Private + NAT GW Private Subnet NAT Gateway 경유 프로덕션 (보안 우선)
Public + Public IP Public Subnet IGW 직접 개발/테스트 (비용 절감)
Private + VPC Endpoint Private Subnet VPC Endpoint (AWS 서비스만) 외부 인터넷 불필요 시

4. 원인 분류 한눈에 보기

EKS Pod 외부 인터넷 접근 실패 원인 분류
EKS Pod 외부 인터넷 접근 실패 원인 분류

5. 실무 시나리오: 신규 EKS 클러스터 배포 후 외부 통신 불가

상황: Terraform으로 EKS 클러스터를 새로 프로비저닝했습니다. Node는 Ready 상태이고 Pod는 Running인데, 애플리케이션 로그에 dial tcp: lookup api.stripe.com: i/o timeout이 반복됩니다.

진단 과정:

# 1. Pod에서 외부 연결 테스트
kubectl run test-net --rm -it --image=busybox:1.36 -- sh
wget -qO- --timeout=5 http://1.1.1.1
# 타임아웃 → 네트워크 경로 문제

# 2. Node의 Subnet 확인
kubectl get nodes -o wide
# NAME                          INTERNAL-IP   ...
# ip-10-0-3-45.ec2.internal    10.0.3.45     ...

aws ec2 describe-subnets --filters "Name=cidr-block,Values=10.0.3.0/24" \
  --query 'Subnets[].{ID:SubnetId, MapPublicIP:MapPublicIpOnLaunch}'
# MapPublicIpOnLaunch: false → Private Subnet 확인

# 3. Route Table 확인
aws ec2 describe-route-tables \
  --filters "Name=association.subnet-id,Values=subnet-0abc123" \
  --query 'RouteTables[].Routes'
# 결과: 0.0.0.0/0 경로가 없음!

# 4. 원인 식별
# Terraform 코드에서 Private Subnet용 Route Table에
# NAT Gateway 경로를 추가하는 리소스가 누락됨

# 5. 해결 — Terraform에 경로 추가

Terraform 수정:

resource "aws_route" "private_nat" {
  route_table_id         = aws_route_table.private.id
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id         = aws_nat_gateway.main.id
}

resource "aws_route_table_association" "private" {
  count          = length(var.private_subnet_ids)
  subnet_id      = var.private_subnet_ids[count.index]
  route_table_id = aws_route_table.private.id
}
# Terraform 적용
terraform plan
terraform apply

# 적용 후 확인
kubectl run test-net --rm -it --image=busybox:1.36 -- wget -qO- --timeout=5 https://httpbin.org/ip
# 응답 수신 확인

사후 분석:

  • VPC 모듈에서 Subnet, Route Table, NAT Gateway, Route를 하나의 단위로 관리하면 누락을 방지할 수 있습니다.
  • terraform plan에서 Route 리소스의 존재 여부를 확인하는 CI 검증 단계를 추가합니다.
  • EKS 클러스터 프로비저닝 후 자동 연결 테스트(smoke test)를 CI/CD 파이프라인에 포함합니다.

6. VPC Endpoint를 활용한 대안 설계

외부 인터넷 접근이 AWS 서비스(ECR, S3, CloudWatch 등) 호출만을 위한 것이라면, NAT Gateway 없이 VPC Endpoint로 대체할 수 있습니다.

NAT Gateway가 필요한 경우:

  • Pod가 외부 인터넷 API(Stripe, Twilio 등)를 호출해야 할 때
  • 외부 패키지 저장소(npm, PyPI 등)에 접근해야 할 때
  • 써드파티 SaaS 서비스와 통신해야 할 때

VPC Endpoint로 대체 가능한 경우:

  • AWS 서비스만 호출 (ECR, S3, CloudWatch Logs, STS, SSM 등)
  • 클러스터 운영에 필요한 최소 통신만 필요

EKS 운영에 필요한 주요 VPC Endpoint:

서비스 Endpoint 유형 용도
com.amazonaws.region.ecr.api Interface ECR API 호출
com.amazonaws.region.ecr.dkr Interface ECR 이미지 pull
com.amazonaws.region.s3 Gateway ECR 이미지 레이어 (S3 저장)
com.amazonaws.region.logs Interface CloudWatch Logs 전송
com.amazonaws.region.sts Interface IRSA (IAM Roles for Service Accounts)
com.amazonaws.region.ec2 Interface VPC CNI의 ENI 관리
비용 비교
NAT Gateway: ~$32/월(시간 비용) + 데이터 전송 비용. Interface VPC Endpoint: ~$7.2/월(AZ당) + 데이터 처리 비용. AWS 서비스만 호출하는 클러스터라면 VPC Endpoint가 비용 효율적입니다. 다만 Endpoint 수가 많아지면 누적 비용이 NAT Gateway를 초과할 수도 있으므로, 트래픽 패턴에 따라 판단해야 합니다.

7. 재발 방지 체크리스트

항목 확인 방법 권장
NAT Gateway 상태 CloudWatch NatGateway 네임스페이스 모니터링 알림 설정
Route Table 경로 IaC(Terraform)로 관리, plan 시 검증 CI 자동 검증
Subnet IP 가용량 CloudWatch SubnetAvailableIPs 메트릭 80% 임계치 알림
Security Group 변경 AWS Config 규칙으로 변경 감지 비인가 변경 알림
DNS 해석 Pod에서 주기적 health check CoreDNS 메트릭 모니터링
신규 클러스터 배포 후 자동 연결 테스트(smoke test) CI/CD에 통합
Multi-AZ NAT GW AZ별 독립 NAT Gateway + Route Table 단일 AZ 장애 격리

8. 정리

  • EKS Pod의 외부 인터넷 접근은 Route Table → NAT Gateway → Internet Gateway 경로가 정상이어야 동작합니다. VPC CNI가 Pod에 Subnet IP를 직접 할당하므로, Pod의 네트워크 동작은 EC2 인스턴스와 동일합니다.
  • 가장 흔한 원인은 NAT Gateway 미설정 또는 Route Table 경로 누락입니다. Private Subnet에 Worker Node를 배치했다면 반드시 NAT Gateway 경로가 있는지 확인합니다.
  • Security Group은 Stateful이라 Outbound만 확인하면 되지만, NACL은 Stateless이므로 Inbound의 Ephemeral Port(1024-65535)도 허용해야 합니다.
  • IP 직접 접근은 되는데 도메인이 안 되면 DNS 문제입니다. CoreDNS Pod 상태와 VPC DNS 설정을 확인합니다.
  • AWS 서비스만 호출하는 클러스터라면 VPC Endpoint로 NAT Gateway를 대체하여 비용을 절감할 수 있습니다.

참고 문서

반응형