AWS EKS에서 ALB Ingress + Node.js 앱의 502/503/504 오류 이해와 해결

AWS EKS 환경에서 AWS ALB Ingress Controller와 Node.js 백엔드를 운영하다 보면 502, 503, 504와 같은 HTTP 오류 코드를 마주하게 됩니다. 처음 이 오류들을 접하면 직관적으로 이해하기 어렵습니다. 503 오류가 발생했을 때 “로드 밸런서에 연결된 타겟이 없는 것인가?”라고 추측하거나, 502 오류를 보고 “애플리케이션이 죽었나?”라고 오해하기 쉽습니다. 하지만 실제 원인을 분석해보면 이 상태 코드들의 의미와 발생 조건은 미묘하게 다릅니다.

이 글에서는 HTTP 502 / 503 / 504 오류의 의미와 차이를 명확히 하고, AWS EKS + ALB Ingress + Node.js 아키텍처에서 발생하는 구체적인 원인과 해결 방법을 다룹니다. RFC 표준 정의AWS 공식 문서를 근거로 개념을 정립하고, 실무에서 바로 적용 가능한 트러블슈팅 가이드를 제공합니다.


1. 503 – 타겟이 없다는 뜻일까?

503 Service Unavailable 오류는 이름에서 알 수 있듯 “서비스를 이용할 수 없음”을 의미합니다. 처음에는 단순히 서버가 다운된 상황으로 생각하기 쉽지만, 로드 밸런서 환경에서는 조금 더 구체적인 의미를 가집니다.

정의와 원인

RFC 7231에 따르면 503 코드는 일시적인 과부하나 점검 등으로 서버가 요청을 처리할 수 없는 상태를 의미합니다.

“The 503 (Service Unavailable) status code indicates that the server is currently unable to handle the request due to a temporary overload or scheduled maintenance…”RFC 7231 Section 6.6.4

AWS ALB 환경에서 503 오류는 주로 로드 밸런서가 요청을 전달할 유효한 타겟(Target)을 찾지 못했을 때 발생합니다. AWS 공식 문서는 다음과 같은 상황을 명시합니다.

“The target groups for the load balancer have no registered targets, or all of the registered targets are in an unused state.”Troubleshoot your Application Load Balancers

Kubernetes 환경에서는 다음과 같은 경우에 해당합니다:

  1. 타겟 없음 (No Targets): Service의 Selector가 Deployment의 라벨과 일치하지 않아 Endpoints가 비어있는 경우 (kubectl get endpoints 결과가 <none>).
  2. 타겟 비활성 (Unhealthy Targets): Pod가 존재하지만 Readiness Probe를 통과하지 못해 트래픽을 받을 준비가 되지 않은 경우. 이 경우 ALB는 해당 타겟을 ‘Unhealthy’ 또는 ‘Unused’로 간주하여 요청을 보내지 않습니다.
  3. Ingress 설정 오류: Ingress 리소스가 존재하지 않는 Service나 잘못된 포트를 가리키고 있을 때.

동작 흐름

sequenceDiagram
    participant Client
    participant ALB
    participant TargetGroup
    
    Client->>ALB: HTTP Request
    ALB->>TargetGroup: Select Healthy Target
    TargetGroup-->>ALB: No Healthy Targets Available
    ALB-->>Client: 503 Service Unavailable

중요한 점은 503 오류가 항상 ALB에서 생성되는 것은 아니라는 사실입니다. 백엔드 애플리케이션이 직접 503 응답을 보낼 수도 있습니다. 이를 구분하기 위해서는 CloudWatch 지표를 확인해야 합니다.

  • HTTPCode_ELB_5XX 증가: ALB가 타겟을 찾지 못해 자체적으로 반환한 경우.
  • HTTPCode_Target_5XX 증가: 백엔드 애플리케이션이 503을 반환한 경우.

실무 팁: Readiness Probe 확인

503 오류 발생 시 가장 먼저 kubectl get endpoints <서비스명>을 확인하세요. 만약 Endpoints가 비어있다면 Service Selector를 점검해야 합니다. Endpoints는 있지만 접근이 안 된다면, Pod의 Readiness Probe 설정을 확인해야 합니다. 애플리케이션 구동 시간이 긴데 Probe 대기 시간이 짧다면, Pod가 영원히 Ready 상태가 되지 못해 503이 발생할 수 있습니다. 관련 개념: Readiness Probe, Kubernetes Service


2. 502 – Node.js 서버가 연결을 끊었나?

502 Bad Gateway 오류는 “잘못된 게이트웨이”라는 의미로, ALB가 백엔드 서버로부터 유효하지 않은 응답을 받았음을 나타냅니다.

정의와 원인

RFC 7231에서는 게이트웨이나 프록시가 상류 서버(Upstream Server)로부터 유효하지 않은 응답을 받았을 때 502를 반환한다고 정의합니다.

“The 502 (Bad Gateway) status code indicates that the server, while acting as a gateway or proxy, received an invalid response from an inbound server…”RFC 7231 Section 6.6.3

AWS EKS + Node.js 환경에서 502 오류의 가장 흔한 원인은 TCP 연결 종료 타이밍의 불일치(Keep-Alive Mismatch) 입니다.

  1. Keep-Alive Timeout 불일치: Node.js의 기본 keepAliveTimeout5초인 반면, AWS ALB의 기본 idle timeout60초입니다.
  2. 시나리오: ALB는 60초 동안 연결이 유지될 것이라 기대하고 유휴 상태인 연결을 재사용하여 요청을 보냅니다. 하지만 Node.js는 5초가 지났으므로 이미 소켓 연결을 끊어버립니다(TCP RST 또는 FIN).
  3. 결과: ALB는 닫힌 소켓으로 요청을 보내려다 실패하고, 클라이언트에게 502 Bad Gateway를 반환합니다.

AWS 문서는 이를 다음과 같이 설명합니다:

“…if the application closes the TCP connection to the load balancer ungracefully, the load balancer might send a request to the application before it receives the packet indicating that the connection is closed.”Troubleshoot your Application Load Balancers: HTTP 502

이 외에도 애플리케이션 크래시(OOM 등) 로 인해 프로세스가 즉시 종료되거나, HTTP 헤더 크기 초과로 인해 ALB가 응답을 파싱 하지 못할 때도 502가 발생합니다.

동작 흐름

sequenceDiagram
    participant ALB
    participant NodeJs as Node.js App
    
    ALB->>NodeJs: TCP Connection Established
    Note over ALB, NodeJs: Idle (No traffic)
    NodeJs->>NodeJs: Keep-Alive Timeout (5s) Exceeded
    NodeJs--xALB: Close Connection (TCP RST/FIN)
    
    Note over ALB: Still thinks connection is open (Idle < 60s)
    ALB->>NodeJs: Send New Request on Closed Socket
    NodeJs-->>ALB: Connection Reset / Closed
    ALB-->>Client: 502 Bad Gateway

실무 팁: Node.js Keep-Alive 설정

Node.js 애플리케이션의 keepAliveTimeoutALB의 Idle Timeout(기본 60초)보다 길게 설정해야 합니다. AWS는 백엔드 타임아웃을 ALB보다 길게 가져갈 것을 권장합니다.

const server = app.listen(port);
server.keepAliveTimeout = 61000; // 61 seconds
server.headersTimeout = 62000;   // keepAliveTimeout보다 커야 함 (Node.js 10.15.2+)

관련 개념: HTTP Keep-Alive, TCP Connection Termination


3. 504 – 어디서 타임아웃이 났을까?

504 Gateway Timeout 오류는 게이트웨이가 상류 서버로부터 제때 응답을 받지 못했음을 의미합니다. 클라이언트에게 504 오류가 보인다면, 이는 항상 ALB가 반환한 것입니다.

정의와 원인

“The 504 (Gateway Timeout) status code indicates that the server… did not receive a timely response from an upstream server…”RFC 7231 Section 6.6.5

AWS ALB에서 504 오류가 발생하는 조건은 두 가지입니다.

  1. 연결 타임아웃 (Connection Timeout): ALB가 백엔드(Pod)와 TCP 연결을 맺는 데 10초 이상 소요될 때. (네트워크 문제, 보안 그룹 차단 등)
  2. 응답 타임아웃 (Response Timeout): 연결은 성공했으나, 애플리케이션이 ALB의 Idle Timeout(기본 60초) 내에 응답을 완료하지 못했을 때. (느린 쿼리, 외부 API 지연, 데드락 등)

“The load balancer established a connection to the target but the target did not respond before the idle timeout period elapsed.”Troubleshoot your Application Load Balancers: HTTP 504

대부분의 애플리케이션 레벨 504 오류는 백엔드 처리 지연 때문입니다. 데이터베이스 쿼리가 느리거나, 외부 시스템 연동에서 타임아웃 처리가 미흡하여 Node.js의 이벤트 루프가 블로킹되면 60초를 넘기기 쉽습니다.

동작 흐름

sequenceDiagram
    participant Client
    participant ALB
    participant NodeJs as Node.js App
    
    Client->>ALB: HTTP Request
    ALB->>NodeJs: Forward Request
    Note over NodeJs: Processing (Heavy Query / External API)
    
    rect rgb(255, 240, 240)
        Note over ALB: Idle Timeout (60s) Exceeded
        ALB--xNodeJs: Close Connection
        ALB-->>Client: 504 Gateway Timeout
    end
    
    NodeJs-->>ALB: Response (Too Late)
    Note over ALB: Ignored

실무 팁: 타임아웃 전략

단순히 ALB의 Idle Timeout을 늘리는 것은 미봉책입니다. 애플리케이션 내부의 타임아웃을 먼저 점검해야 합니다. 외부 API 호출이나 DB 쿼리에 명시적인 타임아웃(예: 5초)을 설정하여, 요청이 무한정 대기하다가 504로 이어지는 것을 방지하세요. 네트워크 문제(Security Group 등)로 인해 패킷이 드랍되는 경우에도 연결 타임아웃(10초)으로 504가 발생할 수 있음을 명심해야 합니다. 관련 개념: AWS ALB Timeouts, Security Group


요약 및 디버깅 체크리스트

AWS EKS + Node.js 환경에서 5xx 오류는 원인에 따라 명확히 구분됩니다.

  • 503 (Service Unavailable): 타겟 없음. (설정 오류, Readiness Probe 실패)
  • 502 (Bad Gateway): 연결 끊김. (Keep-Alive 불일치, 애플리케이션 크래시)
  • 504 (Gateway Timeout): 응답 지연. (느린 처리, 네트워크 차단)

장애 발생 시 다음 체크리스트를 순서대로 확인하여 원인을 좁혀나갈 수 있습니다.

  1. CloudWatch 지표 확인: HTTPCode_ELB_5XX vs HTTPCode_Target_5XX 비교. (ALB 자체 문제인지 애플리케이션 응답인지 구분)
  2. Kubernetes Endpoints 확인: kubectl get endpoints <서비스명> 결과가 비어있지 않은지 확인. (503 원인)
  3. Pod 상태 및 로그 확인: kubectl get pods로 재시작(Restart) 횟수 확인 및 OOMKilled 여부 점검. (502 원인)
  4. 애플리케이션 로그 분석: “Connection Reset” 에러나 쿼리 수행 시간 로그 확인.
  5. Keep-Alive 설정 검토: Node.js의 keepAliveTimeout이 ALB Idle Timeout(60s)보다 큰지 확인. (502 해결)
  6. 네트워크/보안 그룹 점검: ALB와 Worker Node 간의 Security Group 규칙 확인. (504 원인)