1️⃣ Flask + AWS Lambda + API Gateway 개념 정리
AWS Lambda는 서버를 직접 관리하지 않고, 코드만 실행할 수 있는 서버리스(Serverless) 컴퓨팅 서비스
이때, Lambda는 기본적으로 HTTP 요청을 직접 받을 수 없기 때문에 API Gateway와 연결해야 한다.
즉,
- API Gateway: API 요청을 받아서 Lambda에 전달하는 역할
- Lambda: API의 실제 동작(Flask 서버 역할)
2️⃣ serverless-wsgi가 무엇인지?
serverless-wsgi는 Flask 같은 WSGI 기반 프레임워크(Web Server Gateway Interface)를 AWS Lambda에서 실행할 수 있도록 도와주는 라이브러리.
AWS Lambda는 기본적으로 HTTP 서버가 없고, Lambda의 event와 context 객체를 다뤄야 한다.
Flask는 일반적으로 WSGI 서버(Gunicorn, uWSGI 등)가 필요하지만,
Lambda에는 그런 환경이 없기 때문에 serverless-wsgi가 WSGI 요청을 Lambda의 이벤트로 변환해주는 역할을 한다.
📌 serverless-wsgi의 역할
- API Gateway 요청을 Flask의 WSGI 형식으로 변환
- Flask에서 응답한 데이터를 API Gateway 형식으로 변환
- Lambda 내에서 Flask 앱을 실행 가능하도록 만듦
📌 설치 및 사용 방법
pip install serverless-wsgi
Lambda 핸들러(lambda_function.py) 설정:
from app import app
from serverless_wsgi import handle_request
def lambda_handler(event, context):
return handle_request(app, event, context)
3️⃣ IAM 사용자 권한 설정
AWS Lambda + API Gateway를 사용하려면 IAM 권한이 필요.
각각의 역할을 하는 정책(policy)들을 IAM에 추가한다.
📌 필요한 IAM 정책
정책 이름 설명
AmazonAPIGatewayAdministrator | API Gateway 리소스 생성 및 관리 |
AmazonEC2ContainerRegistryFullAccess | ECR (도커 이미지 저장소) 사용 |
AmazonRDSDataFullAccess | RDS(Database) 접근 |
AmazonS3FullAccess | S3 파일 저장소 접근 |
AmazonSSMFullAccess | AWS Systems Manager 접근 (환경 변수, Parameter Store) |
AWSCloudFormationFullAccess | AWS CloudFormation 템플릿 사용 |
AWSLambda_FullAccess | Lambda 함수 생성 및 관리 |
CloudFrontFullAccess | CloudFront (CDN) 사용 |
CloudWatchFullAccess | 로그 및 모니터링 데이터 접근 |
IAMFullAccess | IAM 사용자 및 역할 관리 |
IAM 사용자 deploy에게 위 정책들을 추가하면, AWS 리소스를 배포하고 관리할 수 있다.
4️⃣ 전체 배포 과정 요약
AWS Lambda + API Gateway를 사용해서 Flask API를 배포하는 과정은 이렇게 진행된다.
📌 배포 흐름
1️⃣ Flask 앱 (app.py) 작성
2️⃣ Lambda에서 Flask 실행을 위한 핸들러 (lambda_function.py) 준비
3️⃣ Docker 컨테이너 이미지 생성 (Dockerfile)
4️⃣ AWS Lambda + API Gateway 리소스 정의 (template.yaml)
5️⃣ GitHub Actions (deploy-lambda.yaml) 설정하여 코드 푸시 시 자동 배포
6️⃣ API Gateway URL을 통해 Flask API 사용 가능
5️⃣ 폴더 구조
이제 폴더와 코드들을 하나씩 살펴보자.
.
├── app.py # Flask 앱 (웹서버 코드)
├── config.py # 보안키 등 환경변수 관리
├── lambda_function.py # AWS Lambda 핸들러
├── requirements.txt # 파이썬 라이브러리 목록
├── Dockerfile # Docker 컨테이너 설정 파일
├── template.yaml # AWS SAM 템플릿 (Lambda, API Gateway 설정)
├── resources/ # 추가적인 리소스 폴더
│ ├── chat.py # 채팅 API 기능 모듈
└── .github/
└── workflows/
└── deploy-lambda.yaml # GitHub Actions 자동 배포 스크립트
6️⃣ 각 파일 코드 상세 설명
📌 template.yaml (AWS SAM 템플릿)
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Flask API with Container + API Gateway
Parameters:
ImageUri:
Type: String
Description: "ECR Image URI (컨테이너 이미지 URI)"
Globals:
Api:
Cors:
AllowMethods: "'GET,POST,OPTIONS'"
AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
AllowOrigin: "'*'"
Resources:
ChatFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: flask-llm-chat-lambda
PackageType: Image
ImageUri: !Ref ImageUri
Timeout: 120
MemorySize: 2048
Events:
ChatApi:
Type: Api
Properties:
Path: /{proxy+}
Method: ANY
Outputs:
ApiEndpoint:
Description: "API Gateway Base URL"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod"
이 템플릿은 Lambda + API Gateway를 자동으로 생성하는 역할
FunctionName: flask-llm-chat-lambda 부분은 필요에 따라 변경하자.
📌 Dockerfile (컨테이너 설정)
#Python 3.10버전에서 테스트 했다.
#도커 소프트웨어에게 python3.10, aws의 람다와 같은 서버를 준비하도록 한다.
FROM public.ecr.aws/lambda/python:3.10
#라이브러리 설치를 위해 requirements.txt를 컨테이너에 복사한다.
# requirements.txt 현재경로
COPY requirements.txt ./
#람다에 파이썬 라이브러리 설치
RUN pip install --no-cache-dir -r requirements.txt --target "${LAMBDA_TASK_ROOT}"
#소스코드를 컨테이너에 복사한다.
#. 현재경로의 모든 파일을 컨테이너의 LAMBDA_TASK_ROOT경로에 복사한다.
COPY . ${LAMBDA_TASK_ROOT}
#서버 동작
CMD [ "lambda_function.lambda_handler" ]
#lambda_handler.py의 lambda_function 함수를 실행-> 서버가 동작한다.
- Python 가상 환경 (프로젝트에선 3.10ver 사용중이라 3.10으로 독커 컨테이너 설정처리)
- Flask와 필요한 라이브러리를 설치 (requirements.txt)
- Lambda에서 실행할 소스코드를 복사
- lambda_function.lambda_handler를 실행하여 Lambda가 Flask를 호출하도록 설정
📌 lambda_function.py (Lambda 핸들러)
from app import app
from serverless_wsgi import handle_request
def lambda_handler(event, context):
return handle_request(app, event, context)
API Gateway 요청을 Flask가 처리할 수 있도록 변환해줌.
7️⃣ GitHub Actions 배포 자동화
📌 .github/workflows/main.yaml
name: Build and Deploy Flask Container (SAM + API Gateway)
on:
push:
branches: [ "main" ] # main 브랜치에 push 발생 시 실행
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
# (1) GitHub 저장소 코드 체크아웃
- name: Check out code
uses: actions/checkout@v2
# (2) AWS 자격 증명 설정 (GitHub Secrets에서 가져옴)
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-2 # 서울 리전
# (3) 환경 변수 설정
- name: Set environment variables
run: |
# GitHub Secrets에서 값을 가져와 환경 변수로 설정
echo "ECR_REPO_NAME=${{ secrets.ECR_REPO_NAME }}" >> $GITHUB_ENV
echo "ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID }}" >> $GITHUB_ENV
echo "AWS_REGION=ap-northeast-2" >> $GITHUB_ENV
# (4) ECR 리포지토리 생성 (없는 경우) 컨테이너 관리할 리포지토리
- name: Create ECR repository (if not exists)
run: |
aws ecr describe-repositories --repository-names $ECR_REPO_NAME || \
aws ecr create-repository --repository-name $ECR_REPO_NAME
env:
ECR_REPO_NAME: ${{ env.ECR_REPO_NAME }}
AWS_REGION: ap-northeast-2
# (5) ECR 로그인 (Docker 이미지 push를 위해)
- name: Login to Amazon ECR
run: |
aws ecr get-login-password --region ap-northeast-2 \
| docker login --username AWS --password-stdin $ACCOUNT_ID.dkr.ecr.ap-northeast-2.amazonaws.com
env:
ACCOUNT_ID: ${{ env.ACCOUNT_ID }}
# (6) Docker 이미지 빌드 및 태그 설정
- name: Build Docker image
run: |
# 타임스탬프를 이용한 유니크한 태그 생성
TIMESTAMP=$(date +%Y%m%d%H%M%S)
echo "IMAGE_TAG=${TIMESTAMP}" >> $GITHUB_ENV
# 로컬 태그로 빌드
docker build -t $ECR_REPO_NAME .
# ECR 푸시를 위한 태그 설정 (타임스탬프 태그 사용)
docker tag $ECR_REPO_NAME:latest $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_REPO_NAME:${TIMESTAMP}
env:
ECR_REPO_NAME: ${{ env.ECR_REPO_NAME }}
AWS_REGION: ${{ env.AWS_REGION }}
ACCOUNT_ID: ${{ env.ACCOUNT_ID }}
# (7) Docker 이미지를 ECR에 푸시
- name: Push Docker image
run: |
docker push $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_REPO_NAME:${IMAGE_TAG}
env:
ECR_REPO_NAME: ${{ env.ECR_REPO_NAME }}
AWS_REGION: ${{ env.AWS_REGION }}
ACCOUNT_ID: ${{ env.ACCOUNT_ID }}
# (8) AWS SAM CLI 설치 - Serverless Application Model
- name: Install AWS SAM CLI
run: |
sudo pip install --ignore-installed aws-sam-cli
# (9) SAM으로 Lambda 함수 배포
- name: Deploy with SAM
run: |
# 새로운 이미지 URI 설정 (타임스탬프 태그 사용)
IMAGE_URI="$ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_REPO_NAME:${IMAGE_TAG}"
ECR_REPO_URI="$ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_REPO_NAME"
# SAM 배포 실행 (--force-upload 추가)
sam deploy \
--template-file template.yaml \
--stack-name FlaskTranslateStack \
--capabilities CAPABILITY_IAM \
--parameter-overrides ImageUri=$IMAGE_URI \
--image-repository $ECR_REPO_URI \
--force-upload \
--no-fail-on-empty-changeset
env:
ECR_REPO_NAME: ${{ env.ECR_REPO_NAME }}
AWS_REGION: ${{ env.AWS_REGION }}
ACCOUNT_ID: ${{ env.ACCOUNT_ID }}
- git push 하면 자동으로 배포됨.
- AWS_SECRET_ACCESS_KEY, AWS_ACCESS_KEY_ID 등의 GitHub Secrets 필요.
- Actions >Secrets and varlables에서 필요 변수들을 설정하자. 계정 아이디는 AWS 프로필을 누르면 12개 숫자 확인가능
컨테이너는 커밋 푸쉬 후 자동으로 빌드 및 배포된다.
Amazon Elastic Container Registry (ECR)메뉴에서 컨테이너 확인가능
엔드 포인트 확인은
Lambda ➡️ 게이트웨이에서 확인가능
깃허브 액션즈 워크플로우 Deploy with SAM에서도 확인 가능하다.
8️⃣ 에러 디버깅 방법
- Lambda에서 에러가 발생하면, AWS Lambda 콘솔 > 모니터링 탭에서 로그 확인
- CloudWatch Logs에서 상세 에러 메시지 확인 가능
이제 git push 하면 Flask API가 자동 배포돼서, API Gateway URL로 호출할 수 있다!! 🚀