파이썬 서버 배포 - paisseon seobeo baepo

Photo by Hitesh Choudhary on Unsplash

파이썬 웹 애플리케이션을 Production 서버로 배포하는 것은 다소 까다로운 편이다.

그 이유는 WSGI가 필요하기 때문인데 이 시간에는 어떻게 파이썬 웹 애플리케이션을 서버에 올리는지 알아보도록 하겠다.

참고로 WSGI에 대해서 잘 모르시는 분은 예전에 서버에 대해서 정리해둔 글이 있으니 참고 바란다.

개괄

우선 파이썬 웹 애플리케이션이 구동되는 전체적인 그림을 먼저 알아보도록 하자.

우리는 WSGI 서버 중 Gunicorn(구니콘)을 이용하여 서버를 구동할것이다.

(Gunicorn의 경우 Unix 또는 Linux 환경에서만 구동되므로 참고 바란다. 해당 글은 Ubuntu기준으로 설명 한다.)

Gunicorn만으로도 서버 구동이 가능하나 단독으로 사용할시 아래와 같은 문제점이 있다.

  • DDos등 외부 공격 취약
  • HTTPS 처리 불가
  • Static 파일의 전송 효율성
  • 다수의 연결을 효과적으로 처리 불가

이를 해결하기 위해 보통 Nginx를 이용하게 되는데 나중에 살펴보겠지만 프록시로 Gunicorn에게 요청을 넘겨주게 된다.

각설하고 이제 구체적으로 이를 어떻게 설정하는지 살펴보도록 하자.

Gunicorn 설정

1. 설치

먼저 파이썬 웹 애플리케이션을 구동하기 위해 Gunicorn의 설치가 필요하다.

아래 명령어를 통해 프로젝트에 Gunicorn을 설치하도록 한다.

pip install gunicorn

만약 가상환경을 이용한다면 가상환경 안에서 설치해줘야 한다.

2. Gunicorn 테스트

아래 명령어를 통해 잘 구동이 되는지 확인해본다.

gunicorn --bind 0.0.0.0:8000 [Project file path]:app

여기서 [Project file path] 는 시작할 파일의 경로를 적어준다.

경로는 마침표(.)으로 구분해주며 예를들어 src/index.py 를 구동한다고 했을 때 최종적인 명령어는 아래와 같다.

gunicorn --bind 0.0.0.0:8000 src.index:app

이제 0.0.0.0:8000 에 접속하여 이상이 없는지 확인한다.

3. Gunicorn 서비스 등록하기

Gunicorn을 일일히 명령어로 실행되기 보다. 안정적으로 서버가 재시작 되더라도 구동되기 위해 서비스 등록이 필요하다.

시스템에 gunicorn을 등록하기 위해 우선 아래 경로로 편집기를 이용하여 열어준다.

$ vim /etc/systemd/system/gunicorn.service

이후 아래와 같은 내용을 입력해준다.

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

[Service]
User=[유저 이름]
Group=[유저 그룹]
WorkingDirectory=[파이썬 웹 애플리케이션 프로젝트 경로]
ExecStart=[Gunicorn 설치 경로] --workers 3 --bind 0.0.0.0:8000 [프로젝트 경로]:app

[Install]
WantedBy=multi-user.target

[변수 이름] 에 대한 설명은 아래와 같다.

  • [유저 이름]

: Linux환경의 유저 이름 아래 명령어를 통해 확인 해 볼 수 있다.

$ whoami
  • [유저 그룹]

위의 유저 이름이 속한 그룹 아래 명령어를 통해 확인 가능하다.

$ groups [사용자명]
  • [Gunicorn 설치 경로]

Gunicorn이 설치된 경로 만약 가상환경을 통해 설치됐다면 가상환경의 설치 경로를 적어준다.

위의 내용을 토대로 작성된 최종적인 파일은 아래와 비슷한 모습이다.

[Unit]
Description=gunicorn daemon
After=network.target
[Service]
User=root
Group=root
WorkingDirectory=/root/video_cron
ExecStart=/root/video_cron/venv/bin/gunicorn --workers 3 --bind 0.0.0.0:8000 src.index:app
[Install]
WantedBy=multi-user.target

여기서 로그 작업을 추가하거나 코드가 변경 되었을때 Gunicorn이 자동으로 재시작 되어 반영되도록 할 수 있는데 ExecStart에 몇가지 옵션을 추가해주면 된다.

...
ExecStart=/root/video_cron/venv/bin/gunicorn --workers 3 --bind 0.0.0.0:8000 src.index:app --reload --error-logfile /root/logs/debug.log --access-logfile /root/logs/access.log --capture-output --log-level debug
...

위의 /root/logs/debug.log, /root/logs/access.log 파일이 존재 해야 에러가 발생하지 않으므로 없다면 빈파일을 만들어 준다.

옵션에 대한 설명 또는 다른 추가적이 기능이 필요하다면 아래 링크를 참고 바란다.

이제 모두 작성을 마쳤다면 아래 명령어를 통해 Gunicorn의 서비스를 등록해준다.

$ sudo systemctl start gunicorn # Gunicorn 서비스 시작
$ sudo systemctl enable gunicorn # 시스템 재시작시 Gunicorn 자동 시작
$ sudo systemctl status gunicorn.service # Gunicorn 서비스 상태 확인

active (running)이 되었다면 정상적으로 실행된 것이다.

Nginx 설정

1. 설치

아래 명령어를 통해 우선 Nginx를 시스템에 설치 해주도록 하자.

$ sudo apt-get update
$ sudo apt-get install nginx

2. 설정

Nginx의 설정을 바꿔야 하는데 /etc/nginx/sites-enabled/ 의 하위에 설정 파일이 위치한다 기본적으로 default 파일이 있는데 이를 삭제하고 이름을 바꿔 새로 작성해주거나 그냥 default 파일을 수정해도 무관하다.

설정 파일을 우선 관리자 권한으로 열어준다.

$ sudo vim /etc/nginx/sites-enabled/[설정파일이름]

해당 파일에 아래와 같은 내용을 작성한다.

server {
listen 80;
server_name [Public IP주소];

charset utf-8;

location / {
include proxy_params;
proxy_pass http://[Public IP주소]:8000;

}
}

[Public IP주소] 대신에 도메인이 있다면 이를 적어줘도 무방하다.

3. Nginx 재시작 하기

설정 파일이 반영되기 위해선 Nginx의 재시작이 필요하다.

$ sudo service nginx restart

재시작 후 마찬가지로 정상적으로 실행 되었는지 아래 명령어로 확인해보자.

$ sudo service nginx status

서버 접속 테스트

지금까지 왔다면 Production 서버의 설정을 모두 완료한 것이다.

이제 설정한 Public IP (또는 도메인)으로 접속해서 정상적으로 접속되는지 확인해보자.

Nginx에서 80포트를 설정 했으므로 브라우저에 Public IP (또는 도메인)만 주소 창에 입력하면 접속 가능하다.

정리

요청은 아래와 같은 순서로 전달된다.

  1. 브라우저에서 주소에 아이피 또는 도메인을 입력시 Nginx로 요청이 전달된다.

2. Nginx는 프록시로 Gunicorn으로 요청을 전달한다.

3. Gunicorn은 전달 받은 요청을 Flask 또는 Django에 전달한다.

응답은 이의 역순으로 이뤄어지며 다시 한번 처음 봤던 그림을 보고 이해 해보자.

행복한 아빠

Docker

Docker로 파이썬 배포 운영하기

행복한아빠 2016. 9. 22. 19:54

파이썬으로 개발을 하고 보니 운영서버 배포에 대한 고민이 생겼습니다. 물론 Java로 할 경우도 운영서버 구성이 번거롭기는 마찬가지이지만 파이썬을 위한 운영서버는 할 게 더 많네요.

지인의 추천으로 도커를 사용하기로 했습니다.

운영서버 구성

우리의 운영서버(WAS)는 다음과 같은 소프트웨어가 설치 되어야 합니다.

  • Python3, PIP
  • MySQL Lib
  • 파이썬 모듈들...
  • uWSGI 설치 및 구성
  • NginX 설치 및 구성
  • 소스 받기 위한 Git
  • 그리고 우리의 애플리케이션

이것들 설치 가이드 작성해 보니 꽤 길고 실제 설치하는데 넘 오래 걸립니다. 문제는 WAS를 여러 대 띄울라면 이 재미 없는 작업을 매번! 해 줘야 하네요.

간단한 배포/운영 방법

설치 가이드 잘 작성해 놓고 각 서버마다 필요한 소프트웨어 설치하고 Git을 통하여 소스만 pull 하는 방식입니다.

구성은 쉽지만 앞에 이야기 한 것처럼 서버가 늘어날 때마다 왠 종일 걸리는 설치작업을 계속 해줘야 합니다. 모듈 추가 같은 환경변화라도 있으면 서버마다 또 해야 하고 서버가 동일한 환경을 가지게 유지하기가 쉽지 않을 것 같습니다.

VM 이미지를 이용?

우리는 AWS를 이용합니다. AWS에는 VM의 이미지를 만들고 그 이미지로 인스턴스를 구동하는 방법을 제공합니다.

한 서버에 필요한 소프트웨어와 우리의 애플리케이션을 설치하고 그 이미지를 만들어 인스턴스를 만드는 방법도 가능할 것 같습니다.

파이썬 서버 배포 - paisseon seobeo baepo

언뜻 보면 훌륭한 방법인 것 같은데 배포할 때마다 저 큰 이미지를 만들고 인스턴스를 새로 생성한다는 것이 부담입니다.

소스코드 한 줄 바꿨다고 저 짓 하기는 망설여지네요.

그리고 이전 버전의 인스턴스(서버)는 날려야하니 인스턴스 관리도 좀 그렇습니다.

그리고 배포때마다 이미지가 생겨야 하는데 VM 이미지 용량도 그렇고 엄청난 양의 이미지가 생기겠네요.

Docker를 이용한 배포/운영

역시 이런 경우 도커를 이용한 방법이 최고입니다. 

  1. 개발자가 소스를 push 합니다.
  2. 빌드서버는 새로운 소스와 환경으로 빌드를 하고 테스트/확인 후 도커 이미지를 빌드합니다.
  3. 빌드서버는 도커 이미지를 private docker repositoy에 push 합니다.
  4. 빌드서버는 각 운영서버에 새로운 이미지로 다시 가동하라고 합니다.
  5. 각 운영서버들은 기존 컨테이너를 지우고 이미지를 다시 받아 새로운 버전을 가동합니다.
  • 소스형상관리: Gitlab
  • 운영서버: CoreOS (도커를 위한 경량 OS 정도로 생각하세요)
  • Private Docker Repository : Docker Repository or Nexus Repository Manager
  • Build Server : docker-py 모듈로 운영서버 원격 배포 모듈 대충 작성

도커로 운영하면 보통 이 정도로 관리할 것으로 예상되고 우리 규모에서 이 정도면 충분하다고 판단되어 이렇게 구성합니다만....

실제 배포하다보니 또 다른 문제가 발생합니다. 이런 도커 이미지가 너무 커 배포가 넘 느리다는...