team logo icon
article content thumbnail

HealthCheck 문제 발생시 Elastic Beanstalk Restart 자동화 하기

HealthCheck 문제가 발생했을 때, 대처할 수 있는 방안을 생각 해보기

🚨 HealthCheck 가 실패했다! 🚨


최근 진행하던 프로젝트에서 발생한 의문의 HealthCheck 실패 문제.

이를 분석하고 해결하던 과정에서 구축한 자동화 시스템을 소개한다.


1️⃣ . 문제 발생



페이지에서 502 오류 발생

이야기는 이렇게 시작된다.

어느날 오후에 특정 EC2 를 이용하는 페이지가 502 에러가 발생한다는 연락을 받았다.


일단 EC2 의 모니터링을 확인했을 때 문제가 없었으나 내부 컨테이너가 내려가있었고,

Elastic Beanstalk무언가 문제가 생겼음을 예상할 수 있었다.


Elastic BeanstalkHealthRed 로 띄우고 있었고 여기서부터 고민이 시작되었다.

ElasticBeanstalk 의 Health가 Red 상태


당시에 간단하게 구조만 그려보자면 Ec2 안에 있는 Caddy 라는 오픈 소스 웹서버가

요청을 받아 인증서를 발급하여 Elastic Beanstalk 으로 프록시 해주고, 로드 밸런서가 리스닝해 이를 Elastic Beanstalk 환경과 연결된 Ec2로 분산하는 것이다.

(개수 무관) 요청의 흐름 방향 예시

이 과정에서 LoadBalancerTarget Group

특정 PortHealth Check 를 주기적으로 확인하는데, 이 과정에서 왜인지 비주기적으로 실패를 띄우는 것이였다.


2️⃣ . 시도 1 ) Health Check의 시간을 적절하게 바꾸기



당시에 LoadBalancerElastic Beanstalk 모두 Red 를 띄운 상태였고,

EC2 의 상태 자체에는 문제가 없었기에 Health Check 과정에서 어떠한 문제가 생겼다고 생각했다.


다만, 같은 시간대에 CPU 가 약간 올랐기 때문에 그 과정에서 네트워크가 잠시 느려졌을 수 있겠다고 생각했다.

EC2 > Target Groups > ~ > Edit Health Check Settings 에서 볼 수 있는 기본 화면

해당 타겟 그룹의 Health CheckTime Out 은 default인 5초였고 이 시간을 늘리도록 설정했다.


사실 그럼에도 이미 테스트 한 결과 1 초 이상의 결과는 절대 나오지 않아 이 방법으로 해결이 되지 않을 것 이라고 확신했다. (해결되면 더 문제고)


다만 해당 EC2에 프론트가 남긴 로그나 ELB 에 로그와 관련된 설정이 없는 상태였기 때문에 원인을 찾을 수 없었고, 일단은 로그가 찍힐 환경을 만드는 것이 중요하다고 판단했다.

엑세스 로그를 해당 공식 문서에 적혀있는 바와 같이 설정했다.


이게 본 주제는 아니니 간단히 작성하자면, S3 에 엑세스 로그를 넣을 버킷을 하나 만들었고

S3 Bucket 생성
S3 Bucket S3:PutObject 권한 부여

관련 권한을 부여해줬다.

다행히 과금은 전송이 아닌 S3 만 부여해주기 때문에 필요한 만큼만 쌓아두면 된다.

Amazon S3 > Buckets > {my_bucket} > Management LifeCycle 설정 예시

우리 프로젝트의 경우는 해당 로그를 쌓아둘 필요는 없었기 때문에 S3Lifecycle Rules 를 설정하여 특정 주기 이후로는 없앴다. 돈 아껴 돈 소중해



2️⃣ . 시도 2) 로그 분석하기



ELB 로그에서 실마리를 잡았을까? 안타깝게도 주제가 주제인 만큼 여기서 실마리를 찾지 못했다.

오히려 이전과 다르게 Load Balancer는 금방 본인의 Health 를 되찾았으나,

Elastic Beanstalk Event Log Message

Elastic BeanstalkLoad BalancerHealth에 의존적이었기에 살아있는 인스턴스가 없다는 판단을 내리고 그대로 되살아나지 못했다.

당연하다. Elastic Beanstalk 은 스스로 HealthCheck 요청을 보내지 않기 때문이다.


결국 해당 에러에 대해 당장 실마리를 잡기엔 로그 분석에 시간이 더 필요했고,

클라이언트 쪽에도 몇가지 요청이 필요한 상황이었기에 내가 내린 판단은 하나였다.


예 이제부터 본론입니다.



3️⃣ . 진짜 HealthCheck가 안되는지 확인하기



일단 문제 상황이 특정 대상 그룹에서 발생하는 것은 알았다.

그렇다면 HealthCheck를 정말 보내기는 하는걸까? 받았으나 응답을 안하는 것일까?


이를 알기 위해서 해당 Ec2 내부에서 HealthCheck 를 하고 주기적으로 로그를 남기도록 스크립트를 작성해 실행시켰다.

Health Check sh 예시

잘 찍히는 것을 확인하고 해당 스크립트를 백그라운드로 실행했다.



4️⃣ . 팀원들에게 메일 보내기



이제 문제 상황이 발생했음을 팀원들에게 자동으로 알려야 한다.

문제가 발생되는 곳은 특정 Target Group 이였기 때문에 적절한 기준만 잡으면 된다.

EC2 > Target Groups > {my_target_group} > monitoring

이 모니터링은 TargetGroup 모니터링에 기본적으로 제공되니 CloudWatch 에서도 이를 기준으로 삼아 알람을 전송하도록 하면 된다.

CloudWatch > Alarms > Create alarm > Metric
CloudWatch > Alarms > Create alarm > Conditions

기준으로 잡을 Metric 을 선택한 후, 어떤 값을 기준으로 알람을 보낼지 선택하는 과정을 거치면 된다.

나같은 경우는 Healthy Host살아있는 인스턴스 값이 1 이하가 되는 순간으로 잡았다.

SNS Topics 생성

이제 SNS Topic 을 만들어서 누구에게 어떤 내용으로 메일을 전송할지 작성해주면 된다.

나 또한 팀원들의 메일과 어떤 문제가 발생했는지를 간략하게 적었다.


전송 받는 메일 예시

이후 인증 메일도 받고 에러가 나면 이런 식으로 문제가 발생될시 메일이 전송되게 된다.

대충 문제가 생겼으니 빨리 일해야지? 라는 내용으로 보냈다


5️⃣ . Elastic Beanstalk 살리기 자동화 하기 (1)



로그도 남겼다. 메일도 보냈다.

그러면 이제 남은 것은 적어도 클라이언트의 인스턴스가 접속에 문제없도록 자동화 하는 것이다.

나는 럭키하다.

이 문제가 발생하기 전에 CloudWatch 경보에서 Lambda 함수를 호출하는 것을 지원해주기 시작했기 때문이다.

일단 Lamda 로 가, Elastic Beanstalk 을 살리는 스크립트를 짜면 될 것 이다.


이 과정에서 나는 Boto3 라는 AWS Python SDK 를 선택했다.

일단 파이썬이라는 언어를 다뤄본 경험도 있지만,

열심히 찾아봐도 비슷한 구축 자료가 없어 공식문서에 의존해야 했기 때문에 친절해야했다.

여기서 Elastic Beanstalk 을 선택하면 가능한 API 목록을 보여주고

나는 여기서 update_environment 를 선택했다.

Updates the environment description, deploys a new application version, updates the configuration settings to an entirely new configuration template, or updates select configuration option values in the running environment.


-출처 : ElasticBeanstalk update_environment

Elastic Beanstalk Update Environment

문서를 보니 내가 원하는 것이 새롭게 deploy 하는 것이니 필수로 요구하는 것만 넣으면 된다고 판단해

environment_id 를 기입해줬다.

그러면 이제 파란색 TEST 버튼을 눌러 확인하면 된다.


당연히 에러가 나고 로그가 보이지 않는다. 이유는 내가 로그를 찍지 않았기 때문이다.

위 스크립트에서 error_message = str(e) 를 추가해 에러 메세지도 출력하게 하면 권한이 부족하다는 메시지가 나온다.

IAM > Roles > {my_role} > Edit Policy

당연하다. 우리는 호출만 할 뿐 실제로 해당 Lamda Function이 우리의 자원에 접근할 수 있는 권한을 부여해주지 않았기 때문이다.

IAM 에 들어가 우리의 Role 을 찾아 해당하는 권한을 넣어주면 되는데, 나 같은 경우는 JSON으로 넣는게 편해 이와 같이 넣었다.


다시 호출해보자.

Lambda Function Test Result
Elastic Beanstalk Event log

성공적으로 환경을 update 하는 것을 볼 수 있다.

... 하고 끝나면 좋았겠지만


6️⃣ . Elastic Beanstalk 살리기 자동화 하기 (2)



다음날 메일을 통해 확인한 뒤 접속했으나 결과는 예상과 달랐다.

CloudWatch > Alarms > {my_alarm}

SNS 는 정상적으로 보내졌으니 trigger 가 발동된 것은 맞았으나,

왜인지 Lambda 는 작동하지 않은 것이다.

Lambdainvoke 모니터링을 확인해도 호출조차 하지 않은 것으로 보였다.


경보가 작동되지 않는 경우에 관해 공식문서를 찾아보니 이와 같은 답변을 볼 수 있었다.


당연히 CloudWatch 에서 Lambda 를 넣어주는 과정이 있었고,

그 과정에서 들어가지는 Trust Relationships 를 통해 권한이 부여되는 줄 알았다.

Lamda Trust relationships

그러나 이는 사실 역할을 부여해줄 뿐 실질적으로 Lambda 를 실행할 권한은 부여되지 않았던 것이다.

Lambda invokeFunction Policy


여기에 Elastic Beanstalkenvironment update가 실질적으로는 업데이트만 해줄 뿐

다시 서버를 올려주지 않는다는 것을 알았고 새로운 API 로 바꾸는 것을 결심하게 되었다.


API 로 바꾸는 경우 몇가지 권한이 더 필요한데,

서버를 다시 올리는 순간부터 CloudFromation 의 권한을 필요로 하게 된다는 점이다.


그 이유는 Elastic Beanstalk User Policy 라는 문서에서 찾아볼 수 있는데,

ElasticBeanstalk 을 업데이트 하거나 새롭게 배포할때,

CloudFormation 이라는 리소스 템플릿 서비스를 사용하게 되는 듯 하다.


그래서 몇가지 권한을 더 추가해주면

ElasticBeanstalk Events Log

드디어 원하는 대로 Elastic Beanstalk자동으로 서버를 시작하는 것을 볼 수 있다. 🫡

최종 흐름으로 정리한 구조는 이러하다.

Elastic Beanstalk Restart 자동화 구조


7️⃣ . 마무리 ....?



사실 위 구조로는 처음부터 언급하긴 했으나

결국 빠르게 구축한 임시방편이기 때문에 아쉬운 점이 많을 수 밖에 없다.


근본적인 실패 이유를 찾는 것이 더 중요하기 때문이다.

당시 사용자가 몰리던 상황이 아니었으나 로그를 보니 최근에 프론트에서 도입했던 Sharp 라이브러리가 말썽을 피우는 것 같다...


내부에 있는 메모리가 전혀 정리 되지 않고 오르기만 했기 때문이다.

앞으로 프론트와 많이 대화하며 원인을 더 분석해봐야 할것 같다. 화이팅! 👏🏻


최신 아티클
Article Thumbnail
Polla
|
2024.05.17
저는 지울 Id가 없으면 418을 주겠습니다. 불만 있으신 분?
라이트닝 토크에서 어그로만 끌다 온 크루가 아쉬워서 작성하는 글
Article Thumbnail
Polla
|
2024.05.17
나의 개발 마인드 변화기 (feat. CDN)
우아한테크코스를 다니고 마인드를 바꾼 이야기