[AWS] Windows 개발 환경에서 Serverless Framework 오류 (Runtime.ImportModuleError)
봇진성이란?
start-aws Slack 워크스페이스에는 클라우드에 관심을 가지고 공부하는 2,000 명이 넘는 대학생, 멘토 분들이 활동하고 있습니다. 학생 분들은 AWS IAM 사용자 계정을 제공받아 AWS 기반 프로젝트를 진행합니다. 이때 모든 서비스에 대한 권한을 제공하면, 어마무시한 비용이 발생할 수 있습니다. 그래서 AWS Lambda 와 같이 비용 위험도가 낮은 서비스에 대한 권한만 부여한 채, 계정을 전달합니다.
만약 사용해야 하는 서비스가 있다면 AWS IAM 관리자에게 Slack 상에서 요청하고, 관리자는 이 요청을 AWS 콘솔에 접속하여 직접 부여해야 합니다. 이때 아래와 같은 문제점들이 발생합니다.
- AWS IAM 관리자가 이 요청을 실시간으로 처리해줄 수 없다.
- 1번으로 인해 요청자는 요청이 처리되기 전까지 개발을 진행할 수 없다.
이 문제를 해결하기 위해 봇진성이라는 프로젝트가 시작되었습니다.
24시간 작동할 수 있는 로봇 + AWS IAM User 계정 관리자 박진성 = 24시간 작동할 수 있는 AWS IAM User 계정 관리자 봇진성
서비스 플로우
- 권한이 없을 때 콘솔 상단에 출력되는 오류 문구
- 권한이 필요한 IAM User ID
- 권한이 필요한 서비스 명
이 3개의 정보를 Slack Workflow 에 입력하여 제출합니다.
오류 메시지로부터 추출된 필요 권한 리스트의 위험도를 측정하고, 이를 기준으로 아래의 세가지 플로우가 발생할 수 있습니다.
- 측정된 위험도가 기준(80/100)보다 낮다
- 측정된 위험도가 기준(80/100)보다 높다 & IAM 계정 관리자가 권한 부여를 승인한다
- 측정된 위험도가 기준(80/100)보다 높다 & IAM 계정 관리자가 권한 부여를 거절한다
이 3가지 상황에 맞게, 리액션으로 현재 상태를 공유 / 관리자에게 권한 부여 확인 요청 DM 전송 / 권한 부여 등을 수행합니다.
봇진성 개발 환경
봇진성은 AWS Lambda 에서 작동하는 서비스입니다. Python 3.11 + Serverless Framework 로 개발 및 배포를 진행하고 있습니다. 봇진성은 위 아키텍처 그림에서도 나타나 있듯이 Slack 과 GPT API 를 사용하므로, slack_sdk 와 openai 라이브러리를 필요로 합니다.
# serverless.yml
service: myService
provider:
name: aws
layers:
hello:
path: layer-dir # Lambda Layer 파일 경로(.zip 파일 경로 등)
name: ${sls:stage}-layerName # Lambda Layer 이름
description: blabla # Lambda Layer 의 설명 텍스트
compatibleRuntimes: # 해당 Lambda Layer 를 사용할 수 있는 런타임
- python3.11
compatibleArchitectures: # 호환 아키텍처
- x86_64
- arm64
AWS Lambda 에서 기본적으로 제공되는 라이브러리 그 외의 라이브러리를 사용하려면, 대부분 Lambda Layer 로 업로드하여 사용합니다. Serverless Framework Docs 공식 문서에서는 위와 같은 serverless.yml 가 Lambda Layer 로 작성되어 있었고, 이를 토대로 작성했습니다.
오류 해결
Runtime.ImportModuleError: Unable to import module 'handler': No module named 'pydantic_core._pydantic_core'
배포를 하는 과정에서 위와 같은 에러를 만나게 되었습니다. Lambda Layer 를 잘못 올렸을 때 자주 발생하던 에러인 No module named '~~~~' 의 형태입니다. 정말 간단하게 필요 라이브러리만 추가해주면 해결될 오류인데.. 아무리 해도 해결이 쉽지 않았습니다.
이 오류와 관련된 여러 글들을 읽어봤는데, 의심되는 부분을 발견했습니다. 바로 이 글에서 말이죠. 이 질문글의 댓글에서는 다음과 같이 말하고 있었습니다. "AWS Lambda 와 개발 환경 간의 아키텍처 차이 때문에 발생하는 오류이다"
# requirements.txt
openai==0.28
slack_sdk==3.27.1
# serverless.yml
plugins:
- serverless-python-requirements
custom:
pythonRequirements:
useDownloadCache: false
useStaticCache: false
그래서 직접 로컬에서 PIP 로 라이브러리를 설치하고, 이를 .zip 파일로 압축하여 레이어로 등록시키는 방식이 아닌 다른 방법을 찾았습니다. Serverless Framework 의 플러그인들 중 serverless-python-requirements 를 사용하면, Python 프로젝트의 의존성 관리를 비교적 쉽게 할 수 있습니다. requirements.txt 또는 Pipfile 에 명시된 Python 패키지를 자동으로 패키징하고 배포 패키지에 포함시켜줍니다.
이때 serverless-python-requirements 의 옵션값으로 useDownloadCache 와 useStaticCache 를 모두 false 로 설정해주었습니다. 이는 이미 로컬에 설치되어 있는 AWS Lambda 와 아키텍처가 일치하지 않는 버전 을 재배포에 사용하지 않도록 하기 위해서 설정하였습니다.
custom:
pythonRequirements:
dockerizePip: true
useDownloadCache: false
useStaticCache: false
Windows 환경과 Mac 환경을 번갈아가며 개발을 진행하고 있는 저는, 조금 더 안정적인 의존성 관리를 위하여 serverless-python-requirements 플러그인의 dockerizePip 옵션을 사용하였습니다.
dockerizePip 옵션은 Serverless Framework의 serverless-python-requirements 플러그인에서 사용할 수 있는 옵션입니다. Python의 의존성을 설치할 때 Docker를 사용할지 여부를 결정합니다.dockerizePip: true로 설정하면, pip 명령이 Docker 컨테이너 내에서 실행되어 Python 패키지를 설치합니다.
이는 로컬 환경과 AWS Lambda의 실행 환경 간에 차이를 최소화하고, 모든 의존성이 AWS Lambda에서도 문제 없이 작동하도록 도와줍니다. 디폴트 설정인 dockerizePip: false 로 설정하면, pip 명령이 로컬 환경에서 직접 실행되어 Python 패키지를 설치합니다.
아키텍처 오류?
'내 Lambda Function 도 x86, 내가 개발하고 있는 윈도우 환경도 x86 인데,, 왜 아키텍처 오류가 나는 것이지?' 라는 생각이 들었습니다. 이에 대해 많은 자료를 찾아봤고, 그에 대한 요약은 아래와 같습니다.
AWS Lambda 는 기본적으로 Linux 기반의 실행 환경을 제공합니다. 이는 결국 Linux 의 x86 을 의미합니다. 하지만 봇진성의 개발 환경은 Windows 의 x86 이였고, 이 사이에 여러 차이가 발생할 수 있습니다.
같은 x86 이여도, 현재 운영체제에 최적화 되어있기에 이를 다른 환경에서 사용 시에 문제가 발생할 수 있습니다.
파이썬 패키지 중에는 순수 파이썬으로만 작성되어 있는 것이 있는 반면, C 언어 등이 혼합되어 작성되어 있는 패키지 또한 존재합니다. 후자의 경우 운영 체제에 크게 종속되어 이와 같은 오류가 발생할 수 있습니다.
Amazon Linux EC2 에서 배포를 진행하면 어떨까?
Amazon Linux EC2 환경에서 Cloud9 으로 배포를 진행했습니다. 배포를 할 때 사용한 serverless.yml 파일은 아래와 같습니다. 이러한 설정으로 배포를 진행하게 되면, requirements.txt 에 작성되어 있는 패키지들을 pip 기본 옵션으로 install 하고, 이를 패키징 해서 Lambda 함수에 사용하게 됩니다.
# serverless.yml
service: bjs
frameworkVersion: "3"
provider:
name: aws
runtime: python3.11
architecture: x86_64
stage: dev
region: ap-northeast-2
httpApi:
id: cvd11qoyh4
iamRoleStatements:
- Effect: Allow
Action:
- lambda:InvokeFunction
Resource: "arn:aws:lambda:ap-northeast-2:629515838455:function:bjs*"
functions:
entrypoint:
handler: handler.lambda_handler
timeout: 30
tags:
service: bot-jinseong
events:
- httpApi:
path: /bjs
method: POST
attach-policy:
handler: bjs-attach-policy.lambda_handler
timeout: 30
tags:
service: bot-jinseong
events:
- httpApi:
path: /attach-policy
method: POST
plugins:
- serverless-python-requirements
Lambda x86 과 Amazon Linux x86 은 서로 같은 환경을 공유하기에, serverless-python-requirements 에 별다른 옵션을 주지 않아도, 패키지 사용에 문제가 없는 것을 확인하였습니다.
결론
이렇게 Lambda 환경과 개발 환경 간의 차이로 인해서 발생하는 오류를 확인하였고, 이를 해결해보았습니다.
Lambda 를 이용한 개발 및 배포는 '이렇게 쉬워도 되나' 싶을 정도로 쉽지만, 그 환경에 대한 이해는 필수임을 배울 수 있었던 시간이였습니다.
개발 및 도움을 주신 많은 멘토님들께 감사드립니다.
댓글
이 글 공유하기
다른 글
-
[AWS IAM] 최소 권한 원칙을 지키는 IAM 사용자 생성기
[AWS IAM] 최소 권한 원칙을 지키는 IAM 사용자 생성기
2024.08.28 -
[AWS] 개인 URL Shortener 만들기
[AWS] 개인 URL Shortener 만들기
2024.04.22