FastAPI를 이용한 TDD 개발 - 3

2024. 3. 12. 13:25·프로그래밍 언어/파이썬

Postgres

Postgres 설정을 위해서 docker-compose.yml 파일에 새로운 서비스를 명세해야합니다. 

그리고 asyncpg 파이썬 라이브러리 설치도 해야합니다. 

 

project 디렉토리 아래 db 디렉토리를 만들고 그 안에 create.sql 파일을 생성하며 아래와 같이 명세합니다. 

CREATE DATABASE web_dev;
CREATE DATABASE web_test;

 

Dokcerfile을 같은 디렉토리에서 만들어 줍니다. 

# pull official base image
FROM postgres:16

# run create.sql on init
ADD create.sql /docker-entrypoint-initdb.d

 

DB 컨테이너의 `docker-entrypoint-initdb.d` 디렉토리에 `create.sql`파일을 넣어두면 이 파일을 실행을 통해서 초기화가 수행됩니다. 

`web-db`라는 서비스 명을 명세해줍니다. 

version: '3.8'

services:

  web:
    build: ./project
    command: uvicorn app.main:app --reload --workers 1 --host 0.0.0.0 --port 8000
    volumes:
      - ./project:/usr/src/app
    ports:
      - 8004:8000
    environment:
      - ENVIRONMENT=dev
      - TESTING=0
      - DATABASE_URL=postgres://postgres:postgres@web-db:5432/web_dev        # new
      - DATABASE_TEST_URL=postgres://postgres:postgres@web-db:5432/web_test  # new
    depends_on:   # new
      - web-db

  # new
  web-db:
    build:
      context: ./project/db
      dockerfile: Dockerfile
    expose:
      - 5432
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres

 

web-db 컨테이너가 가동되면 5432 포트를 통해서 다른 포트와 통신 할 수 있습니다. 

`entrypoint.sh`파일에서 web-db라는 컨테이너의 5432 포트를 통해서 정상적으로 PostgreSQL이 시작되었는지 확인 할 수 있습니다. 

 

#!/bin/sh

echo "Waiting for postgres..."

while ! nc -z web-db 5432; do
  sleep 0.1
done

echo "PostgreSQL started"

exec "$@"

 

app컨테이너의 Dockerfile을 아래와 같이 명세해줍니다. 

# pull official base image
FROM python:3.12.1-slim-bookworm

# set working directory
WORKDIR /usr/src/app

# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# install system dependencies
RUN apt-get update \
  && apt-get -y install netcat-traditional gcc postgresql \
  && apt-get clean

# install python dependencies
RUN pip install --upgrade pip
COPY ./requirements.txt .
RUN pip install -r requirements.txt

# add app
COPY . .

# add entrypoint.sh
COPY ./entrypoint.sh .
RUN chmod +x /usr/src/app/entrypoint.sh

# run entrypoint.sh
ENTRYPOINT ["/usr/src/app/entrypoint.sh"]

 

asyncpg 라이브러리를 requirements.txt에 추가해줍니다. 

asyncpg==0.29.0

 

config.py 모듈에서 Settings클래스의 변수로 databse_url을 추가해줍니다. 

# project/app/config.py


import logging
from functools import lru_cache

from pydantic import AnyUrl
from pydantic_settings import BaseSettings


log = logging.getLogger("uvicorn")


class Settings(BaseSettings):
    environment: str = "dev"
    testing: bool = 0
    database_url: AnyUrl = None


@lru_cache()
def get_settings() -> BaseSettings:
    log.info("Loading config settings from the environment...")
    return Settings()

 

앱, 디비 컨테이너 두개를 기동하도록 해보겠습니다. 

$ chmod +x project/entrypoint.sh
$ docker-compose up -d --build

 

web 서비스의 로그를 확인해 보겠습니다. 

$docker-compose logs web
web_1  | Waiting for postgres...
web_1  | PostgreSQL started
web_1  | INFO:     Will watch for changes in these directories: ['/usr/src/app']
web_1  | INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
web_1  | INFO:     Started reloader process [1] using statreload
web_1  | INFO:     Started server process [37]
web_1  | INFO:     Waiting for application startup.
web_1  | INFO:     Application startup complete.

 

이전 `chmod +x` 명령어를 사용하였지만 환경에 따라서 chmod 755, 777 을 사용해야 할 수 있습니다. 

 

psql을 통해서 DB에 접속 해보겠습니다. 

$ docker-compose exec web-db psql -U postgres
postgres=# \c web_dev
postgres=# \q

 

Tortoise ORM

여러 비동기 ORM중 Tortoise ORM을 사용해 보겠습니다. 

우선 requirements.txt 파일에 라이브러리와 버전을 명세합니다. 

tortoise-orm==0.20.0

 

app 디렉토리 아래 models 디렉토리를 만들고 초기화 파일인 __init__.py 파일과 tortoise.py를 만듭니다. 
그리고 TextSummary 클래스를 명세해 줍니다. 

 

 

# project/app/models/tortoise.py


from tortoise import fields, models


class TextSummary(models.Model):
    url = fields.TextField()
    summary = fields.TextField()
    created_at = fields.DatetimeField(auto_now_add=True)

    def __str__(self):
        return self.url

 

main.py 모듈에서 register_tortoise 헬퍼 메소드를 사용하여 Tortoise 구성과 해제를 하도록 하겠습니다. 

# project/app/main.py

import os

from fastapi import FastAPI, Depends
from tortoise.contrib.fastapi import register_tortoise

from app.config import get_settings, Settings


app = FastAPI()


register_tortoise(
    app,
    db_url=os.environ.get("DATABASE_URL"),
    modules={"models": ["app.models.tortoise"]},
    generate_schemas=True,
    add_exception_handlers=True,
)


@app.get("/ping")
async def pong(settings: Settings = Depends(get_settings)):
    return {
        "ping": "pong!",
        "environment": settings.environment,
        "testing": settings.testing
    }

 

sanity check하겠습니다. 

$ docker-compose up -d --build

 

textsummary 테이블이 정상적으로 생성되었는지 확인합니다. 

$ docker-compose exec web-db psql -U postgres

psql (16.1)
Type "help" for help.

postgres=# \c web_dev
You are now connected to database "web_dev" as user "postgres".

web_dev=# \dt
            List of relations
 Schema |    Name     | Type  |  Owner
--------+-------------+-------+----------
 public | textsummary | table | postgres
(1 row)

web_dev=# \q

 

지금까지 필요한 기능 개발을 위한 모듈 생성과 코드를 구성하였다면 프로젝트 트리 구조는 아래와 같습니다. 

├── .gitignore
├── docker-compose.yml
└── project
    ├── .dockerignore
    ├── Dockerfile
    ├── app
    │   ├── __init__.py
    │   ├── config.py
    │   ├── main.py
    │   └── models
    │       ├── __init__.py
    │       └── tortoise.py
    ├── db
    │   ├── Dockerfile
    │   └── create.sql
    ├── entrypoint.sh
    └── requirements.txt

 

마이그레이션

Tortoise는 Aerich을 통하여 데이터베이스 마이그레이션을 지원합니다. 

우선 Aerich이 schema관리를 하도록 하기 위해서 기존 컨테이너 볼륨을 삭제하도록 하겠습니다. 

$ docker-compose down -v

 

기존에는 서버 기동시 자동으로 스키마가 생성되도록 하였는데요. 자동으로 생성되는 것을 방지하고자 register_tortoise 헬퍼 함수를 수정하겠습니다.

 

register_tortoise(
    app,
    db_url=os.environ.get("DATABASE_URL"),
    modules={"models": ["app.models.tortoise"]},
    generate_schemas=False,  # updated
    add_exception_handlers=True,
)

 

이미지를 다시 빌드하고 컨테이너를 돌려보겠습니다. 

$ docker-compose up -d --build

 

textsummary 테이블이 생성되지 않아야 합니다. 확인해보세요. 

$ docker-compose exec web-db psql -U postgres

psql (16.1)
Type "help" for help.

postgres=# \c web_dev
You are now connected to database "web_dev" as user "postgres".

web_dev=# \dt
Did not find any relations.

web_dev=# \q

 

requirements 파일에 aerich라이브러리 버전과 이름을 명세합니다. 

aerich==0.7.2

 

컨테이너를 다시 빌드합니다. 

$ docker-compose up -d --build

 

Aerich을 사용하려면 Tortoise 설정이 필요합니다. app디렉토리 아래 db.py 파일을 작성합니다. 

# project/app/db.py


import os


TORTOISE_ORM = {
    "connections": {"default": os.environ.get("DATABASE_URL")},
    "apps": {
        "models": {
            "models": ["app.models.tortoise", "aerich.models"],
            "default_connection": "default",
        },
    },
}

 

aerich 사용이 가능합니다. 초기화 명령어를 실행합니다. 

$ docker-compose exec web aerich init -t app.db.TORTOISE_ORM

해당 명령어를 실행하면 project/pyproject.toml  파일이 생성 됩니다. 

 

[tool.aerich]
tortoise_orm = "app.db.TORTOISE_ORM"
location = "./migrations"
src_folder = "./."

 

첫 마이그레이션을 만들어 보겠습니다. 

$ docker-compose exec web aerich init-db

Success create app migrate location migrations/models
Success generate schema for app "models"

 

그렇다면 아래 마이그레이션 결과를 migrations/models에서 볼 수 있습니다. 

from tortoise import BaseDBAsyncClient


async def upgrade(db: BaseDBAsyncClient) -> str:
    return """
        CREATE TABLE IF NOT EXISTS "textsummary" (
    "id" SERIAL NOT NULL PRIMARY KEY,
    "url" TEXT NOT NULL,
    "summary" TEXT NOT NULL,
    "created_at" TIMESTAMPTZ NOT NULL  DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS "aerich" (
    "id" SERIAL NOT NULL PRIMARY KEY,
    "version" VARCHAR(255) NOT NULL,
    "app" VARCHAR(100) NOT NULL,
    "content" JSONB NOT NULL
);"""


async def downgrade(db: BaseDBAsyncClient) -> str:
    return """
        """

 

실제 psql에서 테이블이 생성 되었는지 확인 할 수 있습니다. 

$ docker-compose exec web-db psql -U postgres

psql (16.1)
Type "help" for help.

postgres=# \c web_dev
You are now connected to database "web_dev" as user "postgres".

web_dev=# \dt
            List of relations
 Schema |    Name     | Type  |  Owner
--------+-------------+-------+----------
 public | aerich      | table | postgres
 public | textsummary | table | postgres
(2 rows)

web_dev=# \q
저작자표시 (새창열림)

'프로그래밍 언어 > 파이썬' 카테고리의 다른 글

FastAPI를 이용한 TDD 개발 - 5  (0) 2024.03.14
FastAPI를 이용한 TDD 개발 - 4  (0) 2024.03.14
FastAPI를 이용한 TDD 개발 - 2  (0) 2024.03.11
FastAPI를 이용한 TDD 개발 - 1  (0) 2024.03.10
FastAPI를 이용한 TDD 개발  (0) 2024.03.10
'프로그래밍 언어/파이썬' 카테고리의 다른 글
  • FastAPI를 이용한 TDD 개발 - 5
  • FastAPI를 이용한 TDD 개발 - 4
  • FastAPI를 이용한 TDD 개발 - 2
  • FastAPI를 이용한 TDD 개발 - 1
hyeseong-dev
hyeseong-dev
안녕하세요. 백엔드 개발자 이혜성입니다.
  • hyeseong-dev
    어제 오늘 그리고 내일
    hyeseong-dev
  • 전체
    오늘
    어제
    • 분류 전체보기 (286)
      • 여러가지 (107)
        • 알고리즘 & 자료구조 (72)
        • 오류 (4)
        • 이것저것 (29)
        • 일기 (1)
      • 프레임워크 (39)
        • 자바 스프링 (39)
        • React Native (0)
      • 프로그래밍 언어 (38)
        • 파이썬 (30)
        • 자바 (3)
        • 스프링부트 (5)
      • 컴퓨터 구조와 운영체제 (3)
      • DB (17)
        • SQL (0)
        • Redis (17)
      • 클라우드 컴퓨팅 (2)
        • 도커 (2)
        • AWS (0)
      • 스케쥴 (65)
        • 세미나 (0)
        • 수료 (0)
        • 스터디 (24)
        • 시험 (41)
      • 트러블슈팅 (1)
      • 자격증 (0)
        • 정보처리기사 (0)
      • 재태크 (5)
        • 암호화폐 (5)
        • 기타 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    취업리부트
    Spring WebFlux
    #개발자포트폴리오 #개발자이력서 #개발자취업 #개발자취준 #코딩테스트 #항해99 #취리코 #취업리부트코스
    reactor
    Python
    AWS
    spring
    java
    Redis
    docker
    EC2
    항해99
    ecs
    celery
    Docker-compose
    FastAPI
    백준
    프로그래머스
    자바
    완전탐색
    DP
    RDS
    WebFlux
    그리디
    시험
    mybatis
    SAA
    파이썬
    Spring Boot
    OOP
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
hyeseong-dev
FastAPI를 이용한 TDD 개발 - 3
상단으로

티스토리툴바