개인 프로젝트를 진행하다보니, 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으로 실행을 시키면 된다!