docker-compose로 flask 개발환경 구성하기

가끔 개발환경을 구성하다보면, 생각 외로 복잡해지는 경우가 있다. 그럴 때 docker로 옮겨 개발을 하는 편인데, 주로 docker-compose를 이용해 데이터베이스 서버 등등과 백엔드 서버를 같이 띄운다. 하지만 매번 할 때마다 구성이 헷갈려 한번 정리할 필요성을 느껴 정리하게 되었다.

프로젝트 구조 설정

.
├── .env
├── server
│   ├── Dockerfile
│   ├── app
│   │   └── app.py
│   └── requirements.txt
├── db-server
│   └── init.sql
└── docker-compose.yml

위의 db-server/init.sql은 데이터베이스 초기 설정을 위해서 넣어놓은 sql 파일이다. 다른 방식으로 구성을 하여도 물론 상관없고, 그에 따라 docker-compose.yml파일만 잘 수정하면 문제 없다.

docker-compose.yml

docker-compose.yml에서는 .env파일을 읽어서 환경변수로 사용이 가능하다. 따라서 docker-compose.yml을 설정하기 전에 .env를 먼저 작성해준다.

MYSQL_PASSWORD=some-password
MYSQL_DATABASE=database

그 후 아래처럼 작성해준다. services.db-server.enviroment를 통해 데이터베이스를 설정하는데, 자세한 설정은 dockerhub의 mariadb를 참고하도록 하자. 나는 개발할 때 테스트용 데이터베이스를 보면서 작업하므로, 데이터베이스 포트를 접근 가능하게 설정해준다.

version: "3.2"

services:
  db-server:
    image: mariadb:latest
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD}
      - MYSQL_DATABASE=${MYSQL_DATABASE}
    volumes:
        - ./db-server/init.sql:/docker-entrypoint-initdb.d/custom-init.sql
    ports:
      - '3306:3306'
  server:
    build: server/
    volumes:
      - ./server/app:/app
    depends_on:
      - db-server
    environment:
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
      - MYSQL_DATABASE=${MYSQL_DATABASE}
    ports:
      - '5000:5000'

server

docker-compose.ymlservices.server에서 이미지를 빌드해서 사용하게 되는데, 빌드할 이미지는 server/Dockerfile을 통해 작성해준다. 나는 flask를 사용하므로, 아래처럼 작성해준다. 마지막 라인 두줄(COPY ~ CMD)는 앱 소스코드를 추가하고 실행하는 부분이므로, 자신의 패키지를 추가해서 실행하거나, manage.py 등을 이용해서 실행하자.

FROM python:3.6

WORKDIR /app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY ./app/app.py /app/
CMD [ "python", "./app.py" ]

이렇게 하면 server/app이 컨테이너의 /app과 공유되어서 파일 변경을 감지할 수 있다.

실행

이렇게 파일들을 설정하고 실행하면, 다음과 같이 잘 구동이 된다.

$ docker-compose up
Creating example_db-server_1 ... done
Creating example_auth-server_1 ... done
Attaching to example_db-server_1, example_auth-server_1
db-server_1    | 2019-02-06 11:09:09 0 [Note] mysqld (mysqld 10.3.12-MariaDB-1:10.3.12+maria~bionic) starting as process 1 ...
...
정말 많은 데이터베이스 로그...
...
db-server_1    | Version: '10.3.12-MariaDB-1:10.3.12+maria~bionic'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  mariadb.org binary distribution
server_1       |  * Serving Flask app "app" (lazy loading)
server_1       |  * Environment: production
server_1       |    WARNING: Do not use the development server in a production environment.
server_1       |    Use a production WSGI server instead.
server_1       |  * Debug mode: on
server_1       |  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
server_1       |  * Restarting with stat
server_1       |  * Debugger is active!
server_1       |  * Debugger PIN: 242-001-359

정말 간단하게 구성한 구조이므로, 자신의 상황에 맞추어서 잘 수정해서 사용하자. 근데 이게 두가지 문제점이 있는데, 첫번째는 맨 처음 컨테이너를 띄울 때, mariadb 서버가 준비되기 전에 어플리케이션 서버가 구동이 되어서 정상적으로 연결이 안되고, 두번째는 --force-recreate를 사용하더라도 데이터베이스 서버는 아예 삭제되고 재생성되는 것이 아니라서 초기화 과정은 건너뛰기 때문에 정상적으로 초기회되지 않는다. 따라서 데이터베이스를 초기화하고 싶을 때는 컨테이너를 삭제하고 다시 띄우는데, 그 때마다 첫번째로 말한 문제가 계속 나타난다.

해결법은 간단한데, 개발환경임을 알리는 환경변수를 설정하고 일정한 주기마다 데이터베이스에 접속해보고 정상적으로 연결이 될 경우 서버를 키는 방법이다. 근데 개인 프로젝트는 귀찮아서… 그냥 쓴다..

February 6, 2019
Tags: