[Flask] Config 환경 분리하기

happypath·2022년 1월 26일
0

Flask

목록 보기
9/10

지난 10월에 진행했던 개인 프로젝트 코드들을 다시 고치고, 리팩토링 작업 중이다.
새로 배운 라이브러리들도 적용해 보고...
작업 중에 Config 환경을 분리한 코드를 기록으로 남겨보려한다.

참고한 깃허브 - https://github.com/miguelgrinberg/flasky


레거시 코드는 개발 환경(development)과 배포/운영환경(production)이 분리되어 있지 않았다. 때문에 VM에 배포할 때, .env와 config 코드 내용을 하드 코딩으로 '직접' 변경해 줘야 하는 수고스러움이 있었다.

당시만 해도 이걸 구분해야 하는 필요성조차 느끼지 못했으니까...(이런 작업을 해야 하는지 조차 몰랐다는 소리다)^^

한 번 볼꽈..?

1. 기존 레거시 Config 코드

import os

DB_KEY = os.environ.get('DB_KEY')

SQLALCHEMY_DATABASE_URI = DB_KEY
SQLALCHEMY_TRACK_MODIFICATIONS = False

끝...?ㅎ
부...부끄럽구나...ㅎㅎㅎㅎㅎ 괜찮아 이렇게 배워가는거지~


2. 변경 후 Config 코드

기본 Config 클래스를 생성해 주고, 이를 상속하는 DevelopmentConfig, ProductionConfig, HerokuConfig 클래스를 만들어 줬다.

기본 Config 클래스에는 공통적으로 사용되는 변수들을 넣어주고, 개별 환경 클래스마다 필요한 변수들을 선언해 준다.

import os

BASE_DIR = os.path.dirname(os.path.dirname(__file__))


class Config:
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    SQLALCHEMY_RECORD_QUERIES = True
    SSL_REDIRECT = False

    @staticmethod
    def init_app(app):
        pass


class DevelopmentConfig(Config):
    DEBUG = True
    SQLALCHEMY_DATABASE_URI = os.environ.get("DEV_DATABASE_URL")


class ProductionConfig(Config):
    DEBUG = False
    SQLALCHEMY_DATABASE_URI = os.environ.get("DATABASE_URL")

    @classmethod
    def init_app(cls, app):
        Config.init_app(app)


class HerokuConfig(Config):
    SSL_REDIRECT = True if os.environ.get("DYNO") else False

    @classmethod
    def init_app(cls, app):
        ProductionConfig.init_app(app)


config = {
    "development": DevelopmentConfig,
    "production": ProductionConfig,
    "heroku": HerokuConfig,
    "default": DevelopmentConfig,
}

코드 가장 끝에 위치한 config 딕셔너리는, 다른 외부 코드에서 config를 호출할 때 key로 환경을 호출할 수 있도록 만들어 준 것이다.
ex) config[config_type]

** config 파일 여러개 만들어서 분리하는 방법
점프투플라스크 - 서버·개발 환경을 위한 config 분리하기 에서는 각 환경마다 config 파일을 새로 만들어 줬는데, 나는 해당 방식이 오히려 환경 별 config가 한 눈에 들어오지 않고, 파일이 많아지는 것처럼 느껴져서 하나의 파일 안에 모든 환경을 집합시켰다.


3. App 시작점 코드 수정

나는 app 폴더 안에 __init__.py에서 플라스크가 실행 되는데,
코드를 살펴보자.

아래 코드를 설명하자면!

main 함수가 실행되면 → load_dotenv가 .env 파일을 불러오고 → create_app() 함수 실행 → Flask 객체 생성 → config 설정 → 이외 이것저것 불러오고 실행.... → create_app() 끝나면 app.run으로 실행!

def create_app():
    app = Flask(__name__)
    app.secret_key = os.environ["APP_KEY"]
    config_type = os.getenv("FLASK_ENV") if os.getenv("FLASK_ENV") else "default"
    app.config.from_object(config[config_type])
    config[config_type].init_app(app)
    db.init_app(app)
    migrate.init_app(app, db)
	
    <--------생략-------->

    return app


dotenv_path = os.path.join(os.path.dirname(__file__), ".env")
if os.path.exists(dotenv_path):
    load_dotenv(dotenv_path)

if __name__ == "__main__":
    load_dotenv(dotenv_path)
    app = create_app()
    app.run("0.0.0.0", 80)

app.config.from_object(config[config_type]) 코드가 보이시나?!

Flask Docs 에 따르면,

이와 같은 설정을 활성화하기 위해서는 단지 meth:~flask.Config.from_object:: 를 호출 하면 된다
app.config.from_object('configmodule.ProductionConfig')"

config.from_object(type:class)를 사용하면 config에서 내가 만들어 놓은 환경 클래스가 불러져 오고, 그 친구로 활성화가 된다는 것이다! (신기쓰 방기쓰)

여기서 주의할 점은, 환경 변수에 변화를 줄 때는 가상환경을 껐다가 다시 실행해야 적용이 된다! config랑 env 파일 열심히 수정하고 바로 계속 run run run 할 시에 '웨않뒈?' 물음표 찍으며 삽질할 수 있다는 사실ㅎㅎ


4. Furthermore,

사실 위의 config 코드는 아직 완벽하지 않다.
logger도 적용해 보고 싶고, heroku의 경우에는 지금 설정 중이라 코드가 모두 들어가 있지는 않지만,
누군가 프로젝트를 설정하면서 config는 어떻게 구성해야 하는겨....
방황하고 있을 때 이 글이 도움 되길 바란다.

0개의 댓글