All Honey Tip

AWS ECS와 Lambda 아키텍처 분리: 무거운 AI 모델 서빙을 위한 컨테이너와 ALB 로드 밸런서 구축

수정 일:

,

발행 일:

,
AWS ECS와 Lambda 아키텍처 분리: 무거운 AI 모델 서빙을 위한 컨테이너와 ALB 구축

지금까지 API Gateway와 Lambda를 연결해 가벼운 API 서버를 구축하고, DynamoDB로 대화 로그를 빠르게 처리할 아키텍처를 완성했습니다.
이번 시간에는 AWS ECS와 Lambda 아키텍처를 분리하고, AI 모델 서빙을 위해 컨테이너와 ALB 로드 밸런서를 만들어보겠습니다.







챗봇의 핵심인 ‘AI 페르소나 모델’을 서버에 올려야 할 차례입니다.
처음에는 단순히 기존에 만들어둔 Lambda 함수에 AI 모델 코드도 같이 넣으면 안 되나?라고 생각했습니다.

하지만 기가바이트(GB) 단위일 수 있는 AI 모델과 길어질 수 있는 추론 시간은, 가볍고 빠른 작업에 최적화된 ‘서버리스(Lambda)’ 환경이 감당하기 힘든 영역이었습니다. 결국 인프라의 물리적인 용량 제한과 타임아웃이라는 한계에 부딪히게 된 것이죠.

이를 해결하기 위해 저는 가벼운 비즈니스 로직(Lambda)과 무거운 AI 모델 추론(ECS)을 분리하여 각자의 역할에만 집중하게 만드는 아키텍처를 채택하게 되었습니다.





아키텍처를 분리한 이유를 알기 전에,
먼저 해당 서비스들의 특성을 이해해야 합니다.


– AWS Lambda (비즈니스 로직 담당)

이전 글에서도 언급 했지만, AWS 람다는 코드를 올려두면 이벤트(요청)가 발생하는 순간만 서버가 켜집니다. 즉, 필요한 순간에만 실행되고 꺼지는 ‘서버리스 컴퓨팅’이죠.

DB 조회나 로그인 처리 등 ‘가볍고 빠른 비즈니스 로직’에 최적화되어 있습니다.



– Amazon ECS (Elastic Container Service – AI 담당)

위에서 만든 도커(Docker) 컨테이너들을 쉽게 실행하고 관리해 주는 AWS의 서비스입니다. 특히 Fargate 모드를 선택하면, 컨테이너가 필요로 하는 CPU와 메모리만큼만 알아서 할당해 주는 ‘서버리스 컨테이너’ 환경을 제공합니다.

흔히 사용하는 CloudWatch나 ELB도 알아서 연결해주는 장점이 있죠.



– Docker (도커)

내 컴퓨터에서 돌아가는 프로그램(AI 모델, 파이썬 환경 등)을 그 환경 그대로 통째로 압축해서 포장해 주는 ‘컨테이너’ 기술입니다. 인프라 환경이 조금 다르다 해도, 상관 없이 독립적으로 돌아가게 할 수 있어요.







바이블톡 서비스는 검증을 위한 MVP 성격을 띠고 있습니다. 개발 속도를 위해 모든 걸 Lambda 하나에 넣어볼까 했지만, 무거운 AI 모델을 서빙하기엔 치명적인 3가지 한계가 있었습니다.

  1. 배포 패키지 용량 제한 (250MB의 벽): Lambda는 업로드할 수 있는 코드와 라이브러리의 총용량이 250MB로 엄격하게 제한됩니다. PyTorch 같은 딥러닝 라이브러리와 수 GB에 달하는 모델 파일을 사용하게 되면, 배포 조차 되지 않을 수 있습니다.

  2. API Gateway의 29초 타임아웃 룰: Lambda 앞에 문지기로 서 있는 API Gateway는 “29초 안에 응답이 안 오면” 무조건 에러(504 Timeout)를 뱉어버립니다. 서비스에 따라 추론 AI가 대답을 생성하는 데 오래 걸리는 작업이 있을 수 있는데, Lambda쪽에서 이를 기다려주지 못합니다.

  3. 극악의 콜드 스타트 (Cold Start): 어찌어찌 용량을 줄여 Lambda에 올렸다고 쳐도, 15분간 호출이 없다가 새 요청이 들어오면 무거운 AI 라이브러리들을 처음부터 메모리에 다시 올려야 합니다. 갑자기 첫 응답에 상대적으로 더 긴 시간이 걸린다면, 서비스 운영상 치명적일 수 있다고 생각했습니다.

결론: 로그인, DB 저장 같은 빠릿빠릿한 작업은 Lambda에 올리고, 텍스트 생성이나 무겁고 오래 걸리는 AI 작업은 시간과 용량 제한이 없는 ECS(Fargate) 컨테이너로 분리해보면 어떨까 생각했습니다. 간단한 MSA로 보이지 않나요?






MSA라는 거창한 명분을 세웠으니,
이제 콘솔에서 직접 ECS Fargate를 만들어 보겠습니다.


Step 1. ECR(Elastic Container Registry)에 도커 이미지 올리기

ECS가 컨테이너를 실행하려면,
먼저 포장된 도커 이미지를 AWS 창고에 올려두어야 합니다.

※ 저는 지금 MVP 기획과 개발을 Agile하게 혼자 하는 중이라,
거의 깡통에 가까운 도커 이미지
를 올렸습니다.




우선, 콘솔에 ECR을 검색해서 들어가서

image 17




리포지토리 ‘생성’을 누르세요.

image 18






리포지트로 이름 만들고, 기본 설정대로 냅둔 채 ‘생성’합니다.

image 19

※ 옵션을 디폴트대로 냅둔 이유:

  • 이미지 태그 변경 가능성 (Mutable): 코드를 수정하고 새로 배포할 때, 기존 이미지에 latest같은 태그로 편하게 덮어쓰기 위함.
  • 암호화 설정 (AES-256): AWS KMS를 연동하면 아주 미세하게나마 관리 비용이 추가로 발생할 수 있어서, MVP 단계에 맞춰 무료이면서도 기본 표준형인 ‘AES-256’으로 채택.
  • 이미지 스캔 설정 (Disabled): 혼자 빠르게 테스트하는 단계라 도커 이미지 푸시(Push) 속도를 올리기 위함.







그럼 이렇게, 프라이빗 리포지토리가 추가됩니다.
이제 해당 repo를 선택하고, [푸시 명령 보기]를 누르면 터미널 명령어 4개가 나옵니다.

image 20

※ macOS/Linux와 Windows 버전이 있는데 각자 환경에 맞게 사용하면 됩니다.
참고로 해당 명령어를 사용하려면, Docker Desktop과 AWS CLI가 설치되어 있어야 합니다.
귀찮으시면, AWS에서 제공하는 CloudShell을 이용해도 돼요.

우측 상단에 ‘>_’모양으로 되어있는 아이콘을 누르시면 됩니다.

image 21

그럼 하단에 이런 CLI가 나와요.

image 22




도커 테스트 용도로 아래 명령어를 그대로 복사해서 붙여넣으면,

cat <<EOF > Dockerfile
FROM alpine
CMD ["echo", "Hello BibleTalk AI Service"]
EOF

Dockerfile이 생깁니다.

image 23

그리고 푸시 명령에 나오는 4가지 명령어를 차례로 입력합니다.

image 24

그럼 서비스 실행 파일(도커 이미지)이 AWS의 프라이빗 저장소인 ECR(Elastic Container Registry)에 안전하게 업로드(Push)된 것입니다.







Step 2. 작업 정의 (Task Definition) 만들기

ECR이라는 AWS 창고에 도커 이미지를 올렸죠?
이제 이 도커 이미지를 “어떤 사양의 컴퓨터에서 실행할지” 명세서를 작성해야 합니다.

AWS 콘솔에서 ECS를 찾아서 들어가세요.

    image 34








    좌측 메뉴에서 [태스크 정의] [새 태스크 정의 생성]을 클릭합니다.

    image 35
    image 36







    서버 관리를 최소화 하기 위해, AWS Fargate를 선택하고,
    초기 테스트이니 스펙도 그대로 냅둡니다.

    image 37





    컨테이너 이름을 작성하고,
    [ECR 이미지 찾아보기]를 누르세요.

    image 38






    그리고 아까 만든 ECR을 가져와서
    [이미지 선택]을 하면 됩니다.

    image 39
    image 40





    이제 맨 밑으로 내려서 [생성]을 누르면 끝입니다.
    이 태스크로 서비스를 배포하거나 실행할 수 있어요.

    image 41







    Step 3. AWS ALB(Application Load Balancer) 생성

    이제 트래픽을 안전하게 전달해 줄 ALB를 만들어보겠습니다.
    여기서 “MVP 테스트 중이고 서버(컨테이너)도 1개만 띄울 건데, 왜 굳이 로드 밸런서(트래픽 분산 중개기)를 만드는 거지?”라는 의문이 드실 수도 있습니다.

    저도 여러 아키텍처 관련 글들을 읽으면서 의문이 들긴 했으니까요 ㅎㅎ

    이유는 이러합니다.
    우리가 띄울 서버는 고정된 EC2가 아니라 ‘서버리스 컨테이너’인 ECS Fargate입니다.
    다들 알고 있는 트래픽을 분산을 제외하고도, ALB가 필요한 이유는 3가지나 더 있습니다.

    • 가변 IP (고정 IP 역할): Fargate 컨테이너는 고정IP가 제공 되지 않습니다. 즉, 업데이트 or 재시작될 때 내부 IP가 랜덤으로 바뀌게 되는 거죠. 하지만 ALB를 세워 두면 고정 IP(고정 도메인(DNS Name) 역할도 할 수 있고, Lambda가 매번 IP를 찾아다닐 필요 없이 안정적으로 통신할 수 있다는 장점이 있습니다.

    • 무중단 배포 (Zero-Downtime): 나중에 AI 모델을 업데이트하고 새 도커 이미지를 올릴 때, 새 컨테이너가 준비될 때까지 ALB는 기존 컨테이너로 트래픽을 유지해 줍니다. 덕분에 서버가 1대라도 유저는 무중단 서비스를 누릴 수 있는 거죠.

    • 헬스 체크: 컨테이너가 죽었는지 주기적으로 확인하고, 응답이 없다면 즉시 비정상으로 판단해 트래픽을 차단합니다. 그리고 Container를 Unhealthy로 처리하여 ECS가 새 컨테이너를 띄우도록 요청할 수 있죠.

    정리하자면 서버가 1대일 때의 ALB는 ‘트래픽 분산 중개기’가 아닌, 가변 IP에 대한 해결책이자 배포 관리자라고 할 수 있죠. 그럼 바로 콘솔에서 구축해 보겠습니다.




    AWS 콘솔에서 EC2를 검색해서 들어가세요.
    (이유는 모르겠지만, ALB는 EC2 서비스 안에 종속되어 있습니다..)
    ALB 검색하면 EC2가 나와요 ㅋㅋㅋ

    image 42




    좌측 메뉴 하단의 [로드 밸런서]에서 [로드 밸런서 생성]을 클릭합니다.

    image 43








    HTTP/HTTPS 트래픽(일반적인 서비스)에 특화된 Application Load Balancer (ALB)를 만들겁니다. [생성] 버튼을 누르세요.

    image 44








    체계는 외부에서 접근 가능하도록 인터넷 경계로 두고, 사용 중인 VPC를 선택 후 서브넷(가용 영역)은 최소 2개 이상을 체크해야 ALB 생성이 가능합니다.

    image 45
    image 46







    외부(또는 Lambda)에서 80번 포트로 들어올 수 있도록 보안 그룹은 냅두시고,
    [리스너 및 라우팅]에서 [대상 그룹을 생성]을 누르세요

    image 47







    그럼 대상 그룹을 만들 수 있는데, 여기서 꼭 [IP 주소]를 선택하세요.
    (ECS Fargate는 가상 머신 단위가 아니라 IP 기반으로 통신 한다고 합니다.)

    그리고 나머지는 그냥 다 넘어가고 [대상 그룹 생성]을 누르면 됩니다.

    image 48
    image 49
    image 50
    image 51




    그럼 ALB 구축이 완료됩니다.





    무거운 모델은 Docker로 묶어 ECS에 띄우고, ALB를 통해 동적 IP 문제를 해결하며, 가벼운 API는 Lambda가 처리하도록 관심사를 분리 했습니다.

    시스템의 구조가 훨씬 안정적이고 유연해졌다고 볼 수 있죠.
    AWS 자격증을 공부하며 활자로만 배웠던 ALB와 ECS Fargate의 개념을 실제 서비스 아키텍처에 엮어내면서, 인프라 설계에 대한 재미를 느낄 수 있었던 거 같습니다.


    코멘트

    답글 남기기

    이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다