๐Ÿš—ย flask-migrate docker๋กœ ์ž๋™ํ™”ํ•˜๊ธฐ

์ง„ยท2022๋…„ 1์›” 10์ผ
0

์„œ๋ฒ„

๋ชฉ๋ก ๋ณด๊ธฐ
5/5

What is data migration?

migration์ด๋ž€, DB ์—”ํ‹ฐํ‹ฐ ์ฝ”๋“œ์˜ ๋ณ€ํ™”๋ฅผ ์ž๋™์œผ๋กœ ๊ฐ์ง€ํ•˜๊ณ  ์‹ค์ œ DB์— ๋ฐ˜์˜ํ•ด ์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

์ฐธ๊ณ : Python Flask Docker Migrations

ํ˜„์žฌ: ๊ธฐ์กด ์žˆ๋˜ ํ…Œ์ด๋ธ”์—์„œ ์ปฌ๋Ÿผ ๋ณ€๊ฒฝํ•œ ๊ฒŒ ๋ฐ˜์˜๋˜์ง€ ์•Š์Œ.

ํ˜„์žฌ๋Š” docker๋ฅผ ์žฌ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜ ๋นŒ๋“œ๋ฅผ ๋‹ค์‹œ ํ•ด๋„ ์ปฌ๋Ÿผ ๋ณ€๊ฒฝํ•œ ๊ฒŒ ๋ฐ˜์˜๋˜์ง€ ์•Š์Œ

[์ด์œ  ํ›„๋ณด]

  1. ์ฝ”๋“œ ์ˆ˜์ •ํ•˜๋Š” ๊ฒŒ ์‹ค์‹œ๊ฐ„ ๋ฐ˜์˜์ด ์•ˆ ๋จ โ‡’ ๋ฐ˜์˜ ์ž˜ ๋จ

  2. flask ์‹คํ–‰ํ•˜๋Š” ๋ช…๋ น์–ด๊ฐ€ app์—์„œ create_app์„ ์•ˆ ๊ฑฐ์น˜๊ณ  ๊ทธ๋ƒฅ ์กด์žฌํ–ˆ๋˜ app์„ ๊ทธ๋Œ€๋กœ ๋ถˆ๋Ÿฌ์˜จ๋‹ค?

    โ‡’ app.logger.info ์ฐ์–ด๋ณด๋‹ˆ๊นŒ ์ œ์ผ ๋จผ์ € ์‹คํ–‰ํ•จ.

  3. else: db.init_app()์ด๋ผ๋Š” ๊ฒŒ ๊ทธ๋ƒฅ DB์— ํ•ด๋‹นํ•˜๋Š” ํ…Œ์ด๋ธ”์ด ์กด์žฌํ•˜๋Š” ์ง€๋งŒ ๋ณด๊ณ 
    DB์— ์žˆ์œผ๋ฉด: ๋”ฑํžˆ ๋ฐ”๊พธ์ง€ ์•Š๋Š” ๊ฑฐ์ž„
    DB์— ์—†์œผ๋ฉด: ์ƒˆ๋กœ ํ…Œ์ด๋ธ” ๋งŒ๋“ค์–ด์คŒ

    โ‡’ ์ •๋‹ต!

    DB์— ์žˆ์œผ๋ฉด ์•„์˜ˆ ์•ˆ ๋ฐ”๊พธ๊ณ , DB์— ์—†์œผ๋ฉด ์ƒˆ๋กœ ํ…Œ์ด๋ธ”์„ ์•„์˜ˆ ๋งŒ๋“ค์–ด์คŒ.

    ์ฆ‰, ์ปฌ๋Ÿผ ๋ณ€๊ฒฝ์„ ์ „ํ˜€ ๊ฐ์ง€ํ•˜์ง€ ๋ชปํ•จ.

    ๋งŒ์•ฝ ์ฝ”๋“œ ์ƒ์— ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์žˆ๋‹ค๊ฐ€ ์—†์–ด์กŒ์–ด๋„ ๋”ฑํžˆ ์‚ญ์ œํ•˜์ง€ ์•Š์Œ.

ํ•ด๊ฒฐ: flask-migrate๋กœ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ , ๋” ๋‚˜์•„๊ฐ€ ๋„์ปค๋กœ ์ž๋™ํ™”ํ•˜์ž.

์ผ๋‹จ flask-migrate ๋ถ€ํ„ฐ ์ ์šฉํ•ด ๋ณด์ž

[init.py]

from flask import Flask
from flask_migrate import Migrate
from .models import db
from . import config

def create_app():
    flask_app = Flask(__name__)
    flask_app.logger.info('CREATE APP __INIT__')
    flask_app.config['SQLALCHEMY_DATABASE_URI'] = config.DATABASE_CONNECTION_URI
    flask_app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    flask_app.app_context().push()
    db.init_app(flask_app)
    migrate = Migrate(flask_app, db)
			# flask-migrate ์ ์šฉ
    db.create_all()
    return flask_app

์ดํ›„, ํ˜„์žฌ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰์‹œ์ผœ๋‘๊ณ 

  • [docker-compose.yml]
    version: "3.8"
    
    services:
        web:
            build:
                context: .
            env_file:
                - .env
            ports:
                - 5000:5000
            environment:
                - FLASK_APP=./src/app.py
            volumes:
                - ./:/app
        postgres:
            container_name: postgres
            image: postgres:latest
            ports:
                - 5432:5432
            environment:
                - POSTGRES_DB=${PG_DB}
                - POSTGRES_USER=${PG_USER}
                - POSTGRES_PASSWORD=${PG_PASSWORD}
            volumes:
                - postgres:/var/lib/postgres
        pgadmin:
            container_name: pgadmin
            image: dpage/pgadmin4
            ports:
                - 8088:80
            environment:
                - PGADMIN_DEFAULT_EMAIL=${PG_ADMIN_EMAIL}
                - PGADMIN_DEFAULT_PASSWORD=${PGADMIN_DEFAULT_PASSWORD}
    
    volumes:
        postgres:

ํ„ฐ๋ฏธ๋„์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ช…๋ น์–ด๋“ค์„ ์ž‘์„ฑํ•ด ์ค€๋‹ค.

docker exec [์ปจํ…Œ์ด๋„ˆ_์•„์ด๋””] flask db init
# migration์„ ํ•ด๋‹น ์•ฑ์— ์ ์šฉํ•˜๊ฒ ๋‹ค๊ณ  ์„ ์–ธ, ์ด ๊ฒฐ๊ณผ๋กœ migrations ํด๋”๊ฐ€ ์ƒ์„ฑ๋จ.
docker exec [์ปจํ…Œ์ด๋„ˆ_์•„์ด๋””] flask db migrate
# ์ฝ”๋“œ์ƒ์˜ DB ์—”ํ‹ฐํ‹ฐ์˜ ๋ณ€ํ™”๋ฅผ ์ž๋™์ ์œผ๋กœ ๊ฐ์ง€. ์ด ๊ฒฐ๊ณผ๋กœ versions/2cd568bbbbe1_.py ๊ฐ™์€ ๊ฒŒ ์ƒ์„ฑ๋จ.
docker exec [์ปจํ…Œ์ด๋„ˆ_์•„์ด๋””] flask db upgrade
# migrate ๋ช…๋ น์–ด๋กœ ๊ฐ์ง€ํ•œ ์—”ํ‹ฐํ‹ฐ ๋ณ€ํ™”๋ฅผ ์‹ค์ œ DB์— ๋ฐ˜์˜

์ด์ œ ๋„์ปค๋กœ ์ž๋™ํ™”๋ฅผ ํ•ด ๋ณด์ž.

์•„๋ž˜๋Š” ๋ผ์ดํ”„์‚ฌ์ดํด์„ ์ ์–ด ๋ณธ ๊ฒƒ์ด๋‹ค.

DB ์—”ํ‹ฐํ‹ฐ์— ๊ด€ํ•œ ์ฝ”๋“œ ๋ณ€๊ฒฝ
โ†’ ๋„์ปค ์ปจํ…Œ์ด๋„ˆ ์žฌ์‹คํ–‰ํ•˜๋ฉฐ ๋™์‹œ์— ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ˆ˜ํ–‰
โ†’ ์‹ค์ œ DB์— ๋ฐ˜์˜
โ†’ ์„œ๋ฒ„ ์‹คํ–‰

์ด๋•Œ DockerFile์— CMD ๋ช…๋ น์–ด์— .sh ํŒŒ์ผ ์‹คํ–‰์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

๊ธฐ์กด DockerFile

# syntax=docker/dockerfile:1

FROM python:3.8-slim-buster

WORKDIR /app

COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt

COPY . .

CMD ["python3", "-m", "flask", "run", "--host=0.0.0.0"]

์ˆ˜์ •ํ•œ DockerFile

# syntax=docker/dockerfile:1

FROM python:3.8-slim-buster

WORKDIR /app

COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt

COPY . .

CMD [ "/bin/bash", "/app/docker-entrypoint.sh"]
# CMD ["python3", "-m", "flask", "run", "--host=0.0.0.0"]
  • docker-entrypoint.sh
    #!/bin/sh
    
    flask db init
    flask db migrate
    flask db upgrade
    python3 -m flask run --host=0.0.0.0

๊ทธ๋Ÿฌ๋ฉด ์ด์™€ ๊ฐ™์ด ํ„ฐ๋ฏธ๋„์ด ์•„์ฃผ ์ž˜ ๋‚˜์˜จ๋‹ค.

๊ธฐ์กด์— ์ ์—ˆ๋˜ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  ๋„์ปค ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์žฌ์‹คํ–‰ํ•ด๋„ ์ž˜ ๋œ๋‹ค.

flask db init์ด ์ด๋ฏธ ํ•œ๋ฒˆ ๋ถˆ๋ ธ๊ธฐ ๋•Œ๋ฌธ์— ์—๋Ÿฌ ๋ฉ”์‹œ์ง€(Error: Directory migrations already exists and is not empty)๋ฅผ ์†ก์ถœํ•˜์ง€๋งŒ, ์ด๊ฑธ๋กœ ์ธํ•ด ์ € sh ํŒŒ์ผ์„ ์‹คํ–‰ํ•˜๋‹ค๊ฐ€ ์ค‘๋‹จํ•˜์ง€ ์•Š์œผ๋‹ˆ ์ผ๋‹จ ์ €๋ ‡๊ฒŒ ๋‘๊ณ  ์“ฐ์ž.

์ฐธ๊ณ 

ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ๋‹ค. ์•„์ง ํ† ์ด ํ”„๋กœ์ ํŠธ ๋‹จ๊ณ„๋ผ์„œ ์ •๋ฆฌ๊ฐ€ ์ž˜ ์•ˆ๋œ ์ƒํƒœ๋ผ๋Š” ์ .. ์ฐธ๊ณ  ๋ฐ”๋ž€๋‹ค..

โ”œโ”€โ”€ Dockerfile
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ docker-compose.dev.yml
โ”œโ”€โ”€ docker-entrypoint.sh
โ”œโ”€โ”€ migrations
โ”‚   โ”œโ”€โ”€ README
โ”‚   โ”œโ”€โ”€ alembic.ini
โ”‚   โ”œโ”€โ”€ env.py
โ”‚   โ”œโ”€โ”€ script.py.mako
โ”‚   โ””โ”€โ”€ versions
โ”‚       โ”œโ”€โ”€ 2cd568bbbbe1_.py
โ”‚       โ”œโ”€โ”€ a9bfee46c75b_.py
โ”‚       โ””โ”€โ”€ ae72eeaaa4f3_.py
โ”œโ”€โ”€ requirements.txt
โ””โ”€โ”€ src
    โ”œโ”€โ”€ __init__.py
    โ”œโ”€โ”€ app.py
    โ”œโ”€โ”€ config.py
    โ”œโ”€โ”€ database.py
    โ””โ”€โ”€ models.py

7 directories, 28 files

gitignore?

migrations ํด๋” ๋„ฃ์–ด๋„ ๋˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ธ๋‹ค.

ํ•œ๊ณ„

์•„๋ฌด๋ž˜๋„ docker-entrypoint.sh๋กœ ์•„์˜ˆ ๋„์ปค ์‹คํ–‰๋•Œ flask migrate์™€ python3 flask run ๋ช…๋ น์–ด๋ฅผ ๊ฐ™์ด ์ผ๊ณ , ๊ฐ™์€ ์ปจํ…Œ์ด๋„ˆ์—์„œ ์‹คํ–‰ํ•˜๋‹ค ๋ณด๋‹ˆ ๋งค๋ฒˆ ์—”ํ‹ฐํ‹ฐ ์†์„ฑ์„ ๋ณ€๊ฒฝํ–ˆ์„ ๋•Œ ์„œ๋น„์Šค ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๊ป๋‹ค๊ฐ€ ์ผœ์•ผ ํ•ด์„œ ๋ถˆํŽธํ•˜๋‹ค.

์ฃผ๋กœ ํ˜„์ง์—์„œ๋Š” flask migrate๋ฅผ ๋‹ค๋ฅธ ๋ณ„๊ฐœ์˜ ์ปจํ…Œ์ด๋„ˆ๋กœ ๋ถ„๋ฆฌํ•ด์„œ ์‚ฌ์šฉํ•˜๋‚˜? ๊ทธ๋ ‡๊ฒŒ ํ•ด์„œ ์–ป๋Š” ์ ์ด ๋ฌด์—‡์ผ๊นŒ?

...์ผ๋‹จ ์ด๋งŒ ํ•˜๊ณ .. ๋‚ด์ผ ๊ธฐ๋ง์ธ ๊ณ„์ ˆ์„ ์กฐ๊ธˆ์ด๋ผ๋„ ๊ณต๋ถ€ํ•ด์•ผ๊ฒ ๋‹ค...

profile
์ด๊ฒƒ์ €๊ฒƒ ๊ฐœ๋ฐœํ•˜๋Š” ๊ฒƒ ์ข‹์•„ํ•˜์ง€๋งŒ ์„œ๋ฒ„ ๊ฐœ๋ฐœ์ด ์ œ์ผ ์ข‹๋”๋ผ๊ตฌ์š”..

0๊ฐœ์˜ ๋Œ“๊ธ€