[Gunicorn] 프로젝트 배포 시 gunicorn WSGI 서버 사용하기 (오답노트)

Alex of the year 2020 & 2021·2021년 6월 10일
1

Web, Server, Git, etc.

목록 보기
10/11
post-thumbnail

EC2 RDS Gunicorn 연동

(+210601) Gunicorn이 그래서 뭐였는데

  • WSGI의 한 종류

    WSGI (Web Server Gateway Interface)
    (매번 읽었던 이야기인데 이번에는 'gateway'라는 것에 좀 더 무게를 두고 생각해보았으니 gateway 볼드체)

    • 파이썬에만 종속되는 인터페이스
    • WSGI는 CGI 디자인 패턴을 발전시킨 인터페이스

    CGI (Common Gateway Interface)
    개발자들의 다양한 언어를 통해 개발해 둔 다양한 형태의 요청을 이해할 수 있는 공통의 규약이자 프로그램
    (== 웹 서버와 애플리케이션 사이의 동시 통역사)

    • CGI의 발전형태이므로 웹 서버의 요청을 해석하여 애플리케이션으로 보내주는 역할은 당연히 동일
      (== Apache나 NginX로 들어오는 HttpResquest를 파이썬이 이해할 수 있게 던져줌)
    • 그래서 말그대로 'MiddleWare'
    • 참고로 장고는 이런 동시통역사(WSGI)의 상위 버전을 기본적으로 달고 있음 (python manage.py runserver 할 때)
  • Web Server(ex. NginX)로 받은 서버사이드 요청을 애플리케이션인 Django로 보낼 때의 middleware

    Web server는 기본적으로 정적인 것만 처리한다. 그러나 인터넷에서 흔히 보이는 동적인 페이지들은 이런 Web server만을 갖고 렌더할 수는 없는 성질의 것이다. 내가 백에서 작성하는 애플리케이션 코드를 웹 서버가 이해하기 위해서는 NginX와 같은 웹서버가 내 코드를 이해해야할텐데, 그렇지 못함. 그래서 이런 중간 다리 격인(literally 'middleware') WSGI가 필요한 것.


세션(강의) 노트

EC2 인스턴스에 로컬로 작성한 프로젝트를 배포하는 준비 과정
(== 개인 PC에서 개발한 것과 마찬가지로 EC2 서버에 비슷한 개발환경을 설치하는 과정)

1. SSH 환경에 Miniconda 설치

  1. pem 파일이 있는 폴더로 이동 --> pem 파일을 이용하여 SSH로 EC2에 접속 (ssh -i [pem파일이름] [SSH서버주소] --> EC2 서버 접속 완료
  2. 이후 전체 플로우는: miniconda 설치, 패키지 업그레이드, 최소한의 패키지만 설치. 하나씩 환경설정할 것.
  3. miniconda 설치 스크립트 (각자의 OS에 맞는 것으로) 다운로드 우클릭 후 주소 복사 --> 터미널로 데려와서 wget [복사한주소] --> 이후 ls 시, 미니콘다 설치 완료 확인 가능 (ex. Miniconda3-latest-Linux-x86_64.sh)
  4. chmod +x [Miniconda3-latest-Linux-x86_64.sh]
  5. 이후 바로 ./Miniconda3-latest-Linux-x86_64.sh 실행 시켜서 미니콘다 설치
  6. 나오는 것에 다 yes

    +) 210601 추가
    실수로 no를 누른 것이 있었다.
    Do you wish the installer to initialize miniconda3 by running conda init? 여기서

    실수로 어쩌다 no (hell no...)

    이 경우 아래 7번을 실행해도, 명령 라인 앞에 (base)가 생기지 않는 현상이 생긴다.
    이 때에는 export PATH="~/miniconda3/bin:$PATH"~/.bashrc에 직접 적어주었고, conda init을 통해 해결했다.

  1. 모두 설치한 후에는 source .bashrc 입력 --> 명령 라인 가장 앞에 (base)가 생김

2. APT get 명령어를 이용한 패키지 업데이트, 업그레이드 --> GCC 설치, mysql Client 설치

sudo apt-get update
sudo apt-get upgrade

+) 210601 추가

  • apt-get update운영체제에서 사용 가능한 패키지들과 그 버전에 대한 정보를 업데이트
    설치되어 있는 패키지를 최신으로 업데이트하는 것이 아닌 설치가능한 리스트를 업데이트
    apt-get install 명령어로 특정 패키지 설치가 안된다면 위의 명령어를 한 번 쳐주는 것이 좋음

  • apt-get upgradeapt-get install 명령어로 설치한 패키지들을 최신 버전으로 업그레이드
    이를 이용하면 apt-get update로 가져온 각 패키지들의 최신 버전에 맞게 업그레이드를 함

sudo apt-get install gcc
sudo apt-get install libmysqlclient-dev

+) 210610 추가

GCC

  • GNU Compiler Collection의 줄임말. GNU 프로젝트의 일환으로 개발되어 널리 사용되는 컴파일러.
  • 많은 컴파일러와 운영체제를 만드는 데 사용되었음
  • 시스템 네이티브 컴파일러를 사용할 때에 비해, 같은 파서로 코드를 처리하므로 이식성이 향상된다.
  • 참고 : GCC의 동작 방식
    https://woodforest.tistory.com/181

3. Conda를 이용하여 프로젝트를 위한 가상환경 설정

conda create -n [conda이름] python=3.8
conda activate [conda이름]
git clone [repo주소]
이후 ls 시, 잘 클론 되었음.

주의할 점은 이 때, 클론된 프로젝트 속의 requirements.txt를 가상환경에 모두 설치해줘야하는 것.
한 번에 requirements 내용 모두 설치하는 명령어는
pip install -r requirements.txt
이후 pip freeze로 패키지 모두 설치되었는지 확인

4. 내 프로젝트에 my_settings.py 작성 및 settings.py에 EC2 서버의 퍼블릭 아이피를 설정해준 후 서버 돌려보기

퍼블릭 아이피 확인: AWS EC2 접속 후, running중인 EC2 인스턴스 클릭 --> IPv4 퍼블릭 주소 확인 가능

+) 210610 추가
너무 당연한 이야기지만, 퍼블릭 IP를 사용하자.

복사하여, settings.py의 ALLOWED_HOSTS에 붙여넣기
(ex. ['*', 'IPv4서버주소', 'IPv4서버주소:8000']

프로젝트의 root directory에 my_settings.py 생성하여,
DATABASES, SECRET_KEY 설정
이 때 DATABASES에 들어가는 디테일은 RDS에 연동된 DB 디테일

(ex.

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': '--보안--',
        'USER': '--보안--',
        'PASSWORD': '--보안--',
        'HOST': '[SSH주소(RDS엔드포인트)]',
        'PORT': '3306',
    }
}

SECRET = {
    'secret': '--보안--',
}

[참고] 로컬환경에서의 RDS 접속 명령어
mysql -u root -h [RDS엔드포인트주소] -p 후 패스워드 입력

이후 python manage.py runserver로 서버 돌려 확인
(혹시 이 때 TimeZone setting error 시, 'Asia/Seoul' 잘 쓰여져 있는지 다시 한 번 확인)
python manage.py runserver 0:8000을 써야 퍼블릭 아이피 사용하는 것

이후 포스트맨으로 다시 한 번 확인
퍼블릭 아이피/[작성한 엔드포인트 주소] 호출하여 확인

여기까지만 해도 호출은 원활하게 이루어지지만,
장고에서의 기본 manage.py runserver 명령어는 단일 스레드로 동작
--> 개발 및 테스트로는 적당하지만, 리퀘스트가 많을 수 있는 운영환경에서는 적합 X

따라서, 멀티쓰레드를 지원하는 웹 애플리케이션 서버 프로그램인 구니콘을 설치하여 배포하는 것이 좋다

5. 구니콘 설치

구니콘 역시 설치 방법은 pip install gunicorn
구니콘 설치 이후에도 SSH 세션이 끊어져도 서버를 동작시켜주기 위해 nohup이라는 툴을 써서, 구니콘을 백그라운드로 동작시켜주도록 한다.

gunicorn --bind=0.0.0.0:8000 [프로젝트명].wsgi 명령어는 백그라운드로 돌리지 않고 그냥 돌리는 것
nohup gunicorn --bind=0.0.0.0:8000 [프로젝트명].wsgi & 명령어는
장고의 웹 애플리케이션을 지정해주는 역할을 하는 wsgi를 다시 적어 백그라운드로 돌리는 명령어
(&는 백그라운드로 동작하는 명령)

ps ef | grep python 이 ps 명령어는 구니콘이 잘 실행되는지, PID는 몇인지 알 수 있게 해주는 명령어
이후에는 포스트맨으로 다시 한 번 호출하여 호출이 잘 되는지 확인 필수

gunicorn을 계속 띄워 두지 말고
포스트맨으로 확인이 모두 끝난 후에는 kill [확인한PID번호]로 구니콘을 종료하도록 한다.

이후 nohup gunicorn --bind=0.0.0.0:8000 [프로젝트명].wsgi 명령어 입력 시,
구니콘이 정상종료된 것을 확인할 수 있다.


+) 210610 추가

gunicorn.service 등록하기

(레퍼런스 : 점프 투 장고 https://wikidocs.net/76904)

  • gunicorn의 시작, 중지를 쉽게 하고
  • aws ec2 서버를 다시 시작할 때 gunicorn을 자동으로 실행하기 위함
  • 환경 변수 파일 및 서비스 파일 작성이 필요하다

서비스 파일 생성 시 애를 많이 먹었다.

지금 보니 애초에 환경 변수 파일을 생성하지 않고, 서비스 파일 생성 내 EnvironmentFile 에서 있지도 않는 변수 파일을 지정해두니 당연히 애를 먹을 수 밖에 없는 것이었다. (!!!)

1) 환경 변수 파일 생성

위치 : home/ubuntu/miniconda3/envs/[프로젝트이름].env
(점프 투 장고에서는 venvs를 사용했지만 나는 miniconda3)

DJANGO_SETTINGS_MODULE=config.settings.prod

( +) 이거 어디서봤다 했더니, 장고 프로젝트 생성 후 config.wsgi에가면 볼 수 있는 환경 변수 세팅이었다)


2) (⭐️1) 하고 나서⭐️) 서비스 파일 생성

위치 : /etc/systemd/system/gunicorn.service

[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=ubuntu
Group=ubuntu
WorkingDirectory=/home/ubuntu/[프로젝트있는최상위디렉토리]/[프로젝트이름]
EnvironmentFile=/home/ubuntu/venvs/[프로젝트이름].env
ExecStart=/home/ubuntu/venvs/mysite/bin/gunicorn \ # 백슬래시 잘 먹힌다 (첨에 애먹는 과정에서 "이게 안먹힌다고...?" 했음)
        --workers 2 \ # 나는 3. 이 수를 구하는 것은 아래 레퍼런스 참고.
        --bind unix:/tmp/gunicorn.sock \ # 이부분도 gunicorn.sock 파일 위치로 따로 지정해주었다.
        [프로젝트명].wsgi:application
[Install]
WantedBy=multi-user.target

3) 서비스 실행 및 등록

2)에서 만든 서비스 파일이 관리자 디렉토리에 있으므로 실행 역시 관리자 권한으로 실행 (!!!)
sudo systemctl start gunicorn.service
이후, 서비스 잘 실행되는지 확인하기 위해
sudo systemctl status gunicorn.service

(저 작은 초록불을 키기 위해 너무 애를 썼다...)

EC2 서버 재시작 시 자동으로 gunicorn 실행을 위해
sudo systemctl enable gunicorn.service

만약, 서비스 종료를하고 싶다면
sudo systemctl stop gunicorn.service
(다시 시작하려면 stoprestart로 바꾸어주면 된다)


+) 210601 reference
WSGI, CGI (필력 🙏🏻)
https://this-programmer.tistory.com/entry/gunicorn%EC%9D%80-%EB%8C%80%EC%B2%B4-%EB%AD%90%ED%95%98%EB%8A%94-%EB%86%88%EC%9D%BC%EA%B9%8C-%EB%B6%80%EC%A0%9C-CGI-WSGI%EB%8A%94-%EB%8C%80%EC%B2%B4-%EB%AD%90%EB%83%90

https://tibetsandfox.tistory.com/22

Gunicorn workers 수
http://hell0-world.com/architecture/2020/05/10/gunicorn.html

profile
Backend 개발 학습 아카이빙 블로그입니다. (현재는 작성하지 않습니다.)

0개의 댓글