Nginx 502 Gateway가 발생했을 때 해결법과 근본적인 발생 원인

ddongseop·2023년 7월 21일
2

프로젝트에 적용한 무중단 배포를 위한 플로우는 아래와 같다

이 과정에서 자주 발생하는 502 Bad Gateway 오류를 어떻게 해결할 수 있는지,
발생하는 근본적인 원인은 어떻게 해결할 수 있을지 정리해보고자 한다.


1. Nginx 502 Bad Gateway

배포된 서버에 API를 호출했는데, 위와 같이 502 Gateway와 함께 nginx 어쩌구 오류가 뜬다면
Nginx가 가리키고 있는 포트에서 서버가 돌고 있지 않을 때 발생하는 문제일 확률이 높다.
심지어 Github Actions의 CI/CD도 모두 성공이 뜨고, CodeDeploy 상에서도 아래와 같이 배포 성공으로 뜨는 모습을 확인해볼 수 있다.
(실패해놓고 health check까지 성공으로 뜨는 이유는 후술할 것임)

이런 경우에는 Nginx가 가리키고 있는 포트에 서버가 잘 돌고 있는지 다시 확인해보는 과정이 필요한데, 아래와 같은 순서로 진행해보면 된다.

🔥 STEP 1.

sudo vim /etc/nginx/conf.d/service-url.inc

ssh 명령어를 통해 EC2에 접근하면 현재 Nginx가 가리키고 있는 포트를 확인할 수 있다.

🔥 STEP 2.
STEP 1.에서 확인한 Nginx가 가리키고 있는 포트에서 실제로 서버가 돌고 있는지 확인해본다.

sudo lsof -i :8081  // 8081 포트 확인
sudo lsof -i :8082  // 8082 포트 확인

🔥 STEP 3.
STEP 2.에서 확인한 결과, STEP 1.에서 확인한 Nginx가 가리키는 포트실제로 서버가 돌고 있지 않다면 아래의 처리를 해준다.
(위의 캡처본에서는 8081 포트에도 서버가 돌고 있지만, 만약 이 글에서 설명하는 오류가 터졌다면 sudo lsof -i :8081의 결과로 아무것도 출력되지 않을 것이다.)

sudo vim /etc/nginx/conf.d/service-url.inc

위의 vim 명령어를 다시 입력해서 service-url.inc 파일의 포트를 서버가 돌고 있는 포트(8082)로 수동으로 바꿔준다.

🔥 STEP 4.

sudo service nginx restart

service-url.inc 파일이 업데이트 된 것을 Nginx에 적용하기 위해 재시작해준다.

🔥 STEP 5.

cd app // deploy.sh가 있는 폴더로 이동
chmod +x deploy.sh
./deploy.sh // deploy.sh를 실행하여 배포 및 스위칭 테스트

명령어를 통해 실행파일로 만든 뒤에 수동으로 deploy.sh 파일 테스트

⭐️ 정상 구동 시에
sudo lsof -i :8081이랑 sudo lsof -i :8082 다시 해보면 둘다 돌아가고 있을텐데,
현재 Nginx가 바라보는 포트가 최신 버전이고, 나머지 포트가 과거 버전이다.

⭐️ 만약 서버 새롭게 배포했는데, 큰 문제가 발생됐다고하면
위 해결법처럼 수동으로 포트번호만 바꿔주고 리로드하면 바로 과거의 서버로 돌아갈 수 있음 (복구에 용이)


2. 위의 문제가 발생하는 근본적인 원인

Nginx 502 Bad Gateway가 뜨는 문제는 대부분 Nginx가 가리키는 포트에서 jar 파일이 정상적으로 실행되지 않았기 때문이다.

jar 파일이 정상적으로 실행되지 않는다면, 어떻게 확인해볼 수 있을까?
배포 과정에서 jar 파일이 실행될 때 찍히는 로그들은 아래와 같이 확인해볼 수 있다.

cd app // jar 파일이 있는 폴더로 이동
cat nohup.out // nohup.out 파일에서 로그를 확인

Redis와 같이 dependency에 추가된 패키지가 EC2 로컬에 설치되어 있지 않는 등의 문제로 jar 파일 실행이 실패할 수 있는데, 위와 같이 로그를 확인하면 쉽게 해결할 수 있다.

nohup으로 실행하면 백그라운드로 실행되다보니 로그가 안보이니까 간단한 문제인데도 헤매는 경우가 많은데,

⭐️ nohup.out 파일 확인하는 습관을 반드시 길러서 어떤 문제인지 확인하자 !!


☄️ jar 파일 실행되지 않는 예시

nohup.out을 확인해보았는데, 위와 같이 Port already in use 문제가 빈번히 발생하는 경우가 있다.
위 코드와 같이 deploy.sh에서 기존에 사용 중인 포트에 있는 프로세스를 kill을 해주는데 왜 포트가 이미 사용중일까?
이 이유를 알기 위해서는 -15 옵션으로 실행되는 SIGTERM이 -9 옵션으로 실행되는 SIGKILL과 무엇이 다른지 알아야할 필요가 있다.

SIGTERM은 강제 종료를 시키는 SIGKILL과 다르게 자식 프로세스를 정리할 시간을 충분히 준다는 차이점이 있다.
출처: https://seereal.pw/22

종료되는 데에 5초의 시간을 주었는데, 이 시간만으로 프로세스가 종료되지 않았기 때문에 sleep 10으로 늘려보았고, 결과적으로 문제가 해결되었다.
더 좋은 CD를 위해서는 단순히 sleep을 10초동안 하는 것보다는, 해당 포트가 정상 종료될 때까지 sleep 하다가, 종료가 확인되면 jar 파일을 실행하게 하는 것이 좋을 것이다.
(이때의 sleep은 서버가 중단된다는 의미는 아니므로 상관없음)

❗️ 그런데 이상하게도, jar 파일이 정상적으로 실행되지 않았는데 health check를 통과하여 CodeDeploy 상에서의 배포는 성공하는 경우가 많았다. (위에서 언급했듯이)

이떄의 health check는 대체 누가 통과한 걸까?
정확하지는 않지만, SIGTERM 명령을 받은 죽어가는 jar 파일이 health check를 통과한 뒤에 죽는 것이 아닐까 예상하고 있다.

0개의 댓글