Web Server

Flask App Using Nginx & Gunicorn

PON_Z 2023. 1. 27. 17:06

- 먼저 웹서버WAS(Web Application Server)에 대해 알고가자. 웹서버는 클라이언트에게 정적인 컨텐츠, 즉 html, css, js를 제공하고 WAS는 웹서버가 단독으로 처리할 수 없는 DB로직 처리가 필요한 동적 컨텐츠를 제공함과 동시에 정적인 데이터도 제공한다. 그렇다면 WAS만 사용하면 되는것이 아닌가 하는 의문이 생긴다. 그래도 되지만 WAS는 DB조회 및 다른 로직을 처리하는 일도 하기 때문에 정적인 컨텐츠를 웹서버에 맡기고 동적인 컨텐츠를 WAS에 맡겨 기능을 분리해 두는 것이 서버 부하를 방지하고 효율적이다.

 

 

- 기본 flask 서버는 개발용으로써, 배포용으로 적합하지 않다. flask를 단독으로 실행하면 단일 프로세스가 Request를 처리하게 되는데, 트래픽이 많을 경우 이로인해 서버에 병목이 생길 수 있다. WSGI(Web Server Gateway Interface)는 여러개의 쓰레드를 생성하여 여러 Request를 병렬로 처리함으로써 이 문제를 해결한다.

 

- WSGI를 이해하기에 앞서 CGI(Common Gateway Interface) 에 대한 이해가 필요하다. CGI는 웹서버와 WAS 사이의 인터페이스를 제공한다. 웹 서버 종류에는 Apache, Nignx가 있고 파이썬 웹 프레임 워크에는 Flask, Django가있다. CGI는 이를 연결하는 하나의 규약을 제공하여 다른 프레임워크를 사용하게 되더라도 연결하는데 불편하지 않게 해준다. 정리하면 WSGI는 웹서버 입장에서는 CGI 역할을, 프레임 워크 입장에서는 웹서버 역할을 하는 일종의 미들웨어이다.

 

- WSGI를 사용하게 되면 웹 프레임워크로서의 기능을 수행할 수 있게 된다. 하지만 WSGI는 ssl과 정적인 파일을 지원하지 않는다(uwsgi는 지원하나 cpu 자원이 많이 소모된다). 따라서 정적인 파일을 지원하기 위해 Nginx를 사용한다.

 

 

- Nginx는 경량 웹서버이다. 클라이언트로부터 Request를 받았을 때 요청에 맞는 정적 파일을 응답해주는 HTTP Web Server로 활용되며, Reverse Proxy Server로 활용하여 WAS 서버의 부하를 줄일 수 있는 로드밸런서로 활용되기도 한다. 또한 Nignx는 Event-Driven구조로 동작하기 때문에 고정된 프로세스만 생성하여 사용하고, 비동기 방식으로 요청을 Concurrency하게 처리 가능하다. 이로 인해 Apache 웹서버 보다 성능이 좋다.

 

- 아래 그림처럼 새로운 Request가 들어와도 프로세스와 쓰레드를 생성하지 않기 때문에 적은 자원으로 효율적인 운영이 가능하여 단일 서버에서도 동시에 많은 Request를 처리할 수 있다.

Nginx 동작 원리

 

요약 :

- 파이썬 웹 프레임워크는 비동기가 아니기 때문에 동접자에 대한 대처가 어렵지만, nginx와 gunicorn을 사용하여 보완할 수 있다. 

- Gunicorn 사용 이유 : WSGI Middleware 역할

- Nginx 사용 이유 : Reverse Proxy Server, Load Balancer 역할

 

App : flask app

Web Server : nginx

Middleware : gunicorn 

 

- 프로세스 : client request -> nginx : web proxy server -> gunicorn : application server -> flask app

 

 

- Gunicorn 설정

- Install

yum install http://centos7.iuscommunity.org/ius-release.rpm

# 파이썬 설치
yum install python36u

# pip 설치
yum install python36u-pip
yum install python36u-devel
# centOS7
yum install nginx
pip install gunicorn

 

- 가상환경 생성

# 생성
sudo python3 -m venv venv
# 실행
source venv/bin/activate

 

- gunicorn 연결 테스트

# server는 py 파일명, app은 flask app 이름
gunicorn --bind 0.0.0.0:8000 server:app &

 

- 리눅스 서비스 생성

# gunicorn.sock은 웹서버에서 리버스 프록시 구성에 사용

# /etc/systemd/system/flaskapp.service

[Unit]
Description=Gunicorn instance to serve api_server
After=network.target

[Service]
User=root
Group=root
WorkingDirectory=/home1/root/api_server
Environment="PATH=/home1/root/api_server/venv/bin"
ExecStart=/home1/root/api_server/venv/bin/gunicorn --workers 4 --bind unix:gunicorn.sock --access-logfile /home1/root/api_server/access.log --error-logfile /home1/root/api_server/error.log  --reload -m 777 wsgi

[Install]
WantedBy=multi-user.target

 

- 서비스 실행

sudo systemctl stop flaskapp
sudo systemctl enable flaskapp
sudo systemctl daemon-reload
sudo systemctl start flaskapp

- 서비스 구동 확인

sudo systemctl status flaskapp

-  디버그

sudo systemd-analyze verify flaskapp.service

 

- Nginx 설정

- nginx.conf

user root;
worker_processes  20;

events {
        ### sets the maximum number of simultaneous connections that can be opened by a worker process
        worker_connections 20;
}
http {
        include       mime.types;
        default_type  application/octet-stream;
        server_tokens off;
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                        '$status $body_bytes_sent "$http_referer" '
                        '"$http_user_agent" "$http_x_forwarded_for"';
        access_log  logs/access.log  main;
        sendfile        on;

        server {
                ### if has domain:80
                listen 0.0.0.0:80;
                ### add domain
                server_name _;
                                
                #charset koi8-r;

                # nginx logs
                access_log  logs/access_.log  main;
                error_log logs/error_.log;
                
                # reverse proxy
                location / {
                        index index.html index.htm;
                        # gunicorn socket location
                        proxy_pass http://unix:/home1/root/api_server/gunicorn.sock;
                }
                
                location /static/ {
                        alias /home1/root/api_server/dist/static;
                        try_files $uri $uri/ /$uri;
                        proxy_pass http://unix:/home1/root/api_server/gunicorn.sock;
                }
                

                location = /50x.html {
                        root html;
                        ### add error page
                        # proxy_pass
                }
        }
}

 

- nginx 실행 파일이 있는 곳에서

# nginx start
./nginx
# nginx stop
./nginx -s stop

 

- vue와 같은 SPA기반의 웹프레임 워크를 사용시에는 빌드된 결과물의 정적자산을 "dist/static" 폴더에 위치하게 한 후, flask 서버 파일이 존재하는 곳 (server.py가 존재하는 곳)에 빌드된 결과를 옮긴다. 이후 flask 서버 파일이 존재하는 곳에 "templates" 폴더를 만들고 "dist" 안에 존재하는 index.html을 바라보게 해야 flask-gunicorn-nginx가 연결된다.

- vue 사용시 vite.config.js의 빌드부분에 아래와 같이 설정하는 것을 잊지 말자

  build: {
    target: 'esnext',
    chunkSizeWarningLimit: 5000,
    publicPath: '/',
    assetsDir: 'static',
  },

 

 

 

ref)

- 세팅(gunicorn) :

https://www.digitalocean.com/community/tutorials/how-to-serve-flask-applications-with-gunicorn-and-nginx-on-centos-7

- 세팅(nginx):

https://phsun102.tistory.com/47

 

 

- 개념:

https://2yk.dev/posts/nginx-gunicorn-%EC%9D%B4%EC%9A%A9%ED%95%98%EC%97%AC-flask%EC%95%B1-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0/

https://velog.io/@jimin_lee/Nginx%EC%99%80-Gunicorn-%EB%91%98-%EC%A4%91-%ED%95%98%EB%82%98%EB%A7%8C-%EC%8D%A8%EB%8F%84-%EB%90%A0%EA%B9%8C

https://velog.io/@denhur62/nginx-%EC%99%80-uwsgi%EB%A5%BC-%EC%99%9C-%EC%82%AC%EC%9A%A9%ED%95%A0%EA%B9%8C

http://egloos.zum.com/mcchae/v/11149241

https://losskatsu.github.io/it-infra/reverse-proxy/#2-%ED%8F%AC%EC%9B%8C%EB%93%9C-%ED%94%84%EB%A1%9D%EC%8B%9Cforward-%EC%84%9C%EB%B2%84%EB%9E%80

https://velog.io/@wijihoon123/Nginx%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80

https://2yk.dev/posts/nginx-gunicorn-%EC%9D%B4%EC%9A%A9%ED%95%98%EC%97%AC-flask%EC%95%B1-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0/

https://panda5176.tistory.com/8

https://velog.io/@jimin_lee/Nginx%EC%99%80-Gunicorn%EC%9C%BC%EB%A1%9C-Flask%EC%95%B1-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0

 

728x90

'Web Server' 카테고리의 다른 글

이미지 업로드를 위한 웹서버 구현  (0) 2022.12.08