Today I Learned
날짜
2024년 8월 5일 월요일
내용
ECS 태스크 호출하기
아무리 생각해도 서버 외부에서 호출해야 했다. 람다는 15분 제한 시간에 넘치고, 서버에서 돌리기엔 처음 네이버에 호출하는 순간 CPU 사용률이 80%에 달한다!
다행히 boto3로 ECS Task를 호출하는 방법이 있어 적용했다. 태스크를 직접 요청시에 적용할 수 도 있지만, 미리 정의해놓고 호출해서 원하는 로직만 처리하도록 구현했다. 다만, 일부 파라미터들은 일시적인 환경변수로 지정해줘야 했다.
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
ecs_client = boto3.client(
"ecs",
region_name=region,
aws_access_key_id=AWS_ACCESS_KEY_ID,
aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
)
def ecs_task_definition():
task_setting = dict()
if DEVELOPMENT:
task_setting = {
"cluster": , # 실행할 클러스터의 arn
"taskDefinition":, # 태스크 정의 이름
"subnets": [], # VPC 내 서브넷들의 ID
"securityGroups": , # VPC 내 보안그룹 ID
"name": , # 컨테이너 이름
}
return task_setting
def call_ecs_task(payload: dict):
"""ECS Task 실행"""
try:
task_setting = ecs_task_definition()
response = ecs_client.run_task(
cluster=task_setting["cluster"],
taskDefinition=task_setting["taskDefinition"],
launchType="FARGATE",
networkConfiguration={
"awsvpcConfiguration": {
"subnets": task_setting["subnets"],
"securityGroups": task_setting["securityGroups"],
"assignPublicIp": "ENABLED",
}
},
overrides={
"containerOverrides": [
{
"name": task_setting["name"],
"environment": [
{"name": "ACTION", "value": payload["action"]},
{"name": "SERVICE_ID", "value": payload["service_id"]},
{"name": "DB_USER", "value": get_db_password()["username"]},
{
"name": "DB_PASSWORD",
"value": get_db_password()["password"],
},
{"name": "DATA", "value": json.dumps(payload["data"])},
],
}
]
},
)
task_arn = response["tasks"][0]["taskArn"]
return task_arn
except Exception as e:
logging.info("error in call_ecs_task")
logging.exception(str(e))
기존에 lambda_function.py에 있는 lambda_handler
를 자동으로 호출되었는데, ECS에선 내가 실행할 스크립트를 추가해줘야 했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# lambda_entrypoint.py
import os
import json
from lambda_function import lambda_handler
def main():
# 환경 변수에서 데이터를 읽어옵니다.
event = {
"action": os.getenv("ACTION"),
"service_id": os.getenv("SERVICE_ID"),
"data": json.loads(os.getenv("DATA")),
}
context = {} # Lambda context가 필요하다면 설정
# lambda_handler 함수 호출
lambda_handler(event, context)
if __name__ == "__main__":
main()
그리고 수정한 도커파일
1
2
3
4
5
6
7
8
9
10
11
12
FROM python:3.12-slim
# 애플리케이션 파일 복사
COPY . /app
WORKDIR /app
# 필요한 패키지 설치
RUN pip install --no-cache-dir -r requirements.txt
# 엔트리포인트를 설정하여 컨테이너가 시작될 때 스크립트를 실행하도록 합니다.
ENTRYPOINT ["python", "lambda_entrypoint.py"]
생각보다 쉽게 잘 호출되고 작동해서 당황했다… 왜 돌아가냐..
회고
QA는 해도해도 자꾸 할게 발견된다. 이대로 출시됐다면 끔찍하다 증말..