FastAPI AWS ECS에 배포하기
목차
- 인트로
- 초간단 ECS 요약
- 도커파일(Dockerfile) 작성
- ECR에 이미지 저장하기
- ECS 클러스터 생성하기
- ECS Task Definition 생성하기
- ECS 서비스 생성하기
- 마무리
인트로
위 링크에 이어지는 글입니다. FastAPI 애플리케이션을 배포하기 위해 gunicorn을 설정하고 실행하는 방법을 알아봤습니다. 배포를 위한 여러가지 방법들이 있지만 오늘 공유할 내용은 AWS ECS + EC2 입니다. AWS의 ECS는 크게 2가지로 나뉘는데요, 서버리스 방식인 Fargate와 자체 관리형 인스턴스를 사용하는 EC2 방식이 있습니다. EC2를 선택한 이유는 Fargate보다 신경써야 할 부분은 많지만 비용적인면에서 좀 더 저렴한 측면이 있어서 입니다.
그럼 배포를 시작해보겠습니다. 지난번과 동일한 구조에 Dockerfile을 추가했습니다. 의존성들을 담고 있는 requirements.txt도 추가했습니다.
fastapi
├─ app
│ ├─ __init__.py
│ ├─ gunicorn.config.py
│ └─ main.py
├─ Dockerfile
└─ requirements.txt
초간단 ECS 요약
ECS의 사용법을 다루는 글이기 때문에 서비스 설명에 대한 부분은 빠르게 요약하여 넘어가겠습니다.
- AWS ECS는 Docker 컨테이너 기반의 애플리케이션을 쉽고 빠르게 배포하고 관리할 수 있는 서비스입니다.
- Fargate와 EC2 두 가지 방식을 제공합니다. 필요에 따라 인프라 관리의 복잡성과 스케일링 방식을 선택할 수 있습니다.
- AWS의 다른 서비스들과의 높은 통합성을 통해 보안, 모니터링, 로깅(CloudWatch) 등을 쉽게 적용하여 사용할 수 있습니다.
도커파일(Dockerfile) 작성
다음과 같이 간단하게 Dockerfile을 작성했습니다. 각종 환경변수 설정 및 필요한 패키지들을 설치했습니다.
FROM python:3.11.4-alpine3.17
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV TZ=Asia/Seoul
RUN apk update && apk add --no-cache git mariadb-dev gcc musl-dev curl build-base libffi-dev openssl-dev python3-dev
WORKDIR /app
COPY ./requirements.txt /app/requirements.txt
RUN pip install -r requirements.txt
COPY ./app /app/app/
EXPOSE 8000
이미지를 빌드하고 앱이 잘 실행되는지 확인해봅니다. 다음은 관련 docker 명령어 입니다.
# docker image는 tmp_image_01 설정
docker build -t tmp_image_01 .
# build한 이미지를 local에서 실행해봅니다.
docker container run -d -p 8000:8000 --name project_01 project_01 gunicorn -c app/gunicorn.config.py
# log를 찍어 성공적으로 실행되었는지 확인합니다.
docker container logs project_01
- docker log 실행 결과
ECR에 이미지 저장하기
docker 이미지를 ECS가 배포할 때 불러올 수 있도록 저장소에 저장을 해두어야 합니다. 레지스트리라고 부릅니다. AWS에서 레지스트리 서비스도 제공하는데 바로 ECR(Elastic Container Registry) 입니다. ECR에 이미지를 저장해보도록 하겠습니다.
AWS에 접속 → ECR 서비스 검색 → 리포지토리 생성 (리전 설정 주의)
프라이빗으로 생성해 보겠습니다. 이름은 project_01로 만들어보겠습니다. 표시 여부 설정에서 프라이빗을 선택하고 리포지토리 이름만 설정한 뒤 생성을 하겠습니다.
생성하면 다음과 같은 결과를 볼 수 있습니다.
project_01을 클릭하고 나오는 화면에서 푸시명령보기를 클릭합니다. 푸시 명령에 나오는대로 local에서 ECR로 push를 해 줄 것입니다. AWS CLI가 설치되어 있어야 합니다.
명령어대로 복사하여 그대로 실행하면 됩니다. 하지만 macOS에서 Apple칩을 사용하는 컴퓨터 같은 경우는 docker build --platform linux/x86_64 -t projcet_01 .
로 플랫폼을 지정해주면 됩니다.
push가 완료되면 이제 ECS에 배포를 할 준비가 되었습니다.
ECS 클러스터 생성하기
이제 ECS 클러스터를 생성합니다. AWS 콘솔이 매우 편리하게 잘 되어 있어 차근차근 따라가면 됩니다. 서비스에서 ECS를 검색한뒤 클러스터 생성으로 이동해줍니다.
클러스터 생성 콘솔에서 위에서 아래로 차례대로 입력해나가면 됩니다.
- 클러스터 이름을 지정합니다. 어떤 애플리케이션들을 실행할 것인지 관련된 이름으로 지정하여 작성해주면 됩니다. 예시에서는 계속 사용하고 있는 project_01 이름을 사용하였습니다.
- 인프라를 Fargate or EC2 중에 선택합니다. 포스트 앞에서도 언급한 것 처럼 EC2를 선택합니다.
- Auto Scaling Group을 생성합니다. 프로비저닝 모델은 사용당 비용을 지불하는 온디맨드 방식으로 지정합니다.
- 일반적으로 많이 쓰는 Amazon Linux 2를 선택했습니다.
- Amazon Linux 2에서 이미지를 컨테이너로 실행하는 것이기 때문에
docker build --platform linux/x86_64 -t projcet_01 .
로 빌드를 한 것입니다. Amazon Linux 2가 x86_64 아키텍처를 기반으로 하기 때문입니다. - 모두가 arm64 아키텍쳐의 기반의 컴퓨터를 사용한다면 운영체제를 Amazon Linux 2(arm64)로 선택하고, 빌드 명령어를
docker build -t projcet_01 .
로 사용하면 됩니다.
- Amazon Linux 2에서 이미지를 컨테이너로 실행하는 것이기 때문에
- 인스턴스의 유형을 선택합니다. 인스턴스 유형은 요구사항에 따라 달라지지만 지금은 연습이기에 여기서는 t2.micro를 선택했습니다.
- VPC와 서브넷을 선택합니다. 기본 VPC와 서브넷을 사용하겠습니다. 보안그룹도 알맞게 설정하면 됩니다. 클러스터 생성 후에 EC2 대시보드에서 수정할 수 있습니다.
- 원하는 용량은 Auto Scaling을 실행할 때 원하는 EC2 인스턴스의 최대 개수를 설정합니다.
생성이 완료되면 ECS 클러스터에 다음과 같이 나타납니다.
EC2대시보드로 이동하여 인스턴스도 생성된 것을 확인할 수 있습니다.
ECS Task Definition 생성하기
클러스터를 생성했으면 이제 Task Definition, 작업정의를 생성하면 됩니다. 말 그대로 실행할 컨테이너를
정의하는 것입니다. 실행할 컨테이너의 이미지, 크기, 메모리 할당량, 포트, 로깅 등을 설정하게 됩니다.
- 태스크 이름부터 정해줍니다.
- 시작 유형에서 EC2 인스턴스를 선택합니다.
- 운영체제를 Amazon Linux 2를 선택했기 때문에 Linux/X86_64를 선택합니다.
- 네트워크 모드는 default로 해주겠습니다.
- 태스크 크기는 EC2로 배포할 땐 Optional이기 때문에 CPU와 메모리를 비웁니다.
- 태스크를 실행하기 위한 IAM 역할이 필요합니다. 이름을 쉽게 구분하기 위해 ecs-task라는 IAM을 생성했습니다.
- 단순하게 IAM에서 역할 생성에서 신뢰할 수 있는 엔티티 유형에서 AWS 계정을 선택하고 아래와 같은 권한을 하나 추가했습니다.
- 실행할 컨테이너 이름 및 이미지 URI를 지정합니다. 이미지 URI는 ECR Repository에서 확인할 수 있습니다. :tag명을 반드시 붙여줘야합니다.
- 호스트 포트와 컨테이너포트를 지정합니다. ECS에서는 dynamic port로 설정할 수 있는데, 예시에서는 http포트인 80포트와 gunicorn config에서 지정한 8000 포트를 연결하도록 하겠습니다.
- 리소스 할당에서 하드제한 0.5기가바이트로 설정해주겠습니다. 하드제한, 소프트제한 둘 중에 하나는 반드시 지정해야합니다.
- 다른 설정들을 지나쳐 로깅 옵션을 보면 아래와 같이 이미 선택되어 있습니다. 이대로 두고 넘어가면 cloudwatch에 자동으로 로그 수집이 됩니다.
- 도커 구성에서 명령부분에 gunicorn 명령을 넣어줍니다. 터미널에 입력하는 것과 다르게 만드시
,
로 분리해야합니다.
- 그대로 생성을 누르면 다음과 같이 완성 메세지를 받을 수 있습니다. 태스크를 실행하는 서비스 생성으로 넘어가 보겠습니다.
ECS 서비스 생성하기
작업 정의는 설정을 하는 것이지 컨테이너를 실행하는 것이 아닙니다.
실행을 위해서는 서비스를 생성해야 합니다. 서비스는 작업 정의를 바탕으로 컨테이너 인스턴스를 실제로 실행시키는 역할을 합니다. 여기서는 실행할 작업의 개수와 업데이트 방식 등을 설정할 수 있습니다.
추가적으로 로드밸런서 및 배포 전략 등을 세팅할 수 있습니다.
project_01 클러스터로 이동하여 콘솔에 보이는 서비스 생성을 클릭합니다.
- 하나의 인스턴스에 하나의 태스크만 실행시킬 것이기에 용량 공급자 대신 시작유형을 선택합니다.
- 애플리케이션 유형에서 서비스를 선택합니다.
- 태스크 정의에서 패밀리를 앞서 정의한 태스트 정의를 선택합니다.
- 실행할 서비스의 이름을 작성합니다.
- 그대로 실행합니다.
- 배포전략, 로드밸런서 등 다른 옵션들이 존재합니다. 요구사항에 따라 쉽게 연결시킬 수 있습니다. 그것이 ECS의 장점이기도 합니다. 예제에서는 생략하였습니다.
서비스 생성에는 시간이 좀 걸릴 수 있습니다. 생성이 완료되고 나서 서비스를 클릭하여 로그를 확인해볼 수 있습니다. 정상적으로 서비스가 실행되면 다음과 같은 결과를 얻을 수 있습니다.
- exec format error가 나오는 경우가 있는데, 이것은 빌드할 때 플랫폼이 잘못된 경우이니 플랫폼에 맞게 이미지 빌드를 실행해야 합니다.
마무리
FastAPI + Gunicorn + ECS EC2로 배포하는 방법을 포스팅해보았습니다. 최소한의 설정들만 하는데도 뭐가 꽤 많았습니다. 실제로 운영에서 사용하려면 도메인도 필요할 것이고 HTTPS를 위해 SSL/TLS 인증도 받아야 할 것입니다. 그러면 HTTP를 HTTPS로 리다이렉트 해주기 위해 로드밸런서도 필요해집니다. 로드밸런서를 연결하기 위해 대상그룹 생성도 해야합니다.
상황에 따라 요구에 따라 인프라 구조를 다르게 가져가야하는데 AWS 콘솔에서 편리하게 컨트롤 할 수 있습니다. AWS 콘솔이 계속 변경되는데 변경 될 때마다 더 편리해지는 것 같습니다.