AWS EKS에 FastAPI 프로젝트 배포하기

AWS EKS에 FastAPI 프로젝트 배포하기

AWS EKS에 프로젝트를 배포하려면 Docker 이미지를 만들어야 한다.

이를 위해 Dockerfile을 작성하고, Docker 이미지를 빌드 및 푸시한 후, Kubernetes 매니페스트 파일을 사용해 EKS에 배포하는 과정을 따르게 된다.

단계1 : Dockerfile 작성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 베이스 이미지로 Python 3.9 사용
FROM python:3.9-slim

# 작업 디렉토리 설정
WORKDIR /app

# 시스템 패키지 업데이트 및 필수 패키지 설치
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
&& rm -rf /var/lib/apt/lists/*

# Poetry 설치
RUN pip install poetry

# 로컬 패키지 설치 (project-name_beta_~.whl 위치를 /app/library로 복사)
COPY ../aipin_library/aipin_beta_~.whl /app/library/
RUN poetry add /app/library/aipin_beta_~.whl

# 프로젝트 파일 복사
COPY . .

# 스크립트 실행 권한 부여
RUN chmod +x start.sh

# 컨테이너 시작 시 실행할 명령어
CMD ["./start.sh"]

단계 2: Docker 이미지 빌드

위의 Dockerfile을 프로젝트 루트 디렉토리에 저장한 후, Docker 이미지를 빌드합니다. 터미널에서 다음 명령어를 실행한다.

1
docker build -t my-project:latest .

하지만 에러가 난다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
% docker build -t aipin-orchestrator:latest .
[+] Building 1.9s (9/12)
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 765B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/python:3.9-slim 1.8s
=> CANCELED [1/8] FROM docker.io/library/python:3.9-slim@sha256:451832461e0c1587078511b0a6ad35c3c0a0106 0.0s
=> => resolve docker.io/library/python:3.9-slim@sha256:451832461e0c1587078511b0a6ad35c3c0a010656b660f4f 0.0s
=> => sha256:ac14bdcdeeab6f08dc915a5c5971f998797127c47e2e860ace34090b3886746e 1.94kB / 1.94kB 0.0s
=> => sha256:b4045d7da52ebacb256e6843ae8b6eaedca3fa0486f343d4916e52e8e7320cab 6.88kB / 6.88kB 0.0s
=> => sha256:451832461e0c1587078511b0a6ad35c3c0a010656b660f4f26ebfac0e723f7bf 10.41kB / 10.41kB 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 1.59kB 0.0s
=> CACHED [2/8] WORKDIR /app 0.0s
=> CACHED [3/8] RUN apt-get update && apt-get install -y --no-install-recommends build-essential 0.0s
=> CACHED [4/8] RUN pip install poetry 0.0s
=> ERROR [5/8] COPY ../aipin_library/aipin_beta_2024-0.1.25-py3-none-any.whl /app/library/ 0.0s
------
> [5/8] COPY ../aipin_library/aipin_beta_2024-0.1.25-py3-none-any.whl /app/library/:
------
failed to compute cache key: "/aipin_library/aipin_beta_2024-0.1.25-py3-none-any.whl" not found: not found

이 상황에서 Docker가 컨텍스트 외부 파일을 찾지 못하는 문제는 Docker의 기본 동작과 관련이 있다.

Docker는 빌드 컨텍스트 외부에 있는 파일을 복사할 수 없다.

이를 해결하기 위해 두 가지 접근 방식을 사용할 수 있다

  1. Docker 빌드 컨텍스트를 변경하여 상위 디렉토리를 포함
  2. 빌드 컨텍스트 내에 필요한 파일을 복사

필자는 두 번째 방법을 사용하여 Docker 빌드가 성공하도록 한다.

하지만 이번에는 아래와 같은 에러가 난다.

1
2
 > [4/8] RUN pip install poetry:
#7 1.579 WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1133)'))': /simple/poetry/

이 문제는 SSL 인증서 문제로 인해 pip이 패키지를 설치하지 못하는 경우이다.

Docker 이미지 안에서 SSL 인증서를 제대로 인식하지 못하는 경우가 종종 있다.

PIP 환경변수 설정

인증서 검사를 비활성화하도록 환경 변수를 설정할 수 있다. 이는 보안상 좋은 방법은 아니지만, 일시적인 해결책이 될 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 베이스 이미지로 Python 3.9 사용
FROM python:3.9-slim

# 작업 디렉토리 설정
WORKDIR /app

# 시스템 패키지 업데이트 및 필수 패키지 설치
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*

# 인증서 문제 해결을 위한 환경 변수 설정
ENV PIP_CERT /etc/ssl/certs/ca-certificates.crt

# Poetry 설치
RUN pip install poetry --trusted-host pypi.org --trusted-host files.pythonhosted.org

# 로컬 패키지 설치 (aipin_beta_~.whl 위치를 /app/library로 복사)
COPY aipin_library/aipin_beta_2024-0.1.25-py3-none-any.whl /app/library/
RUN poetry add /app/library/aipin_beta_2024-0.1.25-py3-none-any.whl

# 프로젝트 파일 복사
COPY . .

# 스크립트 실행 권한 부여
RUN chmod +x start.sh

# 컨테이너 시작 시 실행할 명령어
CMD ["./start.sh"]

하지만 아래와 같은 에러가난다.

1
2
3
4
5
6
7
 ERROR [6/8] RUN poetry add /app/library/aipin_beta_2024-0.1.25-py3-none-any.whl                       0.6s 
------
> [6/8] RUN poetry add /app/library/aipin_beta_2024-0.1.25-py3-none-any.whl:
#10 0.507
#10 0.507 Poetry could not find a pyproject.toml file in /app or its parents
------
executor failed running [/bin/sh -c poetry add /app/library/aipin_beta_2024-0.1.25-py3-none-any.whl]: exit code:

poetry는 pyproject.toml 파일이 있는 디렉토리에서 실행되어야 한다.

Dockerfile에서 poetry를 실행하기 전에 pyproject.toml 파일이 있는 디렉토리로 이동해야 한다.

현재 Dockerfile의 구조를 보면, pyproject.toml 파일은 /app 디렉토리로 복사되기 전에 poetry add 명령이 실행되고 있는 것 같다.

이를 해결하려면 다음과 같이 수정할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 베이스 이미지로 Python 3.9 사용
FROM python:3.9-slim

# 작업 디렉토리 설정
WORKDIR /app

# 시스템 패키지 업데이트 및 필수 패키지 설치
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*

# 인증서 문제 해결을 위한 환경 변수 설정
ENV PIP_CERT /etc/ssl/certs/ca-certificates.crt

# Poetry 설치
RUN pip install poetry --trusted-host pypi.org --trusted-host files.pythonhosted.org

# 프로젝트 파일 복사 (pyproject.toml 파일 포함)
COPY . .

# 로컬 패키지 설치 (aipin_beta_~.whl 위치를 /app/library로 복사)
COPY aipin_library/aipin_beta_2024-0.1.25-py3-none-any.whl /app/library/

# Poetry를 사용하여 로컬 패키지 추가
RUN poetry add /app/library/aipin_beta_2024-0.1.25-py3-none-any.whl

# 스크립트 실행 권한 부여
RUN chmod +x start.sh

# 컨테이너 시작 시 실행할 명령어
CMD ["./start.sh"]

이렇게 바꿔서 실행하면…

이번엔 이런 에러가 나타난다.

1
2
3
4
5
6
7
8
9
10
 ERROR [7/8] RUN poetry add /app/library/aipin_beta_2024-0.1.25-py3-none-any.whl                       0.7s
------
> [7/8] RUN poetry add /app/library/aipin_beta_2024-0.1.25-py3-none-any.whl:
#11 0.623 Path /aipin_library/aipin_beta_2024-0.1.25-py3-none-any.whl for aipin-beta-2024 does not exist
#11 0.644 The currently activated Python version 3.9.19 is not supported by the project (^3.10).
#11 0.644 Trying to find and use a compatible version.
#11 0.677
#11 0.677 Poetry was unable to find a compatible version. If you have one, you can explicitly use it via the "env use" command.
------
executor failed running [/bin/sh -c poetry add /app/library/aipin_beta_2024-0.1.25-py3-none-any.whl]: exit code: 1

이 에러는 두 가지 문제를 나타낸다:

  1. pyproject.toml 파일에서 Python 버전이 ^3.10로 설정되어 있고, 현재 Docker 이미지에서 사용 중인 Python 버전은 3.9.19이다.
  2. Poetry가 해당 .whl 파일을 찾지 못하고 있다.

이 문제들을 해결하기 위해 다음과 같이 진행한다

  1. Python 버전 변경: Dockerfile에서 Python 3.10 이미지를 사용하도록 변경한다.
  2. Poetry 환경 설정: Poetry가 Python 버전을 강제로 사용하도록 설정합니다.
  3. 파일 경로 문제 해결: COPY 명령어의 경로를 올바르게 설정합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 베이스 이미지로 Python 3.10 사용
FROM python:3.10-slim

# 작업 디렉토리 설정
WORKDIR /app

# 시스템 패키지 업데이트 및 필수 패키지 설치
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*

# 인증서 문제 해결을 위한 환경 변수 설정
ENV PIP_CERT /etc/ssl/certs/ca-certificates.crt

# Poetry 설치
RUN pip install poetry --trusted-host pypi.org --trusted-host files.pythonhosted.org

# 프로젝트 파일 복사 (pyproject.toml 파일 포함)
COPY . .

# 로컬 패키지 설치 (aipin_beta_~.whl 위치를 /app/library로 복사)
COPY aipin_library/aipin_beta_2024-0.1.25-py3-none-any.whl /app/library/

# Poetry 환경 설정: Python 3.10 사용 강제
RUN poetry env use python3.10

# Poetry를 사용하여 로컬 패키지 추가
RUN poetry add /app/library/aipin_beta_2024-0.1.25-py3-none-any.whl

# 스크립트 실행 권한 부여
RUN chmod +x start.sh

# 컨테이너 시작 시 실행할 명령어
CMD ["./start.sh"]

이렇게 수정하여 이미지를 빌드하였고, 이미지가 잘 만들어졌다.

ECR애 Docker 이미지 푸시

단계1:AWS CLI 설정

먼저 AWS CLI가 설정되어 있어야 한다. 설정되지 않았다면, 다음 명령을 사용하여 AWS CLI를 설정한다.

단계2:ECR 리포지토리 생성

단계3: 도커 로그인

ECR에 로그인해야 한다. 다음 명령을 사용하여 로그인힌다.

1
2
3
% aws configure
% aws ecr get-login-password --region <your-region> | docker login --username AWS --password-stdin <your-account-id>.dkr.ecr.<your-region>.amazonaws.com
Login Succeeded

AWS 자격 증명 파일(~/.aws/credentials)에 아래 것들이 있어야함

1
2
3
aws_access_key_id=...
aws_secret_access_key=...
aws_session_token=...

단계4: Docker 이미지 푸시

1
2
3
4
5
# Docker 이미지 태그
docker tag my-project:latest <your-dockerhub-username>/my-project:latest

# Docker 이미지 푸시
docker push <your-dockerhub-username>/my-project:latest

Cloud9 구성하기

1
2
3
4
$ curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" --output eksctl.tar.gz
$ curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.22.6/bin/linux/amd64/kubectl
$ curl -LO https://github.com/derailed/k9s/releases/download/v0.26.7/k9s_Linux_x86_64.tar.gz
$ curl -sSL -o ~/bin/argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64

위 패키지들 S3에 업로드 후 Cloud9 으로 옮기기

1
2
$ aws s3 cp s3://aipin-bucket/eksctl_Linux_amd64.tar.gz .
... 나머지도 비슷하게 옮기기
1
2
3
4
5
6
7
8
9
10
11
$ tar -zxvf eksctl_Linux_amd64.tar.gz
$ sudo chmod +x eksctl
$ sudo mv eksctl /usr/local/bin/
$ tar -zxvf k9s_Linux_x86_64.tar.gz
$ sudo chmod +x k9s
$ sudo mv k9s /usr/local/bin/
$ chmod +x kubectl
$ sudo mv kubectl /usr/local/bin/kubectl
$ aws eks update-kubeconfig --name [클러스터 명 예 : eks-prod-ct01-tap-01] --region [region명 예 : ap-northeast-2]
$ sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd
$ rm argocd-linux-amd64

Cloud9 -> EKS 접근 시 Token invalid 에러

1
2
$ aws eks update-kubeconfig --region [region명 예 : ap-northeast-2] --name [클러스터 명 예 : eks-prod-ct01-tap-01]
An error occurred (UnrecognizedClientException) when calling the DescribeCluster operation: The security token included in the request is invalid
  • 해결책
    Cloud9 우측 최상단의 톱니바퀴 클릭 > AWS Settings > Credential 부분을 X로 변경 > 터미널 종료 후 다시 시도

namespace 생성

1
2
$ kubectl create ns aipin
namespace/aipin created

Kubernetes 매니페스트 파일 작성

이제 EKS에 배포하기 위한 Kubernetes 매니페스트 파일을 작성한다. deployment.yaml과 service.yaml 파일을 준비한다.

AWS의 Elastic Container Registry에서 이미지 탭에 들어가 배포할 이미지 목록 리스트를 선택 후 URL 복사를 눌러 이미지 태그를 복사한다.

ex) 058264433760.dkr.ecr.ap-northeast-2.amazonaws.com/aipin-orchestrator:latest

Cloud9로 돌아가서 생성한 유저폴더로 이동하여 Deployment.yaml과 Service.yaml 파일을 생성한다.

nano 명령어를 이용하여 deployment.yaml 파일을 생성한다.

1
vim aipin-orchestrator.deployment.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: apps/v1
kind: Deployment
metadata:
name: aipin
labels:
app: aipin-orchestrator
namespace: aipin
spec:
replicas: 3
selector:
matchLabels:
app: aipin-orchestrator
template:
metadata:
labels:
app: aipin-orchestrator
spec:
containers:
- image: 058264433760.dkr.ecr.ap-northeast-2.amazonaws.com/aipin-orchestrator:latest
imagePullPolicy: Always
name: aipin-orchestrator
ports:
- containerPort: 8080
protocol: TCP

동일하게 service.yaml 파일을 생성한다.

1
$ vim aipin-service.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: v1
kind: Service
metadata:
name: aipin-orchestrator
annotations:
alb.ingress.kubernetes.io/healthcheck-path: "/healthy"
namespace: orchestrator
spec:
selector:
app: aipin-orchestrator
type: NodePort
ports:
- port: 80
protocol: TCP
targetPort: 8080

파일 생성 후 apply 명령어를 이용해 pod를 생성하여 등록 및 배포를 진행한다.

1
2
3
4
$ kubectl apply -f aipin-orchestrator.deployment.yaml 
deployment.apps/aipin created
$ kubectl apply -f aipin-orchestrator.service.yaml
service/aipin-orchestrator created

생성 후 이전에 만들어놓은 네임스페이스를 이용해 파드들을 조회해보겠다.

1
kubectl get all -n aipin

배포 시 libpq 에러

kubectl apply로 배포 시 아래와 같은 에러가 난다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Installing dependencies from lock file

No dependencies to install or update

Installing the current project: orchestrator (0.1.0)
Traceback (most recent call last):
File "/app/src/main.py", line 3, in <module>
import controller
File "/app/src/controller.py", line 2, in <module>
from orchestrator import orchestrator
File "/app/src/orchestrator.py", line 1, in <module>
from aipin.Plugin.plugin_manager import *
File "/root/.cache/pypoetry/virtualenvs/orchestrator-9TtSrW0h-py3.10/lib/python3.10/site-packages/aipin/__init__.py", line 1, in <module>
from .orchestrator import Orchestrator
File "/root/.cache/pypoetry/virtualenvs/orchestrator-9TtSrW0h-py3.10/lib/python3.10/site-packages/aipin/orchestrator.py", line 1, in <module>
from aipin.Plugin import *
File "/root/.cache/pypoetry/virtualenvs/orchestrator-9TtSrW0h-py3.10/lib/python3.10/site-packages/aipin/Plugin/__init__.py", line 2, in <module>
from .plugin_manager import PluginManager
File "/root/.cache/pypoetry/virtualenvs/orchestrator-9TtSrW0h-py3.10/lib/python3.10/site-packages/aipin/Plugin/plugin_manager.py", line 3, in <module>
from aipin.Plugin.plugin import *
File "/root/.cache/pypoetry/virtualenvs/orchestrator-9TtSrW0h-py3.10/lib/python3.10/site-packages/aipin/Plugin/plugin.py", line 5, in <module>
from aipin.data import ChatHistory, ChatRequest
File "/root/.cache/pypoetry/virtualenvs/orchestrator-9TtSrW0h-py3.10/lib/python3.10/site-packages/aipin/data/__init__.py", line 3, in <module>
from .vector_retriever import PGVectorRetriever, PGVectorConfig
File "/root/.cache/pypoetry/virtualenvs/orchestrator-9TtSrW0h-py3.10/lib/python3.10/site-packages/aipin/data/vector_retriever.py", line 2, in <module>
from langchain_postgres import PGVector
File "/root/.cache/pypoetry/virtualenvs/orchestrator-9TtSrW0h-py3.10/lib/python3.10/site-packages/langchain_postgres/__init__.py", line 3, in <module>
from langchain_postgres.chat_message_histories import PostgresChatMessageHistory
File "/root/.cache/pypoetry/virtualenvs/orchestrator-9TtSrW0h-py3.10/lib/python3.10/site-packages/langchain_postgres/chat_message_histories.py", line 13, in <module>
import psycopg
File "/root/.cache/pypoetry/virtualenvs/orchestrator-9TtSrW0h-py3.10/lib/python3.10/site-packages/psycopg/__init__.py", line 9, in <module>
from . import pq # noqa: F401 import early to stabilize side effects
File "/root/.cache/pypoetry/virtualenvs/orchestrator-9TtSrW0h-py3.10/lib/python3.10/site-packages/psycopg/pq/__init__.py", line 118, in <module>
import_from_libpq()
File "/root/.cache/pypoetry/virtualenvs/orchestrator-9TtSrW0h-py3.10/lib/python3.10/site-packages/psycopg/pq/__init__.py", line 110, in import_from_libpq
raise ImportError(
ImportError: no pq wrapper available.
Attempts made:
- couldn't import psycopg 'c' implementation: No module named 'psycopg_c'
- couldn't import psycopg 'binary' implementation: No module named 'psycopg_binary'
- couldn't import psycopg 'python' implementation: libpq library not found

로그에 나타난 에러 메시지를 분석해 보면, 문제는 psycopg 패키지가 필요한 libpq 라이브러리를 찾을 수 없기 때문에 발생하는 것으로 보인다.
이는 PostgreSQL과 상호작용하는 Python 라이브러리인 psycopg가 제대로 설치되지 않았거나, 필요한 시스템 종속성이 누락된 경우에 발생한다.

해결법

기본 이미지에 libpq 설치

libpq 라이브러리가 누락된 경우, 이를 설치해 주어야 합니다. Dockerfile에 해당 라이브러리를 설치하는 명령을 추가한다.

1

포트포워딩 진행

참고
https://greenhead.blog/blog/kubernetes/2024-04-27/
https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/setting-up.html
https://velog.io/@judemin/EKS-CICD-%ED%8C%8C%EC%9D%B4%ED%94%84%EB%9D%BC%EC%9D%B8-%EA%B5%AC%EC%B6%95
https://devnoong.tistory.com/entry/MiniKube-%EC%8B%A4%EC%8A%B5-Cloud9-ECR-%EC%97%85%EB%A1%9C%EB%93%9C-%EC%88%98%ED%96%89%ED%95%98%EA%B8%B0#article-4--3--deployment-yaml--service-yaml-%ED%8C%8C%EC%9D%BC-%EC%83%9D%EC%84%B1-%EB%B0%8F-%EB%B0%B0%ED%8F%AC-(%EC%83%88-%EC%9C%A0%EC%A0%80-%EA%B6%8C%ED%95%9C%EC%9C%BC%EB%A1%9C-%EC%A7%84%ED%96%89)

Author

hamin

Posted on

2024-07-03

Updated on

2024-08-08

Licensed under

You need to set install_url to use ShareThis. Please set it in _config.yml.
You forgot to set the business or currency_code for Paypal. Please set it in _config.yml.

Comments

You forgot to set the shortname for Disqus. Please set it in _config.yml.
You need to set client_id and slot_id to show this AD unit. Please set it in _config.yml.