[FLASK] Docker , Nginx, gunicorn 배포

개인 프로젝트를 진행하다보니, Flask로 개발을 진행하였고, Flask의 내장되어있는 webserver는 Production 환경에서 사용하지말라고 하여, gunicorn과 Nginx의 Reverse Proxy 를 사용하여, 구축을 해보았다.
다만, 실제로 프로덕션에서는 Gunicorn과 Nginx사이에서는 Socket통신을 하여야 하지만, 이 포스트에서는 그 방법이 아닌, Reverse Proxy로 처리를 하였다.

시작하기전에, Project Folder는 다음과 같이 구성이 되어있다.

├── README.KR.md
├── README.md
├── docker-compose.yml
├── flask
│   ├── app.py
│   ├── db.sqlite3
│   ├── dockerfile
│   ├── modules
│   │   ├── channel.py
│   │   ├── db.py
│   │   └── download.py
│   ├── requirements.txt
│   └── test.py
└── frontend
    ├── Change_pw.html
    ├── Dockerfile
    ├── components
    │   └── navbar.html
    ├── default.conf
    ├── index.html
    ├── login.html
    ├── nginx.conf
    └── query.html

여기서 봐야할 부분은, flask안에 app.py가 있고, frontend는 전부 html로 구성되어있다.

먼저 flask폴더 안에 있는 dockerfile을 먼저 보자.

FROM python:3.10.5
MAINTAINER Dobob [email protected]

RUN mkdir /app
COPY requirements.txt /
RUN pip3 install -r /requirements.txt
COPY . /app
WORKDIR /app

하나씩 살펴보면,

FROM python:3.10.5 -> 이부분은 python의 3.10.5의 버전을 사용한다는것이고
MAINTAINER Dobob [email protected] 이부분은 관리자(?)를 넣으면 되는부분이다.
RUN mkdir /app 부분은 루트디렉터리(/)에 app 디렉터리를 만드는것이고,

COPY requirements.txt 부분은 flask 디렉터리안에 있는 python의 dependency를 설치 할 리스트를 적어둔 것이다.
이후
RUN pip3 install -r /requirements.txt 는, COPY 한 dependecy 를 설치하고,

COPY . /app -> 이부분은 현재 있는 디렉토리(flask) 내부에 있는 모든 파일들을 /app에 복사하는 명령어이다.

WORKDIR -> 해당 디렉터리에서 모든것을 실행한다(?) 정도로 이해하면 될 것 같다.

이제, frontend 디렉터리의 dockerfile을 봐보자

FROM nginx:latest
MAINTAINER Dobob [email protected]

COPY . /usr/share/nginx/html

RUN rm /etc/nginx/nginx.conf
COPY nginx.conf /etc/nginx/
RUN rm /etc/nginx/conf.d/default.conf
COPY default.conf /etc/nginx/conf.d	

대충 감이 올 것이라고 생각하니 PASS하도록 하겟다.


이제 우리가 구성해야할 부분은 다음과 같다

Client
  |
Nginx (접근 위치 / 와 /api)
  |
------------
|          |
backend  frontend

이런식으로 동작 할 것이다.

그전에 backend부분은 현재 7000번 포트를 사용하여, 통신을 하고 있으므로,

endpoint가 ServerIP/api로 접근하는 부분은 모두 backend:7000으로 접근 할 수 있게 해야한다.

이때 사용하는것이

Nginx Reverse Proxy
이다.

내가 사용한 Nginx Reverse Proxy를 보자,

server {
    listen 80;

    location / {
            root /usr/share/nginx/html;
            index index.html;
    }

    location /api {
        proxy_pass http://backend:7000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    }

}

대충 보면 listen부분은 80번포트로 서버를 열겟다 라는 의미이며,
location / 부분은 "http://serverip/" 로 접근하였을때 어디로 전달을 해 줄것인가? 를 의미한다.

여기선 root디렉터리가 /usr/share/nginx/html안으로 연결이 되어있다.

그리고 location /api부분은, "http://serverip/api" 로 접근하였을때, 어떻게 해 줄것인지를 나타내며

proxy_pass http://backend:7000 으로 넘겨주겟다 라는 의미가 된다.

그러면, 우리가 생각했던 serverip/api 로 연결 시, backend:7000으로 보낸다라는 부분을 해결했다.

이제, 두 컨테이너를 묶어줄 차례이다. docker-compose를 보면 된다.

version: "3.0"


services:
    backend: -> 백엔드로 동작할 부분
        build: ./flask -> 현재 디렉터리 에서 flask라는 디렉터리 안에 있는 dockerfile로 빌드를 진행한다. 
        container_name: flask
        hostname: backend
        restart: always
        command: gunicorn -b 0.0.0.0:7000 app:app -> **중요하다, gunicorn을 사용하여, flask의 코드를 실행하는 부분이다.**
        ports:
            - "7000:7000" -> guicorn에서 7000번 포트로 실행을 하였기에, 7000번 포트를 개방해 준다.
        networks:
            - default
    frontend:
        build: ./frontend 위와 마찬가지,
        hostname: frontend
        container_name: frontend
        restart: always
        ports:
            - "80:80"
        networks:
            - default
        depends_on:
            - backend -> 이부분이 있어야, 두 컨테이너가 같이 동작한다.(의존성관련)

이제 그러면 실행을 해보자.

환경은 macOS Montery + Docker Desktop 을 사용하였다.

해당 디렉터리로 가서 docker-compose up으로 실행을 시키면 된다!

Show Comments