EKS 에서 ingress-nginx 컨트롤러를 Service type: LoadBalancer 로 띄우면 AWS Network Load Balancer 가 붙는다. Route 53 도메인까지 얹은 뒤 브라우저나 curl 로 접근할 때 나오는 증상은 크게 세 가지다 — 연결 자체가 안 되는 connection timed out, 간헐적으로 응답이 멈추는 hang, 그리고 애플리케이션까지 도달했지만 인증에서 막히는 401. 증상마다 봐야 할 계층이 다르므로 아래 순서대로 좁힌다.
요청은 클라이언트 → Route 53 → NLB → 노드(NodePort) → ingress-nginx 파드 → 백엔드 서비스 를 지난다. 어느 구간에서 끊기는지부터 가른다.
# 1. 도메인이 NLB 를 가리키는가
dig +short app.example.com
# 2. NLB 자체가 응답하는가 (도메인을 건너뛴다)
curl -sv -o /dev/null http://<nlb-dns-name>/
# 3. 대상 그룹이 healthy 인가
aws elbv2 describe-target-health --target-group-arn <arn>
# 4. 컨트롤러 뒤의 엔드포인트가 살아 있는가
kubectl get endpoints -n <namespace>
kubectl logs -n ingress-nginx <controller-pod>
2번이 되는데 1번이 안 되면 DNS 문제, 2번이 안 되는데 4번이 정상이면 보안 그룹·대상 그룹 문제, 4번에서 엔드포인트가 비어 있으면 서비스 셀렉터 문제다.
도메인까지는 풀리는데 응답이 없는 경우 대부분 아래 셋 중 하나다.
Route 53 레코드는 NLB 의 DNS 이름을 Alias A 레코드로 잡아야 한다. NLB 의 IP 는 고정이 아니므로 IP 를 직접 A 레코드에 박으면 언젠가 끊긴다. CNAME 은 zone apex 에 쓸 수 없으므로 apex 도메인이면 Alias 가 사실상 유일한 선택이다.
보안 그룹은 두 곳을 본다. NLB 의 리스너 포트(80/443)로 들어오는 인바운드와, 워커 노드가 NLB 로부터 NodePort 대역(기본 30000-32767)을 받도록 허용하는 인바운드다. 두 번째를 빠뜨리면 NLB 대상 그룹이 전부 unhealthy 로 남는다.
내부 통신용 서브넷에 NLB 가 만들어졌는지도 본다. 인터넷에서 접근하려면 service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing 이고 퍼블릭 서브넷에 kubernetes.io/role/elb 태그가 있어야 한다.
클러스터 노드 안에서 NLB 주소로 요청할 때만 간헐적으로 멈추고 외부에서는 정상이라면 hairpin(루프백) 경로를 의심한다. 대상 유형이 instance 인 NLB 로 노드가 자기 자신에게 요청을 돌려보내면 NLB 는 소스 IP 를 보존한 채 같은 노드로 되돌리고, 커널이 그 흐름을 정상 응답으로 인식하지 못해 응답이 오지 않는다. 대상 유형을 ip 로 바꾸거나(AWS Load Balancer Controller + VPC CNI 필요), 클러스터 내부에서는 NLB 주소 대신 Service 의 클러스터 DNS 이름으로 접근해 우회한다.
부하가 없는데 오래 열어 둔 연결이 끊기는 형태라면 NLB 의 idle timeout 을 본다. 기본값은 350초로 고정돼 있고, keep-alive 연결이 그 시간을 넘으면 NLB 가 조용히 끊는다. 클라이언트와 ingress-nginx 양쪽의 keep-alive 시간을 그보다 짧게 잡아 먼저 재사용을 끝내는 편이 안전하다.
# ingress-nginx ConfigMap
data:
keep-alive: "60"
upstream-keepalive-timeout: "60"
worker-processes: "auto"
재현 여부를 확인할 때는 반복 호출로 응답 시간을 모아 본다.
while true; do
curl -s -o /dev/null -w "$(date +%T) code=%{http_code} time=%{time_total}\n" \
--max-time 10 http://app.example.com/healthz
sleep 1
done
여기까지 왔다면 네트워크는 정상이고 인증 계층의 문제다. 두 갈래로 나뉜다.
ingress 에 basic auth 애노테이션(nginx.ingress.kubernetes.io/auth-type, auth-secret, auth-url)이 붙어 있으면 ingress-nginx 가 백엔드에 닿기 전에 401 을 돌려준다. 의도한 설정이 아니면 애노테이션을 지운다.
애노테이션이 없다면 401 은 백엔드 애플리케이션이 낸 것이다. Full authentication is required to access this resource 는 Spring Security 의 기본 메시지이므로, 프록시가 Authorization 헤더를 그대로 넘기고 있는지부터 확인한다. 리버스 프록시를 두 단 이상 거치면 헤더가 중간에서 잘리는 일이 있다.