본문 바로가기
INFRA/DevOps

Flask + gunicorn + nginx 연동

by BTC_쭈콩 2023. 10. 11.

베하 -! 

안녕하세요 콩순이들의 쭈콩입니다 ! 


오늘은 어플리케이션 연동에 대해 알아보기 위한 실습을 준비했습니다. 

 

운영을 하면서 아쉬운점은 개발 환경이나 과정에 대해 알지 못할경우 

문제해결에 걸림돌이 되곤 한다는 것입니다! 

 

그래서 조금더 이해의 폭을 넓히고자 진행한 실습이니 참고해주시면 좋을 것 같습니다 ! 

 

그럼 바로 진행해보도록 하겠습니다 !! - 

 


Flask 마이크로 프레임 워크를 사용하여 Python 어플리케이션을 빌드하기 위해 진행된 실습입니다. 

Flask와 nginx 를 연동하기 위해 미들웨어로 Gunicorn 애플리케이션 서버를 설정해보겠습니다. 

 

Flask 란? 

간단한 웹 사이트, 혹은 간단한 API 서버를 만드는 데에 특화 되어있는 Python Web Framework 로, Python 기반이라 자바가 아닌 파이썬을 기반으로 웹서버를 만들 수 있습니다. 아마 Java 에는 Spring이 짝궁인 것처럼 Python의 짝궁으로는 대표적으로 Flask와 Django가 있습니다. 

 

Gunicorn 이란?

Gunicorn 이란 Python의 Web Server Gateway Interface(WSGI)를 구현하는 HTTP server입니다. 

다수의 WEB 프레임 워크와 널리 호환되며 구현이 심플하고, 서버 리소스가 적어 빠른 속도로 동작한다는 장점이 있습니다. 즉, 웹서버에서 Python, Django 등의 애플리케이션을 호출하기 위해 필요한 서버라고 생각하면 쉽습니다. 

WSGI 서버라는 말이 익숙하지 않은 분들도 계실텐데요! 

WSGI 란?

Web Server Gateway Interface의 약자로 웹서버 소프트웨어와 파이썬으로 만들어진 웹 응용 프로그램 간의 표준 인터페이스 입니다. 이러한 표준 인터페이스는 다양한 웹서버에서 WSGI를 지원하는 응용 프로그램들을 쉽게 호출할 수 있도록 돕습니다.  호출 경로를 요약해보자면 아래와 같습니다. 

요청 -> 웹서버(ex.nginx) -> WSGI server(ex.Gunicorn) -> WSGI를 지원하는 어플리케이션 (ex.Flask)

 

그럼 이제 본격적인 실습을 진행해보도록 하겠습니다!! 

 


실습환경
AWS EC2 ubuntu 22.04 - t2.micro
Flask(python) - grnicorn - nginx

 

Nginx 설치

sudo apt update
sudo apt install nginx
---
Output
Available applications:
  Nginx Full
  Nginx HTTP
  Nginx HTTPS
  OpenSSH
---

# 방화벽 설정 우분투 기본 방화벽 ufw 
sudo ufw allow 'Nginx HTTP'
sudo ufw status
---
Output
Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere                  
Nginx HTTP                 ALLOW       Anywhere                  
OpenSSH (v6)               ALLOW       Anywhere (v6)             
Nginx HTTP (v6)            ALLOW       Anywhere (v6)
---

# 웹서버 동작체크
systemctl status nginx
sudo systemctl enable nginx

 

 

Flask(python) + Gunicorn + nginx 연동

 

1. Ubuntu 리포지토리에서 구성 요소 설치

sudo apt update
sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools

2. Python 가상 환경 만들기

  • Virtualenv는 하나의 서버 인스턴스에서 여러개의 파이썬 버전별 혹은 여러개의 프로젝트 별 종속성 문제를 해결하기 위해 설치하는 일종의 python 가상환경이며, 주로 아래의 케이스에서 많이 유용하다.
    • 개발 서버에서 설치된 python verion과 별도의 project를 진행
    • 동시에 여러 Python 프로젝트를 진행하는 경우 각 버전의 차이가 있는 경우
    • 오래된 Python Project에서 Python 버전은 유지하면 기능을 업그레이드하는 경우
    • 상용 클라우드 (AWS, MS Azure, Google Cloud) 등에서 개발할 때 최신 Python 버전을 지원하지 못하는 경우
sudo apt install python3-venv
mkdir ~/myproject
cd ~/myproject

#Flask 프로젝트의 Python 요구 사항을 저장할 가상 환경 만들기
#Python의 로컬 복사본이 프로젝트 디렉터리 내의 pip디렉터리에 설치됩니다 .myprojectenv
python3.6 -m venv myprojectenv

# 가상환경을 활성화 
source myprojectenv/bin/activate

python3.6이 명령어 없다고 해서 버전확인하니 3.10 버전이라 고쳐주니 잘됨 밑에 빨간 박스가 가상환경을 알려주는 프롬프트

 

3. Flask 애플리케이션 설정

가상환경 내에서 Flask 와 Gunicorn 설치 후 어플리케이션 설계

 

(myprojectenv)\ubuntu@host:~/myproject$
#가상환경 내 프로젝트 디렉터리 안에서 명령어 써야함 

pip install wheel

#Gunicorn과 Flask 설치 
pip install gunicorn flask

 

4. 샘플 애플리케이션 생성

(myprojectenv)\ubuntu@host:~/myproject$
#가상환경 내 프로젝트 디렉터리 안에서 명령어 써야함 
vi ~/myproject/myproject.py
---
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "<h1 style='color:blue'>Hello There!</h1>"

if __name__ == "__main__":
    app.run(host='0.0.0.0')

실습을 두번 진행해서,, 출력내용이 좀 다릅니다 !! 코드는 수정해두었습니다!

(myprojectenv)\ubuntu@host:~/myproject$
#가상환경 내 프로젝트 디렉터리 안에서 명령어 써야함 
sudo ufw allow 5000
python myproject.py

---
Output
 * Serving Flask app 'myproject' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on all addresses.
   WARNING: This is a development server. Do not use it in a production deployment.
 * Running on http://your_server_ip:5000/ (Press CTRL+C to quit)
---

# 이후 웹브라우저에서 서버의 IP 주소를 방문 
http://your_server_ip:5000

#확인후 CTRL + C터미널 창을 눌러 Flask 개발 서버를 중지

 

5. WSGI 진입점 생성

Gunicorn 서버에 애플리케이션과 상호 작용하는 방법

(myprojectenv)\ubuntu@host:~/myproject$
#가상환경 내 프로젝트 디렉터리 안에서 명령어 써야함 

vi ~/myproject/wsgi.py

---
from myproject import app

if __name__ == "__main__":
    app.run()
---

 

6. Gunicorn 구성

(myprojectenv)\ubuntu@host:~/myproject$
#가상환경 내 프로젝트 디렉터리 안에서 명령어 써야함

cd ~/myproject

#you can check that Gunicorn can serve the application correctly by passing it the name of your entry point. This is constructed as the name of the module (minus the .py extension), plus the name of the callable within the application. In our case, this is written as wsgi:app.

# 애플리케이션이 공개적으로 사용 가능한 인터페이스에서 시작되도록 바인딩할 인터페이스와 포트를 지정 

gunicorn --bind 0.0.0.0:5000 wsgi:app

---
Output
[2021-11-19 23:07:57 +0000] [8760] [INFO] Starting gunicorn 20.1.0
[2021-11-19 23:07:57 +0000] [8760] [INFO] Listening at: http://0.0.0.0:5000 (8760)
[2021-11-19 23:07:57 +0000] [8760] [INFO] Using worker: sync
[2021-11-19 23:07:57 +0000] [8763] [INFO] Booting worker with pid: 8763
[2021-11-19 23:08:11 +0000] [8760] [INFO] Handling signal: int
[2021-11-19 23:08:11 +0000] [8760] [INFO] Shutting down: Master
---

http://your_server_ip:5000

확인 후 CTRL + C터미널 창에서 키눌러 종료 
가상환경 비활성화 
deactivate

 

7. Gunicorn 서비스 등록 (Flask 응용 프로그램 제공)

sudo vi /etc/systemd/system/myproject.service

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

# User 이름을 본인의 user 이름으로 변경 할 것
# 절대경로를 잘 파악한 후 변경할 것 
[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/myproject
Environment="PATH=/home/ubuntu/myproject/myprojectenv/bin"
ExecStart=/home/ubuntu/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app

[Install]
WantedBy=multi-user.target
---

sudo systemctl start myproject
sudo systemctl enable myproject
sudo systemctl status myproject

 

8. nginx 구성

Gunicorn 애플리케이션이 실행되고, 프로젝트 디렉터리의 소켓 파일에 대한 요청을 기다림

구성 파일 내용을 추가하여 해당 소켓에 웹 요청을 전달하도록 Nginx 구성

  • "sites-available" 디렉토리는 웹 서버 구성 파일을 관리하는 데 사용되는 디렉토리입니다. 이 디렉토리를 사용하면 여러 가지 가상 호스트 (Virtual Hosts) 또는 서버 블록을 생성하고 관리할 수 있습니다. 각 서버 블록은 다른 도메인 또는 서브도메인에 대한 웹 사이트 구성을 정의하는 데 사용됩니다.
sudo nano /etc/nginx/sites-available/myproject

빨간색은 실습자의 환경에 맞게 변경필요 
---
server {
    listen 80;
    server_name 서버 IP;

location / {
        include proxy_params;
        proxy_pass http://unix:/home/ubuntu/myproject/myproject.sock;
}

---
# nginx 는 sites-enabled를 찾아보지 sites-available을 찾아보지 않기 때문에 꼭 등록 후 링크를 걸어 sites-enabled에 수정사항이 반영되도록 해주어야 한다. 
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
# syntax 에러 검사
sudo nginx -t
sudo systemctl restart nginx
sudo ufw allow 'Nginx Full'

http://서버 IP

 

 

이렇게 Flask + Gunicorn + nginx 로 구현해보았습니다 !! 
저정도는 nginx 에서 해도 되지 않냐고 생각하실 수 있지만! 이건 HTML이 아닌 Python으로 작성됐다는 것을,, 

꼭 참고해주세요 ㅎㅎㅎ !! (쉽지 않았어요,,,)

마지막으로 실습 진행하면서 남겨놓은 트러블슈팅 과정도 공유드립니다 ~~ ! 

 

다 하고나면 원래 위와 같은 Hello There!  페이지가 딱 보여야 하는데 안뜨고 

502 Bad Gateway가 떴습니다...! 

 

1. sudo tail -F /var/log/nginx/error.log 확인

- 13: Permission denied) while connecting to upstream, client 라는 에러로그를 확인 

1. .sock 파일이나 파일이 있는 디렉터리의 권한 또는 소유권 문제
- 해당사항 없었다. 권한 소유권 모두 ubuntu 유저에게 있었음
2. nginx 프록시 설정할 때 syntax 에러문제
- 해당사항 없었다. 잘 들어가있었음
3. nginx.conf 파일에 있는 user확인
- 가보니 user가 www-data로 되어 있었음 그래서 ubuntu로 넣어주니 동작확인

 

2. 가상환경 말고 서버에서도 직접 실행시켜봄

sudo apt-get install python3 python3-pip # 파이썬설치 
sudo apt install gunicorn #Gunicorn 설치 
sudo apt install python3-flask #Flask 설치 
gunicorn -bind 0.0.0.0:8000 wsgi:myproject
# myproject.py 와 wsgi.py 파일이 있는 디렉토리에서 실행해야함
실행후 
서버IP:5000 으로 실행하니까 잘 뜸 

curl 127.0.0.1:5000으로 실행하니까 잘 뜸

 

트러블슈팅으로 인해 실습이 한번에 진행되지 않아서,, 웹페이지 출력내용이 조금 다릅니다 !! 양해 부탁드려요 !! 

오늘은 이렇게 애플리케이션에 대한 이해의 폭을 넓히고자 실습을 진행해보았습니다 !! 

 

낯설기도 하고, 아직 이해의 깊이가 깊어지진 않았지만 그래도 얕게나마 폭을 넓힐 수 있는 기회였던것 같습니다.

 

앞으로도 호기심을 가지고 여러 방면으로 실습하고 공유해보겠습니다?! 

그럼 오늘도 유익한 시간이었길 바라며 이만 물러나겠습니다 !!! 

베 빠 ! -

'INFRA > DevOps' 카테고리의 다른 글

[K8S] SideCar  (0) 2023.10.16
kind  (1) 2023.10.13
[Git] Rebase  (0) 2023.10.04
[DevOps] Jenkins-Git webhook 설정  (0) 2023.10.04
[K8S] Log  (1) 2023.10.03

댓글