반업주부의 일상 배움사

FastAPI => AWS Lambda :: Serverless (without API Gateway) 본문

IT 인터넷/Python

FastAPI => AWS Lambda :: Serverless (without API Gateway)

Banjubu 2023. 3. 4. 10:03
반응형

 

https://www.youtube.com/watch?v=RGIM4JfsSk0 

 

 

[ 한국어 ]

안녕하세요, AWS Lambda에서 서버리스 방식으로 FastAPI 애플리케이션을 호스팅하는 방법을 배우는 이 튜토리얼에 오신 것을 환영합니다.

이전 동영상에서는 가상 서버로 생각할 수 있는 Amazon EC2에서 FastAPI를 호스팅했습니다. 하지만 실제 비즈니스나 서비스의 일부로 사용하는 방법, 즉 프로덕션 준비 방법에 대해 질문하신 분들도 계셨습니다.

솔직히 EC2를 사용하면 상당히 어려운 문제입니다. 트래픽이 증가할 때 호스트를 확장하는 방법, 트래픽 로드 밸런싱 방법, 앱에 대한 롤링 업데이트 방법, OS 및 보안 패치 적용 방법 등을 고려해야 합니다. 말할 것도 없이, API를 사용하는 사람이 있든 없든 서버 가동 시간에 대한 비용을 지불해야 하므로 계속 실행하는 데 비용이 많이 듭니다.

그래서 저는 API 호스팅에 서버리스 컴퓨팅을 사용하는 것을 선호합니다. 그리고 AWS에서는 서버리스 컴퓨팅 서비스를 AWS Lambda라고 부릅니다. 람다 함수라는 것을 만들 수 있는데, 기본적으로 클라우드에서 실행하려는 코드 조각이지만 확장, 보안, 호스팅, 로드 밸런싱 문제를 모두 AWS가 처리하도록 하는 것만 빼면 됩니다. 확장성이 매우 뛰어납니다. 또한 사용한 만큼만 비용을 지불하기 때문에 비용도 저렴합니다. 하지만 가장 중요한 것은 지루한 작업을 많이 덜어준다는 점입니다.

그렇다면 FastAPI를 어떻게 사용할 수 있을까요? 이 동영상에서는 FastAPI 애플리케이션을 가져와서 AWS Lambda와 함께 작동하도록 수정하고, 업로드하고, 테스트한 다음, 이를 라이브 HTTP 엔드포인트로 전환해 보겠습니다. 그리고 EC2 튜토리얼과 달리, 이 API는 즉시 프로덕션에 사용할 수 있습니다. 시작해보겠습니다.

이 프로젝트를 진행하려면 사용할 수 있는 FastAPI 프로젝트 또는 애플리케이션이 준비되어 있어야 합니다. 이 프로젝트에서는 이전 비디오의 일부로 만든 프로젝트를 사용하겠습니다. 따라서 여러분도 따라할 수 있습니다. 프로젝트가 없는 경우 아래 댓글에서 GitHub 링크를 확인하여 직접 복제할 수 있습니다.

또한 AWS 계정이 필요하고 람다 함수에 대한 약간의 지식이 있어야 합니다. 아직 익숙하지 않으시다면 관련 동영상을 확인하실 수 있습니다. 이 두 가지를 설정하고 나면 여기에서 시작할 수 있습니다.

에디터에서 프로젝트 폴더를 열었더니 VS Code가 있습니다. 프로젝트는 정말 간단합니다. 파일은 패스트 API 애플리케이션 파일 하나뿐입니다. 자체 프로젝트를 사용하는 경우 파일이 하나만 있을 수도 있고 여러 파일이 있을 수도 있습니다. 상관없습니다. 중요한 것은 FastAPI 애플리케이션을 만드는 데 사용하는 이 줄입니다.

 



따라서 여기에 있는 모든 경로와 모든 앱 관련 내용은 변경하지 않을 것입니다. 이 부분에만 집중하겠습니다. AWS Lambda에서 FastAPI를 실행할 때의 문제점은 Lambda 함수가 이 API 인터페이스, 즉 경로와 모든 것이 포함된 앱 겟 앱을 이해하지 못한다는 것입니다. 이 AGSI 인터페이스는 람다 함수가 이해할 수 있는 것이 아닙니다.

대신 람다는 핸들러 함수라는 것을 이해합니다. 따라서 기본 핸들러 함수는 다음과 같이 생겼습니다. 기본적으로 인자와 이벤트, 컨텍스트를 받는 함수입니다. 그리고 이것들은 모두 사전입니다. 람다 함수로 실행하려는 Python 파일을 생성할 때 처리기 함수로 간주할 내용을 알려주어야 합니다.

그리고 해당 람다가 실행되면 이 파일로 이 Python 런타임을 생성합니다. 그리고 우리가 지정한 이 함수를 실행합니다. 그런 다음 관련성이 있다고 생각되는 모든 것을 전달할 것입니다. 따라서 API 게이트웨이나 어떤 기술을 사용하든 HTTP 엔드포인트에 람다 함수를 연결하면 경로 정보, 헤더 등 모든 것이 이벤트 및 컨텍스트 객체에 숨겨지게 됩니다.

따라서 해당 데이터의 압축을 풀고 적절한 FastAPI 경로 또는 여기에 있는 이 하위 함수로 라우팅하는 방법을 찾아야 합니다. 이제 직접 포장을 풀고 주어진 이벤트에 따라 어떤 함수를 사용할지 알아내서 먼 길을 갈 수도 있고, 지름길을 택하여 이미 누군가가 이 작업을 위해 고안한 기존 솔루션을 사용할 수도 있습니다.

그리고 GSI 애플리케이션을 실행하기 위한 어댑터인 맨검이라는 라이브러리를 사용할 수 있습니다. 이것은 함수 URL API 게이트웨이 등을 처리하기 위해 AWS Lambda에 있는 FastAPI 애플리케이션입니다. 따라서 사용 방법은 먼저 설치하기만 하면 됩니다. 파이썬 환경으로 이동하여 pip install man gum을 입력하기만 하면 됩니다. 

이 작업이 완료되면 전체 앱을 맨 껌 핸들러로 감쌀 수 있습니다.
이제 문서를 살펴봅시다.
여기에는 기본적으로 처음 두 줄만 있습니다.
먼저 가져와야 합니다.
이제 그 래퍼를 사용해 핸들러를 만들겠습니다.

그리고 여기서 이 핸들을 삭제할 수 있습니다.
이제 이 핸들러 함수는 AWS 람다가 이해할 수 있는 함수입니다.
그리고 함수 요청을 이러한 하위 경로 중 하나로 올바르게 라우팅할 것입니다.

이제 해당 파일을 저장하세요.
이제 파일이 준비되었습니다.
이제 Lambda에 업로드해야 합니다.

그럼 이제 업로드해서 어떤 일이 일어나는지 확인해 봅시다.
AWS 콘솔로 이동하여 Lambda를 검색하거나 클릭합니다.
그리고 나서 함수 생성을 클릭하여 새 람다 함수를 만듭니다.

이제 처음부터 새로 만들겠습니다.
그리고 원하는 대로 함수를 호출할 수 있습니다.
저는 FastAPI 서점이라고 부르겠습니다.
그런 다음 런타임은 Python 3.9 또는 원하는 것을 선택하면 됩니다.

그러면 다른 작업은 할 필요가 없습니다.
다른 모든 설정은 기본 설정으로 그대로 두면 됩니다.

그러니 함수 생성을 클릭하고 생성될 때까지 잠시 기다리세요.
완료되면 다음과 같은 화면이 표시됩니다.
여기에는 몇 가지 다른 요소가 있지만 이 위쪽 부분은 걱정할 필요가 없습니다.

조금 아래로 스크롤하면 코드 소스를 볼 수 있습니다.
이것이 바로 아까 말씀드린 코드, 즉 이 람다 함수가 호출될 때 함수가 실행될 파이썬 코드가 될 것입니다.

그리고 여기에는 200을 반환하는 람다 핸들러인 일종의 Hello World 코드가 작성되어 있습니다.

이제 변경하기 전에 실제로 테스트하여 작동하는지 확인할 수 있습니다.
그리고 새로운 테스트 이벤트가 필요합니다.
그냥 Hello라고 부르겠습니다.
그리고 이것이 람다 함수에 들어갈 이벤트 객체입니다.

변경할 필요는 없습니다.
그냥 저장하고 실행하면 됩니다.
이제 끝났습니다.
이 함수가 실제로 실행되고 Lambda 텍스트에서 Hello를 반환합니다.

아주 기본적이죠.
이제 FastAPI 애플리케이션을 복사하여 여기에 넣으면 어떤 일이 발생하는지 살펴봅시다.
말 그대로 전체 코드를 복사해서 여기에 넣겠습니다.
하지만 개발 환경과 일관성을 유지하기 위해 이름을 main.py로 바꾸겠습니다.

이제 준비가 되었습니다.
이 함수는 로컬에서 사용하는 것과 거의 동일합니다.

이제 이 변경 사항을 실제로 저장하려면 배포를 클릭해야 합니다. 여기에는 변경 사항이 배포되지 않았다고 표시되어 있기 때문입니다.
따라서 다시 실행해도 여전히 이전 버전을 반환합니다.

이제 배포를 누르겠습니다.

이 배너가 녹색으로 바뀌면 업데이트가 성공적으로 완료된 것입니다.

그래서 다시 테스트를 누릅니다. 이번에는 이 파일에서 람다 함수 모듈을 찾을 수 없기 때문에 오류가 발생합니다.
를 찾을 수 없기 때문에 오류가 발생합니다. 파일 이름을 main.py로 변경했기 때문입니다. 그리고 핸들러의
라는 이름을 그냥 핸들러로 변경했습니다. 따라서 이 람다 함수가 어디에 있는지 알려줘야 합니다.
우리가 만든 이 핸들러 함수를 찾아야 합니다.

조금 아래로 스크롤하면 여기에 이 런타임 설정이 표시됩니다.
그리고 여기에 핸들러 설정이 있는데, 이 핸들러 설정은 람다 함수라는 파일과 그 함수에서
람다 핸들러를 찾고 있습니다. 그래서 우리는 실제로 이것을 편집해야 합니다. 그리고 나서 이것을 다음과 같이 변경하겠습니다.
메인 파일로 변경합니다. 그리고 이 함수를 핸들러라고 부릅니다. 메인 도트 핸들러,
저장합니다.

코드 자체는 변경되지 않았으므로 실제로는 아무것도 다시 배포할 필요가 없습니다.
그리고 보시다시피 아래에서 변경한 설정이 여기에 적용됩니다. 이제 다시 실행해 봅시다,
작동하는지 확인해 보겠습니다.

이번에는 다른 오류가 발생했습니다. 실제로 핸들러 함수를 찾았지만
하지만 이제 FastAPI를 가져올 수 없기 때문에 실패합니다. 그리고 이것은 실제로 매우 일반적인
파이썬 함수를 람다로 가져오는 것을 막 시작한 사람들에게는 매우 흔한 실패 유형입니다.
모든 종속성이 있어야 하기 때문입니다.

Lambda에서 함수를 실행할 때 런타임에 있는 것은 사실 이것뿐입니다.
파이썬 라이브러리가 있습니다. 기본적으로 AWS API 라이브러리도 내장되어 있을 것 같습니다. 하지만 그것 말고는
이 환경에는 다른 것이 없습니다. 따라서 FastAPI나 pip와 함께 설치하는 모든 것들은 이 폴더 안에
이 폴더 안에 넣을 방법을 찾아야 합니다.

사실 이것은 그리 나쁜 문제처럼 들리지 않습니다. 모든 종속 요소를 끌어다 놓기만 하면 되니까요,
그렇죠? 하지만 실제로는 그보다 더 복잡해집니다. 예를 들어 업데이트할 수 있게 하려면 어떻게 해야 할까요?
이 기능을 어떻게 업데이트할까요? 종속성을 어떻게 업데이트할까요? 그리고 어떻게 하면 여러분의 개발 환경에서
개발 환경에서도 작동하고 클라우드의 Lambda 함수와 동기화할 수 있을까요?

사실 이 문제를 해결할 수 있는 방법은 여러 가지가 있습니다. Docker에 익숙하다면 Lambda는
Docker를 실행할 수 있습니다. 따라서 이를 사용하여 모든 종속성을 설치한 다음 해당 Docker 이미지를 실행할 수 있습니다.
모든 종속성을 한 번 설치한 다음 이미 Lambda 베이스 레이어라는 것을 만들 수 있습니다.
해당 베이스 레이어를 사용하는 함수의 모든 항목에 이미 존재합니다.

또는 디스크에 전체 종속성 디렉터리를 압축한 다음 Lambda 함수에 업로드할 수도 있습니다.
이것이 가장 간단한 방법이고 가장 쉬운 방법이기 때문에 이 튜토리얼에서는 이 방법을 사용하겠습니다.

이제 프로젝트 폴더로 돌아와서 종속성이 폴더의 아무 곳에도 없는 것을 볼 수 있습니다.
실제로 다른 위치에 저장하는 가상 환경을 사용하고 있기 때문입니다. 따라서 여기에는 없습니다.
여러분도 마찬가지일 수도 있고, 기본 Python 인터프리터에서 라이브러리를 직접 사용하고 있을 수도 있습니다.

따라서 이러한 종속성을 로컬 디렉터리에 설치하는 방법을 찾아야 합니다.
이제 이 GitHub 프로젝트의 README로 돌아가서 댓글에 있는 이 FastAPI ADBS Lambda GitHub 프로젝트에 실제로 이 모든 작업을 수행하는 데 사용할 수 있는 몇 가지 유용한 명령을 붙여넣어 놓았습니다.

따라서 t 플래그와 폴더 이름으로 pip install을 실행하면 실제로 원하는 파일이나 종속성을 해당 하위 디렉터리에 설치합니다.
그래서 저는 그렇게 할 것입니다.

또한 개별적으로 설치하는 것이 아니라 요구 사항 도트 텍스트에서 설치하겠습니다.

먼저 방금 설치한 라이브러리인 맨검을 요구 사항 도트 텍스트에 추가하겠습니다.
그런 다음 터미널에 이 프로젝트의 라이브러리를 의미하는 pip install dash t 라이브러리를 입력합니다.

그리고 요구 사항을 텍스트에 점으로 표시합니다.

이 작업이 완료되면 프로젝트로 돌아가면 기본적으로 이 프로젝트에 필요한 모든 Python 종속성이 포함된 새 라이브러리 디렉터리가 생성된 것을 볼 수 있을 것입니다.

이제 이 모든 것을 압축하여 Lambda에 업로드해야 합니다.
하지만 이것은 일종의 임시 라이브러리처럼 설치되었기 때문에 실제로 프로젝트에서 사용하지 않을 것이므로 실수로 커밋하여 프로젝트에 쓸모없는 코드가 많이 남는 것을 방지하기 위해 git 무시 항목에 추가하고 싶습니다.
그래서 여기에 lib를 추가하겠습니다.
그러면 회색으로 바뀔 것입니다.

이제 이걸 어떻게 압축할까요?
이 파일을 압축할 때 실제로 이 모든 파일과 모든 폴더가 루트 경로에서 확장되기를 원합니다.
그래서 여기 이 lib 폴더에 넣었지만 람다 함수에서 메인 닷 파이가 액세스할 수 있도록 하려면 lib 폴더에 있으면 안 되고 공간 디렉터리에 있어야 합니다.

다시 돌아가서 다음 명령어를 읽어보면 어떻게 하는지 알 수 있습니다.
기본적으로 디렉터리를 라이브러리 파일로 변경한 다음 거기에 압축을 걸어야 합니다.
그런 다음 이전 상위 디렉터리와 같은 종류의 람다 함수라는 파일에 압축할 것입니다.
그리고 이 대시 또는 재귀를 의미합니다.
그래서 모든 파일에 있는 모든 것을 거기에 압축합니다.
그리고 점은 해당 디렉토리에서 수행한다는 의미입니다.

이제 터미널에서 실제로 실행해 보겠습니다.

실행이 완료되면 다시 프로젝트로 돌아가서 이제 여기에 새로운 람다 함수 도트 압축 파일이 있는 것을 볼 수 있습니다.
이 파일도 커밋하고 싶지 않으므로 무시 목록에 추가하겠습니다.

이제 실제로 제가 해야 할 일은 이 메인 닷 파이를 해당 zip 파일에 추가하는 것뿐입니다.
다시 읽어주기로 돌아가서, 마지막으로 실행해야 할 명령이 하나 있습니다.
zip 람다 함수인 dot zip dash u와 main dot py입니다.
대시 u는 zip 파일을 바꾸지 말고 업데이트하거나 새로운 것을 추가하라고 말합니다.
그리고 이것이 우리가 원하는 파일입니다.

그러니 그냥 복사하세요.
그럼 람다 함수를 zip으로 압축한 다음 메인 파일인 dot py 파일을 복사합니다.
자, 이제 우리의 API는 지난 튜토리얼을 따랐다면 실제로 데이터베이스 저장소 역할을 하려면 로컬에 book.json 파일이 필요한데, Lambda에는 하드 디스크 개념이 없기 때문에 AWS Lambda에서는 실제로 이 작업을 수행하는 좋은 방법이 아닙니다.
함수가 실행될 때마다 완전히 새로운 컴퓨터가 실행된다고 생각하면 됩니다. 따라서 우리가 디스크에 저장하거나 쓰는 모든 내용은 해당 함수가 종료된 후에는 거의 존재하지 않게 됩니다. 아마도 람다가 아직 따뜻할 때 15분 동안, 즉 람다가 함수를 재활용하여 새로운 함수를 생성하기 전까지 해당 컴퓨터에서 함수가 살아 있는 시간 동안일 것입니다.
하지만 결론은 실제로 거기에서 파일을 쓰거나 읽을 수 없으며 지속될 것으로 기대할 수 없다는 것입니다. 다만 이 튜토리얼에서는 이 문제를 다루지 않으려고 합니다.
따라서 지금은 그냥 무시하겠습니다. 제이슨이 메인 파이와 잘 작동하여 API의 데이터 소스를 제공할 것이라는 점을 당분간 이 책을 통해 미리 알려드리고자 합니다.
그럼 이제 이 책도 zip에 추가해 보겠습니다.
이제 압축 파일에 해당 파일을 추가했습니다.
브라우저에서 zip 폴더를 열면 실제로 모든 종속 요소와 함께 main.py 파일 및 books.json 데이터 파일을 볼 수 있습니다.
이제 이 zip 파일을 사용할 준비가 되었습니다. 이 파일을 Lambda에 넣으면 바로 실행할 수 있습니다.
이제 AWS 콘솔의 Lambda 함수로 돌아가서 코드 소스에서 업로드 위치 버튼으로 이동한 다음 여기에서 zip 파일을 선택할 수 있습니다.
그 버튼을 클릭한 다음 업로드할 zip 파일을 선택하고 저장을 누르세요.
이제 완료되면 코드 소스에서 더 이상 패키지 내용을 보거나 수정할 수 없다는 것을 알 수 있습니다.
지금은 그냥 zip 파일일 뿐이지만 로컬에서 빌드할 때 이미 그 안에 무엇이 들어 있는지 알고 있기 때문에 괜찮습니다.
이제 함수를 다시 실행하고 어떤 일이 일어나는지 살펴봅시다.

여전히 실패합니다. 하지만 로그를 열어보면 이번에는 다른 오류가 발생한다는 것을 알 수 있습니다. 어댑터가 이벤트에 사용할 핸들러를 유추할 수 없다고 나와 있습니다. 이는 람다 함수가 호출된 방식과 관련이 있을 수 있습니다. 로컬에서 테스트하고 있나요? 요청 페이로드가 지원되는 핸들러에 유효한지 확인하세요.

영어로 번역하면, 기본적으로 우리가 람다에 제공하는 페이로드가 람다가 이해할 수 있는 것이 아니라는 뜻입니다. 이것을 파싱할 수 없습니다. HTTP 경로, 경로, 헤더를 이해하지 못합니다. 그런 정보를 기대하지만 그런 정보가 없습니다.

따라서 이 인터페이스를 사용하여 테스트하기 위해 실제로 할 수 있는 일은 새 이벤트를 만드는 것입니다. 그런 다음 템플릿으로 이동하면 API 게이트웨이 AWS 프록시라는 템플릿이 있는데, 이 템플릿은 실제로 람다 함수를 실제 API 엔드포인트에 연결할 때 얻을 수 있는 정보입니다. 하지만 이것은 템플릿입니다. 따라서 몇 가지를 수정해야 합니다.

우선, 사용할 경로와 사용할 HTTP 메서드도 선택해야 할 것입니다. 저는 정말 간단한 작업을 하고 싶습니다. 그래서 저는 이 루트 경로를 선택하려고 합니다. 그래서 경로를 루트 슬래시 디렉토리로 바꾸겠습니다. 그리고 이 경로를 get 요청으로 만들겠습니다. 이제 이 페이로드를 수정해서 그렇게 하도록 하겠습니다.

이제 페이로드 구조는 이 정보가 실제로 JSON 데이터 전체에 걸쳐 여러 지점에서 반복되도록 되어 있습니다. 따라서 해당 필드가 표시되는 각 지점을 살펴보고 변경하면 됩니다. 여기서 진행되는 다른 모든 내용을 이해하지 못하더라도 걱정하지 마세요. 지금 이 시점에서는 그 어떤 것도 건드릴 필요가 없습니다.

이제 수정이 완료되었으니 이 이벤트를 저장하겠습니다. 오, 새 이름을 생각해 내야겠어요. FastAPI HTTP 페이로드 히트 저장이라고 부르겠습니다. 이제 다시 테스트해 보겠습니다. 이번에는 성공했습니다. 세부 사항으로 이동하면 응답이 내 서점 앱에 환영한다는 것을 알 수 있습니다.

실제로 이 함수를 호출해야 한다는 것을 성공적으로 파악하고 이 메시지를 반환한 것을 볼 수 있습니다. 이제 FastAPI가 AWS 람다에서 작동하고 있습니다. 다른 경로로 변경할 수도 있습니다. 예를 들어 책을 나열하는 경우 여기에 복사하겠습니다. 이벤트를 변경할 수 있는지 테스트하고 싶다고 가정해 보겠습니다. 경로를 책 목록으로 만들되, 책이 나타나는 모든 곳에서 경로를 변경해야 합니다.

이 페이로드에서 총 세 곳에 나타나는 것 같습니다.
좋아요, 저장을 누른 다음 다시 테스트합니다.

이제 JSON 폴더에 번들로 묶은 모든 책이 실제로 나열되는 것을 볼 수 있습니다.

지금까지는 꽤 잘 진행되고 있습니다. 이제 FastAPI 애플리케이션을 핸들러로 래핑하고
람다 함수에 넣었습니다. 테스트를 해보니 작동합니다. 우리는 이것을 실행할 수 있고
서버가 없어도 실행할 수 있습니다. 그리고 클라우드에 있습니다.

이 프로젝트를 마무리하기 위해 마지막으로 필요한 것은 실제로 공용 HTTP 엔드포인트를 만들어서 HTTP 연결이 가능한 모든 곳에서
호출할 수 있도록 하는 것입니다. 브라우저에서, 다른 앱에서, 프런트엔드에서.

이제 이 작업을 시작하겠습니다. 사실 이 작업은 꽤 복잡한 작업이었습니다. 이전에는 API 게이트웨이라는 다른 AWS 서비스를 사용해야 했습니다. 그리고 이를 구성하고 프록시라는 것을 통해 람다에 연결한 다음 이러한 상호 작용을 별도로 테스트하고 작동하는지 확인해야 했습니다.

하지만 오늘 Lambda에는 HTTP 엔드포인트를 즉시 아주 쉽게 만들 수 있는 새로운 기능이 추가되었습니다. 구성으로 이동하면 함수 URL이라는 탭이 있습니다. 아무것도 할 필요가 없습니다. 함수 URL 생성을 누르기만 하면 됩니다. 여기에서 유형 없음을 선택한 다음 교차 도메인 오리진 액세스를 구성할 수 있습니다. 이 항목만 별표로 남겨두고 다른 모든 항목은 기본값으로 두면 됩니다. 그리고 다른 많은 정보가 제공될 것입니다. 지금은 신경 쓸 필요가 없습니다. 그냥 저장을 누르면 됩니다.

이제 완료되었습니다. 이미 사용할 수 있는 함수 URL이 생겼습니다. 이제 브라우저에서 확인해 보겠습니다. 함수 URL을 열고 확대하겠습니다. 그리고 여기에 응답하는 공개 URL이라는 것을 알 수 있습니다. 따라서 실제로 어디서나 볼 수 있고, 휴대폰이나 다른 컴퓨터에서 시도해 볼 수 있으며, 실제로 여기에서 액세스할 수 있습니다.

이 못생긴 API URL을 없애고 나만의 도메인 이름을 가지려면 어떻게 해야 하나요? 이 경우에도 여전히 API 게이트웨이를 사용한 다음 라우트 53에 연결하여 DNS 확인을 받아야 할 수도 있습니다. 하지만 내부적으로 또는 더 큰 앱이나 서비스의 일부로 사용할 수 있는 API를 얻는 것이 목표라면 이 API를 사용하는 것이 좋습니다. 공개되어 있습니다. 그리고 바로 사용할 수 있는 HTTPS 프로토콜을 지원합니다.

실제로 도서 목록과 같은 경로를 입력하여 테스트해 볼 수 있습니다. 여기 JSON 파일에 있는 모든 책을 볼 수 있습니다. 임의의 책과 같은 다른 경로도 시도해 볼 수 있습니다. 이것도 잘 작동합니다.

이제 API를 사용할 준비가 되었습니다. 하지만 이 JSON 파일과 람다 함수가 영구적인 상태가 아니라고 말씀드렸던 것을 기억하시나요? Lambda는 서버를 유지하지 않기 때문에 이는 사실 중요한 부분입니다. 제가 이 API를 호출할 때 Lambda는 "이 함수를 실행하라는 요청을 받고 있습니다."라고 말합니다. 이 함수를 실행할 가상 서버를 프로비저닝해 봅시다. 그리고 그 가상 서버에서 JSON 파일을 포함하여 우리가 가지고 있던 모든 코드를 복사할 것입니다. 그런 다음 실행하고, 파일에서 읽고, 심지어 파일에 쓸 수도 있습니다. 하지만 해당 함수가 완료되면 해당 환경은 더 이상 존재하지 않게 됩니다. Lambda에 의해 재활용될 것입니다. 따라서 이를 변경하기 위해 수행한 모든 작업은 손실됩니다. 그리고 다음에 함수가 실행될 때는 여기서부터 다시 새로 시작됩니다.

따라서 람다 함수를 사용하는 경우 로컬 디스크에 저장하는 것과 같은 방식에 의존해서는 안 됩니다(이 프로젝트에서는 이를 무시하고 그냥 사용했지만).
실제로 원하는 것은 데이터베이스에 연결하는 것입니다. 아마존에는 실제로 람다와 잘 작동하는 많은 데이터베이스가 있지만, Postgres나 SQL 등 익숙한 다른 데이터베이스에도 람다를 사용할 수 있습니다. 따라서 데이터를 저장하기 위한 다른 별도의 메커니즘이 필요합니다. 그리고 로컬 드라이브에만 의존해서는 안 됩니다.

여기까지 FastAPI 애플리케이션을 AWS Lambda에 배포하는 방법에 대해 설명했습니다. 이 튜토리얼이 도움이 되셨기를 바랍니다. 질문이나 의견이 있으시면 아래 댓글을 통해 알려주시기 바랍니다. 도움이 필요하시면 제 동영상 설명에서 링크와 프로젝트 소스 코드를 확인하시기 바랍니다. 아무쪼록 도움이 되셨기를 바라며 시청해 주셔서 감사합니다.

 

 

 

[ English ]

 

Hey everyone, welcome to this tutorial where you'll learn how to host a fast API application serverlessly on AWS Lambda.

In my previous video, we hosted fast API on Amazon EC2, which you can think of as virtual servers. But some of you asked how to get it production ready, meaning how to use it as part of a real business or service.

Honestly, with EC2, that's quite a challenge. You have to think about things like how to scale out your hosts when your traffic increases, how to load balance the traffic, how to do rolling updates for an app, and how to do OS and security patching. Not to mention, it'll be expensive to keep running because you'll be paying for uptime of the server, whether you have people using your API or not.

That is why I prefer to use serverless compute for hosting APIs. And on AWS, the serverless compute offering is called AWS Lambda. We can create something called a Lambda function, which is basically a piece of code we want to run in the cloud, except we let AWS handle all of the scaling, security, hosting, and load balancing problems. It scales very well. It's also cheap because we only pay for what we use. But the most important thing is that it takes a lot of the boring work off of our plate.

So how do we use it with fast API? Well, in this video, we're going to take a fast API application, we're going to modify it to work with AWS Lambda, we're going to upload it, test it, and then turn it into a live HTTP endpoint. And unlike in our EC2 tutorial, this API is going to be more or less production ready, right out of the box. Let's get started.

To work on this project, you're going to need to have a fast API project or application ready to use. For this one, I'm going to be using a project I created as part of a previous video. So you can follow along with that. If you don't have a project, check in the comments below for a GitHub link, and you can just clone it directly.

You'll also need an AWS account and have some knowledge with Lambda functions. I have a video you can check out on that as well, if you're not up to speed with that yet. So once you have those two things set up, you can start here.

I've opened up the project folder in my editor, which is VS Code. And the project's really simple. There's only one file, which is the fast API application file. If you're using your own project, then you might have a file as well, or you might have multiple files. It doesn't matter. The important thing we're going to look at is this line, which we use to create the fast API application.

So all of this path stuff and all this app stuff that we have here, it doesn't, we're not going to change any of that. We're just going to focus on this thing. The problem with running fast API on AWS Lambda is that Lambda functions don't understand this API interface, this app get app, you know, with the routes and everything. This AGSI interface is not something that's understood by Lambda functions.

Instead, Lambda understands something called a handler function. So a basic handler function looks something like this. It's basically just a function that takes into arguments and event and some context. And these are both dictionaries. When we create a Python file that we want to run as a Lambda function, we have to tell it what we want it to consider the handler function.

And when that Lambda is run, it will create this Python runtime with these files. And it will run this function that we specify for it. And then it's going to pass in anything it thinks is relevant. So when we hook up a Lambda function to an HTTP endpoint, maybe with API gateway or whatever technology we use, all the things like the path information, the headers, all that stuff is going to be hidden away in these event and context objects.

And so we have to find a way to unpack that data and have it route to the appropriate fast API path or this sub function here that we have. Now we can go the long way by unpacking this ourselves and then figuring out which of these functions to use, depending on what event is given, or we can sort of take a shortcut and use an existing solution that someone already came up for this.

And we can use this library called man gum, which is an adapter for running a GSI applications. That's our fast API application there in AWS Lambda to handle function URL API gateway, et cetera, et cetera. So the way we use it is we just first have to install it. So go to your Python environment there and just type pip install man gum.

And once that's done, you can wrap your entire app with a man gum handler.
So let's go and have a look at their documentation.
And it's pretty much basically just this first two lines here.
We have to import it first.
And now we'll create our handler using that wrapper.

And I can delete this handle here.
So now this handler function is something that AWS Lambda can understand.
And it's going to route that function request correctly to one of these sub paths.

So just save that file.
Now our file is ready.
We need to upload it to Lambda.

So let's go ahead and try that and see what happens.
Go into your AWS console and search or click on Lambda.
And once you're there, click on create function to make a new Lambda function.

And we're just going to do it from scratch.
And you can call the function whatever you want.
I'm going to call it fast API bookstore.
And then for the runtime, we'll choose our Python 3.9 or whichever one is the one you want.

And then we don't really need to do any of this other stuff.
We can just leave everything else at its default setting.

So just click create function and wait a while for that to create.
Once it's finished, you should see something like this.
There's a couple of different elements here, but we don't have to worry about this top part.

And if you scroll down a little bit, you see the code source.
So this is what I was talking about earlier, where this is going to be the code, the Python code that your function will run when this Lambda function is invoked.

And here they've written some kind of Hello World code for us, which is just a Lambda handler that returns 200.

So we can actually test this out now before we change anything just to make sure it works.
And we're going to need a new test event.
So we'll just call it Hello.
And then this is the event object that's going to go into the Lambda function.

We don't need to change that.
We'll just save and then we'll run it.
And there you go.
This function actually executes and it returns this Hello from Lambda text there.

Okay, so very basic.
Let's see what happens when we just copy our fast API application and just put it in here.
So I'm literally just going to copy the entire code and I'm going to put it here.
But to keep it consistent with our development environment, I'm also going to rename this to main.py.

Okay, so now that's ready.
And this function is pretty much the same as we have locally.

Now, if we actually want to save this change, we have to click deploy because here it says change is not deployed.
So it's if we run it again, it's still returning the previous version we had.

So let's go ahead and hit deploy.

And once this banner turns green, it says it's successfully updated.

So we hit test again. And this time we have an error because we can't find the Lambda function module
in this file. That's because we changed the name of the file to main.py. And we also changed the handler
name from Lambda handler to just handler on its own. So we have to tell this Lambda function where to
look for this handler function that we created.

So if you scroll down a little bit, you'll see this runtime settings here.
And here is the handler setting, which it's looking for a file called Lambda function and a function called
Lambda handler in that function. So we actually have to edit this. And then we're going to change this to
main because that's what our file is called. And then our function is called handler. So main dot handler,
then save.

Okay, so we don't actually have to deploy anything again, because the code itself didn't change.
And their settings that we changed below took effect here, as we can see. So let's go ahead and run this again,
and see if it works.

Okay, so this time it's a different error. It actually found the handler function,
but now it fails because it can't import fast API. And this is actually a very common
type of failure for people just getting started importing their Python functions into Lambda, because you actually
also have to have all the dependencies.

When you're running a function in Lambda, it actually, this is the only thing it has in its runtime.
It's got the Python library. I think it might have the AWS API library as well built in by default. But apart from that,
the environment has nothing else. So things like fast API or anything that you install with pip, you also have to find
a way to put it inside this folder here.

Now, that doesn't actually sound like a very bad problem. Like, let's just drag and drop all our dependencies in there,
right? But actually, it gets more complicated than that. For example, what if you want to be able to update them?
How do you keep this function updated? How do you keep the dependencies updated? And how do you do it in such a way that
you can have it working in your dev environment and also synced up to your Lambda function in the cloud there?

There's actually a lot of different ways this problem can be solved. If you're familiar with Docker, then Lambda is
also able to run Docker. So you can use that to install all your dependencies there and then just run that Docker image.
You can create something called a Lambda base layer where you install all your dependencies once and then it's already
existing for anything in your function that uses that base layer.

Or you can pretty much zip up the entire dependency directory on your disk and then upload it to the Lambda function.
And because that's the most straightforward way and the easiest thing to do, that's what we're going to do here in this tutorial.

So now I'm back in my project folder and you can see that the dependencies are not anywhere here in the folder.
That's because I'm using a virtual environment that actually saves it to a different location. So it's not here.
And you might be doing the same as well, or you might be using the libraries directly in your base Python interpreter.

So we have to find a way to install those dependencies into a local directory.
Now, if you go back to the README in this GitHub project, this fast API ADBS Lambda GitHub project I have in the comments, I've actually pasted a few useful commands that we can use to do all those things.

So if we run pip install with a t flag and a folder name, it's going to actually install the files or the dependencies we want into that sub directory.
So I'm going to go ahead and do that.

And I'm also going to install it from a requirements dot text rather than individually, although you can do that as well.

So first I'm going to add man gum, the library that we just installed to our requirements dot text.
And then in my terminal, I'm going to type pip install dash t libraries, which is going to be standing for the libraries of this project.
And then our requirements dot text.

And once that's done, if you go back to your project, you should see this new lib directory created with basically all of the Python dependencies we need for this project.

So we're going to have to zip all of that up and upload it to Lambda.
But because this is installed as sort of like a transitory library, we're not actually using this in our project, I'm going to want to add it to my git ignore so that I don't accidentally commit this and just have a bunch of useless code going around with me in my project.
So we're just going to add lib to that.
And that should just turn gray.

Okay, so now how do we zip this up?
When I zip this up, I actually want all of these files, all of these folders expanded in the root path.
So even though I've put them in this lib folder here, when we have it in our Lambda function, for our main dot py to be able to access it, it can't be in a lib folder, it should just be in the space directory.

So if you go back to this, read me the next command will tell you how to do that.
We'll basically have to change directory into the library file, and then zip it there.
But then we're going to zip it into file called Lambda function in the sort of the previous the parent directory.
And this dash or means recursive.
So we zip everything in every file there as well.
And the dot just means do it in that directory.

So let's go ahead and actually run this in our terminal.

Okay, once that's finished running, I'll go back to my project again, and I can see that there's a new Lambda function dot zip file here now.
I'm also going to add the zip file to our ignore list because I don't want to commit that one either.

And now I actually the only thing I have to do now is just add this main dot py to that zip file.
So again, back to the read me, there is one last command we have to run.
It's zip lambda function dot zip dash u and then main dot py.
So the dash u says that don't replace the zip file, just update it or add new things to it.
And this is the file we want.

So just go ahead and copy that one.
So zip lambda function dot zip dash u and then our main dot py file.
Okay, and now our API, if you followed the last tutorial, it actually needs a book.json file locally to act as its database storage, which this is actually not a good way to do it with AWS Lambda because there's no concept of hard disk on Lambda.
Every time the function runs, you can pretty much think of it as running a whole new computer. So anything we save or write to disk is pretty much not going to exist after that function terminates. Maybe for 15 minutes while the Lambda is still warm, which is how long a function stays alive for on that machine before Lambda kind of recycles it and creates a new one.
But the bottom line is we can't really write or read files from there and expect it to persist. It's just that that's not a problem I'm trying to address in this particular tutorial.
So we're just going to ignore it for now. I'm just kind of letting you know ahead of time for the time being this books that Jason will work nicely with our main py to provide a data source for our API.
So let's go ahead and add that to our zip as well.
Okay, so now I finished adding those files to my zip.
And if I open the zip folder up in my browser, I can actually see all of the dependencies along with my main.py file and my books.json data file.
So now this zip file is ready to go. If I put this on Lambda, I can just run it.
So let's go back to our Lambda function in the AWS console and in our code source, go to this button that says upload from and then here you can choose a zip file.
So click on that and then select your zip file to upload and hit save.
And now when it's finished, you're going to see that the code source doesn't actually let us look or modify the package contents anymore.
It's just a zip file at this point, but that's okay because we already know what's in it from when we built it locally.
Now let's go ahead and run the function again and see what happens.

This one still fails. But if you open up the log, you're going to find that it's a different error this time. It says the adapter was unable to infer a handler to use for the event. This is likely related to how the Lambda function was invoked. Are you testing locally? Make sure your request payload is valid for a supported handler.

So translated into English, this basically means the payload we're giving, like the stuff we're giving to Lambda, this stuff is not something it understands. It can't parse this. It doesn't understand the HTTP path, the routes, the headers. It's expecting that information, but it's not there.

So what we can actually do so that we can test using this interface is create a new event. And then if you go to the template, there's one called API Gateway AWS proxy, which this is actually the kind of information that we're going to get when we hook up the Lambda function to an actual API endpoint. But this is a template. So we're going to have to modify a couple of things.

First of all, we're going to probably have to pick a path to use and an HTTP method to use as well. I want to do something really simple. So I want to just pick this maybe this root path. So I'm going to turn the path into just my root slash directory. And then I'm going to make it a get request. So let's go ahead and modify this payload to do that.

Now the payload structure is such that this information is actually repeated several points throughout the JSON data. So you're just going to have to go through and change each of the times you see those fields. And don't worry if you don't understand all the other stuff that's going on here, you don't have to touch any of that at this point.

So now that's been modified, I'm just going to save this event. Oh, I have to come up with a new name for it. I'm going to call it fast API HTTP payload hit save. Now I'm going to test it again. This time it's successful. And if we go to the details, you could see that the response is welcome to my bookstore app.

So there you can actually see that it's successfully figured out that it needs to call this function and it's returned this message from us. So now our fast API is working on AWS Lambda. I can also change it to a different path. So for example, maybe list books, I'll copy that over here. So let's say we wanted to test that we can change our event. And we'll just make our path list books, but we have to change it everywhere it appears.

I think it appears three places in total in this payload.
Okay, and then we hit save, then test again.

And now you can actually see it lists all the books that we've bundled up in our JSON folder.

So far, we're doing pretty well. We have a fast API application now wrapped up in a handler and
we've put it into a Lambda function. So we've tested it and it works. We can run this and we
don't even need to have a server to run it. And it's in the cloud.

The last thing we need to finish this project off is to actually make a public HTTP endpoint so that we can actually call this API
anywhere with HTTP connection. So from our browser, from another app, from a front end.

So let's get that working. Now this actually used to be a pretty complicated thing to do. Before we would probably have to use another AWS service called API gateway. And we'd have to configure that and make it connect to the Lambda with something called like a proxy test those interactions separately and make sure that works.

But today there's actually a new feature in Lambda that makes it really, really easy to create an HTTP endpoint right out of the box. If you go to configuration, there's a tab here called function URL. And you really don't have to do anything. You just hit create function URL. And here we can select off type none and then configure cross domain origin access. Just leave that as the star and pretty much leave everything else as default. And it's going to just give you a bunch of other information. You don't have to pay attention for now. You just hit save.

And now we are done. We already have a function URL that we can use. So let's go ahead and check that out in our browser. So I've opened up that function URL, and I'm going to zoom in. And you can see that it's public URL that responds to this. So you can actually view this from anywhere, try it on a phone or a different computer, you can actually access that here.

Some of you might be wondering, how do I get rid of this ugly API URL and have my own domain name? In that case, I'm not quite sure you might still have to go with API gateway and then hook it up with route 53 in order to get that DNS resolution. But if your goal is just to get an API that you can use internally or as part of a bigger app or service, then this API is good to go. It's public. And it's behind an HTTPS protocol right out of the box.

And we can test this further by actually typing in routes like list books. And you can see all the books that we have here in that JSON file. We can also try some of the other routes we have there, like a random book. And that one works as well.

And now our API is ready to go. But do you remember what I said before about this JSON file and this Lambda function sort of not having a persistent state? That's actually kind of important because Lambda doesn't keep its server. Like when I call this API, what happens behind the scenes is that Lambda says, Hey, we are receiving a request to run this function. Let's provision a virtual server to run this. And on that virtual server, it's going to copy all of this code that we had, including that JSON file. And then we can run it, we can read from the file, we can even write to it. But as soon as that function is finished, that environment will no longer exist. It's going to be recycled by Lambda. So anything that we do to change that will be lost. And the next time the function is run, it's going to kind of be fresh from here again.

So if you're using a Lambda function, you can't rely on something like this, saving to a local disk, even though I kind of ignored that and just used it in this project.
What you actually want is to have this connect to a database. Amazon actually has a lot of databases that work really well with Lambda, but you can also use it with anything you're familiar with like Postgres or SQL or anything like that. So you're going to need to have some other separate mechanism to store your data. And you can't really rely on the local drive to do that.

And that's pretty much it on how to deploy a fast API application to AWS Lambda. I hope you found this tutorial useful. And if you have any questions or comments, please let me know in the comments below. If you need help at any point, then check in my video description for links and project source code. Anyways, I hope you found this useful and thank you for watching.

 

 

반응형
LIST
Comments