일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 전국대학생게임개발동아리연합회
- 스프링
- UNICON2023
- 인디게임
- 스프링부트
- 라피신
- CICD
- 개발공부
- 티스토리챌린지
- 백엔드개발자
- 생활코딩
- 프리티어
- 오블완
- 배포
- 게임개발동아리
- RDS
- UNIDEV
- AWS
- Developer
- 42서울
- 인프라
- 자바개발자
- 프로그래밍
- 백엔드
- EC2
- 체크인미팅
- 온라인테스트
- UNICON
- 위키북스
- 도커
- Today
- Total
Hyun's Wonderwall
[AWS] EC2 서버 계속 꺼짐(상태 검사 실패) 해결법 - Lambda & EventBridge로 재시작 자동화하기! 본문
[AWS] EC2 서버 계속 꺼짐(상태 검사 실패) 해결법 - Lambda & EventBridge로 재시작 자동화하기!
Hyun_! 2024. 10. 7. 17:55
처음으로 서버 배포 담당을 맡은 때부터 지금까지, 항상 모든 프로젝트에서 백엔드 서버를 켜두면 서버가 오래가지 못하고 짧게는 몇 시간에서 길면 며칠 후 맛이 가고는 했다. 즉, EC2 인스턴스가 상태 검사 - 인스턴스 연결성 검사에 실패하는 일이 잦았다.
이 문제 상황에서 나는 주로 [인스턴스 재시작]을 시키거나 [인스턴스 중지] + (잠시 기다리고) + [인스턴스 시작]을 수동으로 진행시켜서 해결해왔었다. 많은 경우에 이 방식으로 해결되었지만 종종 해결이 안 되기도 해서... 오래 중지해 두어도 안 돌아오면 인스턴스를 새로 만들었었다. (AMI로 인스턴스 복제하는 법 몰랐을 때는 아예 nginx, docker 다 새로 깔았다...)
메모리 사용량이 높으면 인스턴스가 꺼진다는 말을 읽고 인스턴스 유형을 업그레이드 해보기도 했는데 (t3.small로) 마찬가지로 종종 꺼져서 크게 효과가 없었다. 나만 겪는 문제는 아닌 것 같은데, 검색했던 당시 자세한 해결법을 찾지 못했었다. (당시 찾은 최선이 중지+시작..)
인스턴스 연결성 검사가 실패할 때마다 수동으로 조치하는 것이 번거로웠고, 서비스를 실배포할 때는 이와 같은 문제가 생기면 안 돼서 해결책을 강구했다.
구글링을 한 결과, 아래의 블로그를 발견하여 인스턴스 중지+시작이 매일 일정 시각에 이루어지도록 자동화하는 것에 성공했다. 이후로는 서버가 꺼지는 일이 없었다!
https://blog.naver.com/zacra/223317309373
내 절차에 맞게 적용 과정을 다시 정리해보았다. 인스턴스를 하나 만들어놓은 상태에서 시작 바란다.
1. IAM - 정책 만들기
IAM 서비스 > 정책 탭 > [정책 생성]을 클릭하고, 권한 지정에서 [JSON]을 클릭해 아래의 JSON 코드를 복붙한다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": [
"ec2:Start*",
"ec2:Stop*"
],
"Resource": "*"
}
]
}
[다음]을 누르고 "정책 이름"을 지어준다. (ex: MyEC2AutoRestart)
"이 정책에 정의된 권한"을 보면, 위에서 JSON 코드를 작성함으로써 이 정책에 CloudWatch Logs와 EC2 두가지 서비스에 대한 권한이 허용되었음을 알 수 있다.
[정책 생성]을 클릭해 정책 생성을 완료한다.
2. IAM - 역할 만들기
IAM > 역할 > [역할 생성]을 클릭한다.
"신뢰할 수 있는 엔터티"에 [AWS 서비스], "사용 사례"로 [Lambda]를 선택한다.
"권한 추가"의 검색바에서 위에서 자신이 생성한 정책을 검색해 추가한다.
"역할 이름"을 지정한다. 나는 편의상 정책과 같은 이름으로 지정했다.
[역할 생성]을 클릭해 역할 생성을 완료한다.
3. AWS Lambda - 중지 함수, 시작 함수 만들기
AWS Lambda 서비스로 EC2 인스턴스를 중지하는 함수 하나, 시작하는 함수 하나 이렇게 두 개의 함수를 만들고자 한다.
먼저 중지 함수부터 만들겠다.
Lambda > 함수 > [함수 생성]을 클릭한다.
중지 함수의 "함수 이름"을 짓고(ex. StopEC2Instances), "런타임"을 Python으로 선택.
"권한"에서 "기본 실행 역할 변경" 토글을 열어서 [기존 역할 사용]을 선택하고, 위에서 만든 역할(MyEC2AutoRestart)을 선택한다.
[함수 생성]을 클릭해 함수를 생성한다.
함수 정보 아래의 "코드"를 편집해 아래의 내용을 적는다. (lambda_function.py 파일을 편집)
(*코드에 ID를 직접 쓰지 않는 방법은 후술합니다.)
import boto3
region = 'eu-north-1' # 자신의 리전에 맞게 변경
instances = ['i-...'] # 대상 인스턴스 ID를 작성
ec2 = boto3.client('ec2', region_name=region)
def lambda_handler(event, context):
ec2.stop_instances(InstanceIds=instances)
print('stopped your instances: ' + str(instances))
[Deploy]를 클릭해서 배포한다.
이후 "구성 탭"에서 "제한 시간"을 10초로 변경한다.
여기까지 하면 중지 함수 작성이 완료된다.
시작 함수도 같은 방법으로 만들어준다.
시작 함수의 코드는 아래와 같이 적는다.
import boto3
region = 'eu-north-1' # 자신의 리전에 맞게 변경
instances = ['i-...'] # 대상 인스턴스 ID를 작성
ec2 = boto3.client('ec2', region_name=region)
def lambda_handler(event, context):
ec2.start_instances(InstanceIds=instances)
print('started your instances: ' + str(instances))
[Deploy]를 클릭해 배포하고, 제한 시간도 늘려준다.
각 함수에서 Test 버튼을 클릭해보면 작성한 ID의 인스턴스가 중지/시작된다.
4. AWS EventBridge - 일정 생성, 스케줄링
AWS EventBridge 서비스를 활용해 EC2 인스턴스가 특정 시각에 중지되고, 특정 시작에 시각되도록 스케줄링할 것이다.
따라서 중지하는 일정과 시작하는 일정(규칙) 두 개를 생성하고 언제 무엇을 진행할지 정하여야 한다.
중지 일정부터 만들겠다.
Amazon EventBridge > Scheduler > 일정 > [일정 생성]을 클릭한다.
일정 이름을 작성하고 (ex. StopEC2Instances)
일정 패턴에서 발생은 [반복 일정]을 선택,
시간대가 맞는지 한번 확인한다.
일정 유형은 [Cron 기반 일정]을 선택하고, 원하는 일정의 주기와 시각을 써넣는다.
나는 0 5 * * ? * 값을 입력해 매일 새벽 5시에 스케줄러가 동작하도록 했다.
대상은 [AWS Lambda Invoke]를 선택
위에서 만든 서버 중지 함수를 선택하고, [일정 검토 및 생성단계로 건너뛰기] 버튼을 클릭한다.
[일정 생성] 버튼을 클릭하면 일정 생성 완료.
시작 일정도 동일하게 만들면 되는데,
Cron 표현식의 "분"을 1,2로 써넣어
Stop하는 일정이 진행된 이후 5시 1분과 2분에 실행되도록 했다.
(두 번 진행하는 것은 참고한 블로그를 따라, 5시 1분의 시점에서 인스턴스의 중지가 끝나지 않아서 Start 일정이 시작하지 못하는 경우를 고려했다. 1분 또는 2분으로만 적으셔도 무관할 것 같다.)
5. 부록 - 페이로드로 instance들 ID 넘겨주기
함수 코드를 수정하는 대신, 인스턴스 ID를 따로 넣어주고 싶은 경우 아래와 같이 진행하면 된다.
(이것은 원본 블로그에서 더 나아가서 내가 추가로 학습한 내용!)
기존의 Lambda 함수 StartEC2Instances, StopEC2Instances의 코드들을 아래와 같이 수정할 수 있다.
상태코드와 메시지 출력은 디버깅 용으로 추가한 것이어서,
위의 코드에서 instances = event.get('InstanceIds', [])만 변경해도 무방하다.
[ Lambda 함수 StartEC2Instances의 코드 ]
import boto3
region = 'eu-north-1'
ec2 = boto3.client('ec2', region_name=region)
def lambda_handler(event, context):
try:
# Extract instance IDs from the event
instances = event.get('InstanceIds', [])
if not instances:
return {
'statusCode': 400,
'body': 'No instance IDs provided'
}
# Start the instances
response = ec2.start_instances(InstanceIds=instances)
# Log the started instances
print('Started your instances: ' + str(instances))
return {
'statusCode': 200,
'body': f'Started instances: {str(instances)}'
}
except Exception as e:
print(f'Error: {str(e)}')
return {
'statusCode': 500,
'body': f'Error starting instances: {str(e)}'
}
[ Lambda 함수 StopEC2Instances의 코드 ]
import boto3
region = 'eu-north-1'
ec2 = boto3.client('ec2', region_name=region)
def lambda_handler(event, context):
try:
# Extract instance IDs from the event
instances = event.get('InstanceIds', [])
if not instances:
return {
'statusCode': 400,
'body': 'No instance IDs provided'
}
# Stop the instances
response = ec2.stop_instances(InstanceIds=instances)
# Log the stopped instances
print('Stopped your instances: ' + str(instances))
return {
'statusCode': 200,
'body': f'Stopped instances: {str(instances)}'
}
except Exception as e:
print(f'Error: {str(e)}')
return {
'statusCode': 500,
'body': f'Error stopping instances: {str(e)}'
}
두 람다 함수 모두에서 Test 옆의 토글을 클릭해 테스트 이벤트를 만들거나, 저장했던 이벤트를 편집한다.
이곳의 "이벤트 JSON"에 (통신 시 사용하는 RequestBody처럼) argument를 적을 수 있다.
대괄호 안에 자신의 인스턴스 id(들)을 컴마로 구분해서 적어준다. 나는 하나의 인스턴스만 쓰고 있으므로 한 개만 적었다.
{
"InstanceIds": ["i-..."]
}
이제 Test 버튼을 클릭하면 이벤트 JSON에 적은 인스턴스 ID들 문자열 리스트를 가져와 함수가 실행됨을 확인할 수 있다.
위에서 한 것은 테스트 이벤트였으므로 실제 일정에도 적용해주자.
EventBridge로 돌아가서 두 일정을 각각 편집하는데,
Lambda Invoke를 선택한 다음의 "페이로드" 공간에 동일하게 작성해주면 된다.
'Study > Java, Spring' 카테고리의 다른 글
[Mooney] 졸업프로젝트 스타트 - 백엔드 ERD 설계 (4) | 2024.11.26 |
---|---|
[Spring Boot] TDD, 단위 테스트, JUnit (0) | 2024.10.06 |
구글, 카카오 소셜 로그인 Spring Security, OAuth2, Redis에 일반 로그인까지 대응 가능하기.. (0) | 2024.10.06 |
[AWS] EC2, 탄력적 IP, RDS 옮기기! (1) | 2024.10.01 |
[Spring Boot] 백엔드 서버 배포방법 총정리 - AWS EC2, RDS + Docker + GitHub Actions로 CI/CD🌿 (5) | 2024.09.22 |