- Published on
EKS Ingress 502인데 Pod 로그가 비면? ALB/NLB 헬스체크부터
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서버가 502를 뿜는데 애플리케이션 Pod 로그가 아무것도 안 쌓인다면, 문제는 대개 애플리케이션 내부가 아니라 로드밸런서 → 노드/파드로 트래픽이 전달되는 경로 어딘가에서 끊긴 것입니다. 특히 EKS에서는 Ingress(보통 ALB Ingress Controller/AWS Load Balancer Controller)와 Service(NodePort/ClusterIP), 그리고 Target Group(타깃그룹) 헬스체크가 얽히면서 “502 + 무로그” 조합이 자주 발생합니다.
이 글은 "Pod 로그가 비어 있다"는 단서를 출발점으로, ALB/NLB 헬스체크, 타깃그룹 등록 상태, 포트 매핑, 보안그룹/네트워크, readiness/liveness를 순서대로 좁혀가는 체크리스트입니다.
> ALB 자체 502/504 패턴이 더 넓게 필요하면: AWS ALB 502·504 난사 - 원인별 해결 체크리스트
증상 해석: “502 + Pod 로그 없음”이 의미하는 것
다음 중 하나일 가능성이 높습니다.
- ALB/NLB가 타깃(노드/파드/ENI)까지 연결을 못 함
- 타깃그룹은 연결되지만, 헬스체크가 실패하여 라우팅 대상이 없음
- Service/Ingress의 포트 매핑이 어긋나서 다른 포트로 전송
- 노드 보안그룹/네트워크 ACL/서브넷 라우팅 문제로 인바운드가 차단
- (ALB) 백엔드 프로토콜(HTTP/HTTPS), path, success code 불일치
핵심은 “요청이 파드까지 도달했는가?”입니다. 로그가 비면 대개 도달하지 못했습니다.
1) 먼저 확인: 502가 ALB/NLB에서 발생하는지, Ingress 컨트롤러에서 발생하는지
ALB라면
ALB 액세스 로그(가능하면 S3로 활성화) 또는 CloudWatch 지표에서 다음을 봅니다.
HTTPCode_ELB_5XX_Count증가 여부HTTPCode_Target_5XX_Count증가 여부
ELB_5XX가 오르면 ALB가 타깃과 통신 자체를 못 하거나, 타깃이 없거나, 연결/프로토콜 문제일 확률이 큽니다.
NGINX Ingress라면
NGINX Ingress Controller 로그에서 upstream 연결 실패가 보일 수 있습니다. 하지만 이번 주제는 EKS에서 ALB/NLB 경로가 중심이므로, AWS Load Balancer Controller 기반을 전제로 진행합니다.
2) 타깃그룹(Target Group) 상태부터 본다: Unhealthy면 Pod 로그는 비는 게 정상
ALB/NLB는 타깃그룹에 Healthy 타깃이 있어야 트래픽을 전달합니다. 타깃이 전부 Unhealthy면:
- 일부 케이스는 502/503로 빠지고
- 애플리케이션 파드는 요청을 못 받아서 로그가 비게 됩니다.
CLI로 타깃 상태 확인
aws elbv2 describe-target-health \
--target-group-arn <tg-arn>
여기서 State가 unhealthy이고 Reason이 다음 중 하나면 방향이 갈립니다.
Target.Timeout: 헬스체크 요청이 타깃까지 못 감(보안그룹/포트/라우팅)Target.ResponseCodeMismatch: 응답은 오는데 200대가 아님(path/프로토콜/앱 응답)Health checks failed+Connection refused: 포트가 열려있지 않거나 잘못된 포트로 감
3) 가장 흔한 실수: Ingress/Service/Container 포트 매핑 불일치
“Pod는 8080으로 뜨는데 Service는 80으로 보내고, Ingress는 또 443/80을 섞어 쓰는” 형태가 대표적입니다.
점검 순서
- Pod가 실제로 어떤 포트에서 리스닝하는지 확인
kubectl -n <ns> get pod -l app=myapp -o wide
kubectl -n <ns> exec -it <pod> -- sh -c "netstat -lntp || ss -lntp"
- Service의
port/targetPort확인
kubectl -n <ns> get svc myapp -o yaml
- Ingress가 가리키는 Service 포트 확인
kubectl -n <ns> get ingress myapp -o yaml
올바른 예시(HTTP 8080 앱)
apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
selector:
app: myapp
ports:
- name: http
port: 80
targetPort: 8080
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/backend-protocol: HTTP
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp
port:
number: 80
여기서 Ingress는 Service의 port(80) 를 바라보고, Service가 targetPort(8080) 으로 파드에 전달합니다.
잘못된 예시(자주 발생)
- Ingress가
servicePort: 8080을 바라보는데 Service에는 8080 포트가 없음 - Service
targetPort가 8080인데 실제 컨테이너는 8000에서 리스닝
이 경우 헬스체크가 실패하고, 결과적으로 502 + 무로그가 됩니다.
4) ALB 헬스체크 Path/Success code/Protocol이 앱과 맞는지
ALB는 기본적으로 헬스체크를 HTTP:80 / 같은 형태로 합니다. 앱이 /에서 301/302를 내거나, 인증이 걸려 401을 내거나, gRPC인데 HTTP로 체크하면 바로 Unhealthy가 됩니다.
확인할 것
- 헬스체크 Path:
/healthz,/ready등 항상 200을 주는 엔드포인트로 분리 - Success codes: 필요시
200-399로 확장 - Backend protocol: HTTP/HTTPS 일치
AWS Load Balancer Controller에서 흔히 쓰는 어노테이션 예:
metadata:
annotations:
alb.ingress.kubernetes.io/healthcheck-path: /healthz
alb.ingress.kubernetes.io/success-codes: "200-399"
alb.ingress.kubernetes.io/backend-protocol: HTTP
앱이 60초 이상 걸리는 요청으로 504가 난다면(이번 주제는 502지만 함께 자주 엮입니다): EKS ALB Ingress 504(60초) idle_timeout 해결
5) target-type이 instance인지 ip인지: EKS에서 결정적으로 갈리는 포인트
ALB Ingress에서 타깃 타입은 크게 두 가지입니다.
instance: 타깃그룹이 노드(EC2) 를 대상으로 잡고, 트래픽은 NodePort 로 들어갑니다.ip: 타깃그룹이 Pod IP 를 대상으로 잡고, 트래픽이 파드로 직접 갑니다.
instance 타깃에서 자주 터지는 이유
- Service가
NodePort가 아니면(ClusterIP만 있으면) 노드로 들어온 트래픽이 파드로 못 갑니다. - 노드 보안그룹에서 NodePort 범위(기본 30000-32767) 인바운드가 막혀 있으면 헬스체크 실패
ip 타깃에서 자주 터지는 이유
- 서브넷/보안그룹 설정이 파드 IP로의 트래픽을 허용하지 않음
- CNI/보안그룹 for pods 설정과 충돌
Ingress 어노테이션에서 확인:
alb.ingress.kubernetes.io/target-type: ip
타깃 타입을 바꿨다면, Service 타입/보안그룹 규칙도 함께 재점검해야 합니다.
6) 보안그룹/네트워크: “헬스체크 Timeout”이면 거의 여기다
타깃 헬스 상태 Reason이 Target.Timeout이면, 높은 확률로 보안그룹 인바운드 또는 NACL/라우팅 문제입니다.
빠른 체크
- ALB SG → 노드 SG(또는 Pod SG)로 앱 포트/NodePort 허용되어 있는가?
- 노드 SG 인바운드에 ALB SG를 소스로 한 규칙이 있는가?
- NACL이 ephemeral 포트/리턴 트래픽을 막고 있지 않은가?
특히 instance 타깃이면 노드로 들어오는 포트는 앱 포트가 아니라 NodePort입니다.
> EKS 네트워크/노드 상태가 전반적으로 불안정하면 이 글의 점검 루틴도 도움이 됩니다: Terraform apply 후 EKS 노드 NotReady - CNI·IRSA·보안그룹 점검
7) “Pod 로그가 비다”를 확정하는 내부 테스트: 클러스터 내부에서 Service까지는 되나?
로드밸런서 이전에, Service → Pod 라우팅이 되는지 먼저 확인하면 원인 범위를 크게 줄일 수 있습니다.
임시 디버그 Pod로 Service 호출
kubectl -n <ns> run tmp-curl --rm -it \
--image=curlimages/curl:8.5.0 -- sh
# 쉘 안에서
curl -sv http://myapp.<ns>.svc.cluster.local:80/healthz
- 여기서도 실패하면: Service selector, endpoints, readiness 문제
- 여기서는 성공인데 외부에서만 502면: ALB/NLB, 타깃그룹, 보안그룹, 헬스체크 문제
Endpoints가 비어 있지 않은지 확인
kubectl -n <ns> get endpoints myapp -o wide
# 또는
kubectl -n <ns> get endpointSlice -l kubernetes.io/service-name=myapp
Endpoints가 비어 있으면 ALB가 아무리 정상이어도 트래픽이 갈 곳이 없습니다. 보통은 readinessProbe 실패 또는 Service selector 오타가 원인입니다.
8) readinessProbe가 헬스체크와 충돌하는 케이스
Kubernetes readinessProbe가 실패하면 해당 Pod는 Endpoints에서 빠집니다. 그러면:
- Pod는 Running인데
- Service에는 엔드포인트가 없고
- ALB는 Unhealthy/No targets가 되어
- 결과적으로 502 + 무로그가 됩니다.
readinessProbe 예시(권장)
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 3
여기서 /ready는 의존성(DB, 외부 API 등)이 준비되지 않으면 실패하도록 설계하는 게 일반적입니다. 다만 그 의존성이 일시적으로 불안정하면 트래픽이 전부 끊길 수 있으니, 운영 정책에 맞춰 설계해야 합니다.
9) NLB(특히 TLS/Proxy Protocol)에서의 502/무로그 포인트
NLB는 L4라서 “502”라는 표현은 보통 앞단(클라이언트/CloudFront/ALB)이나 애플리케이션 프록시에서 만들어질 때가 많지만, EKS에서는 NLB + ingress-nginx 조합에서 다음 문제가 자주 납니다.
- NLB 헬스체크가 TCP인데 실제로는 HTTP path가 필요
- Proxy Protocol 활성화했는데 NGINX가 이를 해석하지 못해 연결이 깨짐
- TLS 종료 지점이 꼬여서(예: NLB TLS → NGINX HTTP 기대) 핸드셰이크 실패
이 경우도 파드 로그가 비는 경우가 많습니다(핸드셰이크 단계에서 종료되면 애플리케이션까지 못 옴).
10) 실전 트러블슈팅 플로우(10~15분 컷)
아래 순서대로 보면 “어디서 끊겼는지”가 빠르게 드러납니다.
Ingress 이벤트 확인
kubectl -n <ns> describe ingress myapp- AWS Load Balancer Controller가 에러를 뱉는지(권한/어노테이션/리소스 생성 실패)
Target Group health 확인 (
describe-target-health)- Timeout이면 보안그룹/포트
- ResponseCodeMismatch면 path/success code
Service endpoints 확인
kubectl -n <ns> get endpoints myapp -o wide클러스터 내부에서 Service curl
- 성공이면 LB/네트워크 쪽
- 실패면 Service selector/targetPort/readiness
포트 매핑 재검증 (Ingress servicePort ↔ Service port/targetPort ↔ containerPort)
target-type(instance/ip)와 Service 타입/보안그룹 정합성 확인
마무리: “무로그 502”는 애플리케이션이 아니라 경로 문제일 때가 대부분
EKS에서 Ingress 502가 나는데 Pod 로그가 비어 있으면, 먼저 애플리케이션 디버깅에 시간을 쓰기보다 (1) 타깃그룹 Healthy 여부 (2) 헬스체크 설정 (3) 포트 매핑 (4) 보안그룹/NodePort (5) endpoints/readiness를 확인하는 게 훨씬 빠릅니다.
특히 타깃그룹 Reason(Timeout vs ResponseCodeMismatch vs Connection refused)을 읽는 순간, 원인의 70%는 이미 좁혀집니다. 그 다음은 curl로 내부/외부 경로를 분리해 “어디까지 도달하는지”를 확인하면 됩니다.
필요하다면 다음 글도 함께 보며 502/504 패턴을 확장해서 점검하세요.