사실 제목은 거창하지만
나의 이틀간의 삽질 기록이다.
나는 이번에 처음 서버를 배포해보게 되었다.
FastAPI & MySQL을 사용하였고
이 책을 보면서 진행을 하게 되었다.
파이썬 FastAPI 개발 입문 : 네이버 도서
네이버 도서 상세정보를 제공합니다.
search.shopping.naver.com
이 책의 핵심은 간단한 crud시스템을 만드는데
1. docker compose (2개의 컨테이너를 하나의 시스템으로 묶어서 함께 관리할 수 있게 하는 것..?)
2. poetry 사용 (requirements.txt 를 일반적으로 소개하는 것과는 좀 다르긴했음)
그리고 aws와 gcp였나? 배포하는 과정도 끝쪽에 있긴한데..
여기에서는 RDS, App Runner, Continaer registry?? (도커 컨테이너 올려놓는곳..?) 이렇게 3개나 사용한다.
나는 비용적인 문제와 함께 이번 배포는 간단한 CMS와 POC용도의 목적이 강했기 때문에
고정비용으로 나가는 LightSail Instance를 사용하기로 마음먹었다.
후에 알고보니 라이트세일에도 컨테이너 전용이 있고 데이터베이스도 따로 있더라..?
그리고 이왕 도커를 사용하는거 도커에는 git처럼 이미지를 빌드하여 push pull을 하여 쉽게 클라우드에서 로컬에서 빌드한 것을 받아볼 수 있는데 이 부분을 부인에게 듣게되어 (부인은 시니어 백앤드 개발자 (node.js)) 사용해보기로 하였다.
일단 개발하는 부분은 책만 따라가고 쳇지피티와 코파일럿을 사용하니 무난하게 CMS까지 다 연결을 로컬에서 하였다.
문제는 이제 클라우드에서 빌드를 할 적이었다...
일단 docker compose 빌드의 중요한 파일들은 다음과 같다.
도커파일
Dockerfile -> 실질적으로 처음 도커 가상환경 세팅을 지시하는 부분이다.
로컬에서는 다음과 같았다.
FROM python:3.11-buster
ENV PYTHONUNBUFFERED=1
WORKDIR /src
RUN pip install "poetry==1.6.1"
COPY pyproject.toml* poetry.lock* ./
RUN poetry config virtualenvs.in-project true
RUN if [ -f pyproject.toml ]; then poetry install --no-root; fi
ENTRYPOINT ["poetry", "run", "uvicorn", "api.main:app", "--host", "0.0.0.0", "--reload"]
이 부분은 클라우드에 올리기 위해서는 클라우드용 도커파일을 따로 만들게 되었다 (책에서도 그리 하긴 하였음)
Dockerfile.cloud
FROM python:3.11-buster
ENV PYTHONUNBUFFERED=1
WORKDIR /src
RUN pip install poetry
COPY pyproject.toml* poetry.lock* ./
RUN poetry config virtualenvs.in-project true
RUN poetry install --no-root
COPY api api/
COPY entrypoint.sh ./
# entrypoint 스크립트에 실행 권한 부여
RUN chmod +x /src/entrypoint.sh
ENTRYPOINT ["bash", "/src/entrypoint.sh"]
달라진 점이라고 한다면...
빌드를 할적에 api 아래 파일들을 COPY하고
위에서는 ENTRYPOINT 부분에서 fastapi를 실행하는 부분을 적었다면
여기서는 그 해당하는 기능을 가진 쉘스크립트를 실행시킨다는 점이다.
entrypoint.sh
#!/bin/bash
set -e
echo "Waiting for database to be ready..."
sleep 20
echo "Running database migrations..."
poetry run python -m api.migrate_db
echo "Starting FastAPI application..."
exec poetry run uvicorn api.main:app --host 0.0.0.0 --port 8000
사실 여기서 가장 많은 오류와 시간을 잡아먹었는데...
내가 가진 문제는 총 3개정도 였다.
1. echo "Running database migrations..."까지를 가지 않는다
맨위의 set -e는 만약 에러가 난다면 밑에것들을 실행하지않고 바로 종료해버린다는 뜻인데...
디버깅을 해보니 docker-compose.yaml 에서 처음에는
로컬로 하니 mysql을 비밀번호 없이 진행했는데 비밀번호를 넣고나니
cryptography module이 없다는 것이었다...
도커파일에서 설치를 담당하게 하였으니 결국에는 Poetry 패키지를 관리하는 pyproject.toml까지 손을 봐야했는데
사실상 그냥 싹 다 지우고
이걸로 걍 설치해주는게 제일 이었달까
2. 어찌저찌 이제 mysql 접속은 되었다.
참고로 보여주자면
docker-compose.yaml
services:
interior-app:
build:
context: .
dockerfile: Dockerfile.cloud
volumes:
- .dockervenv:/src/.venv
- .:/src
ports:
- 8000:8000
environment:
DB_USER: root
DB_PASSWORD: password
DB_HOST: db
DB_PORT: 3306
DB_NAME: demo
db:
image: mysql:8.0
restart: always
platform: linux/x86_64
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: demo
MYSQL_USER: user
MYSQL_PASSWORD: password
MYSQL_ROOT_HOST: '%'
volumes:
- mysql_data:/var/lib/mysql
ports:
- 33306:3306
volumes:
mysql_data:
migrate_db.py
from sqlalchemy import create_engine
import os
from api.models.item import Base
DB_USER = os.getenv("DB_USER", "root") # 기본값 root
DB_PASSWORD = os.getenv("DB_PASSWORD", "password") # 기본값은 빈 문자열
DB_HOST = os.getenv("DB_HOST", "db") # 기본값 db (Docker Compose의 서비스 이름)
DB_PORT = os.getenv("DB_PORT", "3306") # 기본값 3306
DB_NAME = os.getenv("DB_NAME", "demo") # 기본값 demo
#docker db 에다가 넣는 테이블 생성하는 스크립트
#docker compose exec interior-app poetry run python -m api.migrate_db
#DB_URL = "mysql+pymysql://root@db:3306/demo?charset=utf8"
DB_URL = f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}?charset=utf8"
engine = create_engine(DB_URL, echo=True)
def reset_database():
Base.metadata.drop_all(bind=engine)
Base.metadata.create_all(bind=engine)
if __name__ == "__main__":
reset_database()
여기서의 문제는 migrate_db.py가 entrypoint.sh로 부터 실행은 되는데
ModuleNotFoundError: No module named 'sqlalchemy'
이런 이상한 에러가 나는거임. 난 분명 poetry로 설치를 했을텐데...?
정말 많이 해멨다 여기서; 쳇지피티와 코파일럿은 이상한 얘기만 하길래 구글링을 좀 했는데
정답은.. 이 라이브러리들을 관리하는 .dockervenv와 .venv를 싹지우고 다시 만드는것...!!!
정말 이 두개에서 이틀을 해멨는데 (사실 처음엔 scp 명령어로 파일들 옮기다가 화나서 docker hub로 바꾸었기 때문에 그 부분은 생략한다....)
3. 어디서 빌드하느냐?
이 부분은 좀 생각치도 못했던 부분이긴한데 부인이 개발환경 이야기를 했어서 조금 캐치한 부분이다.
나는 맥과 윈도우를 오가며 개발을 한다.
여기서 중요한점은 맥은 arm 기반이고 윈도우는 데스크탑을 쓰기에 amd64 기반이다.
그런데 docker build를 하게 되면 해당 cpu기반으로 빌드를 하나본데..
이 빌드된 것을 클라우드에 올릴 때가 문제이다.
맥에서 (arm64) 도커 빌드를 하고 lightsail에서 docker pull을 받으니
no matching manifest for linux/amd64 in the manifest list entries
이런 에러가 뜬다..?
LightSail은 amd 씨피유였던것이다..
그래서 맥에서 빌드를 할 때는 그냥 docker build ~~~를 하던 것을 좀 수정해야했다.
docker buildx create --use
docker buildx ls
docker buildx build --platform linux/arm64,linux/amd64 -f 도커파일명 도커허브닉네임/이미지이름:latest --push .
그러고나니 이제 풀을 하고 compose up -d 를 하고나서 보니 아주 잘된다!
내 생에 첫클라우드 배포라 너무 기쁘다..
어쩌면 어렵게 배포한거라 더 그런걸지도...?
CMS 호스팅도 해야하는데, 너무 지쳤으므로 내일 하는거로...
'프로그래밍 > Backend' 카테고리의 다른 글
[AWS] CloudFront, S3 이미지 pdf 다운로드 캐싱에러 log (0) | 2025.02.10 |
---|---|
[FastAPI] AWS LightSail에서 DockerCompose ssl (https) 적용하기 (0) | 2025.02.05 |
[FastAPI] MySQL 한글이 깨져 보일 때 (feat: 파워쉘, cmd등) (0) | 2025.01.16 |
[FastAPI] pydantic v2 - orm_mode를 마이그레이션.. (0) | 2025.01.12 |