Spring Boot 애플리케이션을 AWS EC2에 배포하고, ALB(Application Load Balancer) 뒤에 연결해 두었는데 계속 502 Bad Gateway 가 발생했다. 처음에는 애플리케이션 자체 문제, 보안 그룹, 헬스체크 경로 문제를 의심했다. 그런데 결론적으로는 대상 그룹(Target Group)의 Protocol Version이 HTTP2로 설정되어 있었던 것이 핵심 원인이었다.
정리하면, 내 서비스는 일반적인 Spring Boot 백엔드였고 8080 포트에서 HTTP로 정상 동작하고 있었다. 직접 EC2 내부에서 확인해 보면 /health 엔드포인트는 200 OK를 반환했다. 그런데도 ALB 대상 그룹에서는 계속 Unhealthy가 떴고, 결국 502가 발생했다.
처음에는 가장 흔한 원인부터 점검했다.
8080 포트에서 실행 중인지/health 엔드포인트가 200을 반환하는지/health로 되어 있는지200인지8080이 열려 있는지직접 EC2에서 확인했을 때는 /health가 정상 응답을 주고 있었다. 그래서 애플리케이션이 죽은 것은 아니었고, 헬스체크 경로도 틀리지 않았다.
또 AWS 문서상 ALB 대상 그룹의 상태 검사에서는 HTTP/1.1 또는 HTTP/2를 사용하는 경우 유효한 URI 경로를 지정할 수 있고, 성공 코드는 기본적으로 200이다. 따라서 /health, 200 조합 자체는 문제 없는 설정이었다.
문제는 대상 그룹 상세 설정을 자세히 보다가 발견했다.
HTTP8080HTTP2/health200겉보기에는 크게 이상해 보이지 않을 수 있다. 하지만 AWS 공식 문서에 따르면, Application Load Balancer는 기본적으로 타깃에 HTTP/1.1로 요청을 보낸다. 다만 대상 그룹의 Protocol version 설정을 통해 타깃으로 HTTP/2 또는 gRPC를 사용하도록 바꿀 수 있다.
즉, 나는 평범한 Spring Boot 백엔드를 올려 두었는데, 대상 그룹이 백엔드와 통신할 때 HTTP2를 쓰도록 설정되어 있었던 것이다.
내 애플리케이션은 브라우저나 curl로 접근했을 때는 잘 응답했다. 이 테스트들은 사실상 일반적인 HTTP 요청 확인에 해당한다. 그런데 ALB는 대상 그룹 설정에 따라 타깃과 통신하는 방식이 달라질 수 있다.
AWS 문서에는 대상 그룹의 프로토콜 버전에 따라 요청 프로토콜과의 조합 결과가 달라진다고 명시되어 있다. 특히 HTTP/1.1 요청을 HTTP/2 대상 그룹으로 보내는 조합은 오류가 될 수 있다. 또한 프로토콜 버전이 맞지 않으면 ALB에서 프로토콜 불일치 문제가 발생할 수 있다고 설명한다. ([AWS Docs][2])
결국 내 경우는 다음과 같이 이해할 수 있었다.
/health도 정상 응답Unhealthy해결은 단순했다. 대상 그룹의 Protocol Version을 다음과 같이 바꾸면 되었다.
HTTP8080HTTP1/health200AWS 공식 문서상 ALB는 기본적으로 타깃에 HTTP/1.1로 요청을 보내므로, 일반적인 Spring Boot 백엔드라면 이 설정이 가장 자연스럽다.
설정을 바꾼 뒤에는 대상 그룹 상태가 정상으로 바뀌고, 502도 해결되었다.
안되면 대상그룹 - 로드밸런서를 다시 만들면 HTTP1로 잘 적용된다!!!
솔직히 말하면, 왜 대상 그룹 Protocol Version이 HTTP2로 바뀌어 있었는지는 나도 정확히 모르겠다.
내가 의도적으로 설정한 기억은 없다.
가능한 추측은 몇 가지 있다.
하지만 중요한 것은 원인을 특정하는 것보다, 백엔드 서버가 어떤 프로토콜을 기대하는지와 대상 그룹 설정이 일치해야 한다는 점이다.
이번 문제를 겪으면서 느낀 것은, ALB 502가 난다고 해서 무조건 애플리케이션 코드 문제라고 보면 안 된다는 점이다.
내가 실제로 확인했던 순서는 이랬다.
/health가 200인지 확인특히 앞의 것들이 모두 정상인데도 타깃이 계속 Unhealthy라면, Protocol Version까지 반드시 확인해야 한다.
Spring Boot 백엔드는 정상인데 ALB에서만 헬스체크가 실패하고 502가 난다면, 대상 그룹의 Protocol Version이 HTTP2로 되어 있지 않은지 꼭 확인하자. 일반적인 백엔드라면 HTTP1 설정이 맞을 가능성이 크다.