gunicorn - 배포

hwisaac·2023년 9월 6일
1

gunicorn

목록 보기
5/8

Gunicorn 배포

Gunicorn을 프록시 서버 뒤에서 사용하는 것을 강력히 권장합니다.

Nginx 구성

다양한 HTTP 프록시가 있지만, 기본 Gunicorn 워커를 사용할 때 느린 클라이언트를 버퍼링하는지 확인하는 경우 Nginx를 사용하는 것을 강력히 권장합니다. 다른 프록시 서버를 선택하는 경우 Gunicorn이 디닐 오브 서비스 공격에 취약해지지 않도록 느린 클라이언트를 버퍼링하도록 해야 합니다. 프록시가 제대로 작동하는지 확인하려면 Hey를 사용할 수 있습니다.

Nginx를 사용하는 빠른 클라이언트를 위한 예제 구성 파일:

nginx.conf:

worker_processes 1;

user nobody nogroup;
# 'user nobody nobody;' for systems with 'nobody' as a group instead
error_log  /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
  worker_connections 1024; # increase if you have lots of clients
  accept_mutex off; # set to 'on' if nginx worker_processes > 1
  # 'use epoll;' to enable for Linux 2.6+
  # 'use kqueue;' to enable for FreeBSD, OSX
}

http {
  include mime.types;
  # fallback in case we can't determine a type
  default_type application/octet-stream;
  access_log /var/log/nginx/access.log combined;
  sendfile on;

  upstream app_server {
    # fail_timeout=0 means we always retry an upstream even if it failed
    # to return a good HTTP response

    # for UNIX domain socket setups
    server unix:/tmp/gunicorn.sock fail_timeout=0;

    # for a TCP configuration
    # server 192.168.0.7:8000 fail_timeout=0;
  }

  server {
    # if no Host match, close the connection to prevent host spoofing
    listen 80 default_server;
    return 444;
  }

  server {
    # use 'listen 80 deferred;' for Linux
    # use 'listen 80 accept_filter=httpready;' for FreeBSD
    listen 80;
    client_max_body_size 4G;

    # set the correct host(s) for your site
    server_name example.com www.example.com;

    keepalive_timeout 5;

    # path for static files
    root /path/to/app/current/public;

    location / {
      # checks for static file, if not found proxy to app
      try_files $uri @proxy_to_app;
    }

    location @proxy_to_app {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header Host $http_host;
      # we don't want nginx trying to do something clever with
      # redirects, we set the Host: header above already.
      proxy_redirect off;
      proxy_pass http://app_server;
    }

    error_page 500 502 503 504 /500.html;
    location = /500.html {
      root /path/to/app/current/public;
    }
  }
}

스트리밍 요청/응답 또는 기타 고급 기능(Comet, Long polling, Web sockets 등)을 처리할 수 있도록 하려면 프록시 버퍼링을 비활성화해야 합니다. 이렇게하려면 비동기 워커 클래스 중 하나를 사용해야 합니다.

버퍼링을 비활성화하려면 location 블록에 proxy_buffering off;를 추가하면 됩니다.

...
location @proxy_to_app {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_buffering off;

    proxy_pass http://app_server;
}
...

로드 밸런서의 상태 검사 또는 응답을 기다리지 않고 연결을 닫는 Health Check와 같은 중단된 요청을 무시하려면 proxy_ignore_client_abort on;location 블록에 추가하면 됩니다.

...
proxy_ignore_client_abort on;
...

참고: proxy_ignore_client_abort의 기본값은 off입니다. 로그레벨이 debug로 설정된 경우 Nginx 로그에 오류 코드 499와 Gunicorn 로그에 Ignoring EPIPE가 표시될 수 있습니다.

Gunicorn에 프로토콜 정보를 전달하는 것이 좋습니다. 많은 웹 프레임워크는 이 정보를 사용하여 URL을 생성합니다. 이 정보가 없으면 응용 프로그램은 실수로 'https' 응답에서 'http' URL을 생성하여 혼합 콘텐츠 경고 또는 손상된 응용 프로그램을 생성할 수 있습니다. Nginx를 구성하여 적절한 헤더를 전달하려면 proxy_set_header 지시문을 location 블록에 추가하면 됩니다.

...
proxy_set_header X-Forwarded-Proto $scheme;
...

만약 Nginx를 Gunicorn과 다른 호스트에서 실행 중인 경우 Gunicorn에게 Nginx에서 보낸 X-Forwarded-* 헤더를 신뢰하도록 설정해야 합니다. 기본적으로 Gunicorn은 이러한 헤더를 로컬호스트에서 연결이 올 경우에만 신뢰합니다. 이것은 악성 클라이언트가 이러한 헤더를 위조하는 것을 방지하기 위한 것입니다.

$ gunicorn -w 3 --forwarded-allow-ips="10.170.3.217,10.170.3.220" test:app

Gunicorn 호스트가 외부 네트워크로부터의 모든 연결이 신뢰되는 프록시(예: Heroku)에서 오는 경우 이 값을 '*'로 설정할 수 있습니다. 이 값을 사용하는 것은 연결이 신

뢰되지 않은 프록시에서 Gunicorn으로 올 수 있기 때문에 잠재적으로 위험할 수 있습니다. 이 경우 응용 프로그램은 안전하지 않은 연결에서 SSL 전용 콘텐츠를 제공하도록 속일 수 있습니다.

Gunicorn 19에서는 REMOTE_ADDR 처리 방식에 대한 중요한 변경 사항이 소개되었습니다. Gunicorn 19 이전에는 신뢰할 수 있는 프록시에서 수신한 경우 X-Forwarded-For의 값으로 설정되었습니다. 그러나 이것은 RFC 3875와 일치하지 않았기 때문에 REMOTE_ADDR는 현재 사용자의 IP 주소가 아니라 프록시의 IP 주소로 설정됩니다.

프록시로부터 프록시된 요청을 무시하려면 access_log_format을 설정하는 등 액세스 로그가 X-Forwarded-For를 포함하는 형식으로 지정하면 됩니다. 예를 들어 다음 형식은 REMOTE_ADDR 대신 X-Forwarded-For을 사용합니다:

%({x-forwarded-for}i)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"

또한 Gunicorn을 UNIX 소켓이 아닌 TCP host:port 튜플에 바인딩하는 경우 REMOTE_ADDR는 완전히 비어 있을 것입니다.

Virtualenv 사용

Virtualenv에서 앱을 제공하려면 일반적으로 Virtualenv에 Gunicorn을 직접 설치하는 것이 가장 쉽습니다. 이렇게 하면 해당 Virtualenv에 Gunicorn 스크립트 집합이 생성되어 일반적으로 앱을 실행하는 데 사용할 수 있습니다.

Virtualenv가 설치되어 있다면 다음과 같이 수행할 수 있어야 합니다:

$ mkdir ~/venvs/
$ virtualenv ~/venvs/webapp
$ source ~/venvs/webapp/bin/activate
$ pip install gunicorn
$ deactivate

참고: Gunicorn을 Virtualenv에 강제로 설치하려면 pip에 -I 또는 --ignore-installed 옵션을 전달할 수 있습니다.

$ source ~/venvs/webapp/bin/activate
$ pip install -I gunicorn

모니터링

참고: 이 서비스 모니터를 사용할 때 Gunicorn의 데몬 모드를 활성화하지 않도록 주의하세요. 이 모니터는 실행할 프로세스가 모니터링해야 하는 프로세스일 것으로 예상합니다. 데몬 모드로 전환하면 모니터 서비스에서 모니터링되지 않는 프로세스가 포크-실행되며 일반적으로 모니터 서비스를 혼동시킵니다.

Gaffer

Gaffer를 사용하여 Gunicorn을 모니터링할 수 있습니다. 간단한 구성은 다음과 같습니다:

[process:gunicorn]
cmd = gunicorn -w 3 test:app
cwd = /path/to/project

그런 다음 Gaffer를 사용하여 Gunicorn을 쉽게 관리할 수 있습니다.

Procfile 사용

프로젝트에 Procfile을 만듭니다:

gunicorn = gunicorn -w 3 test:app

동시에 시작해야 하는 다른 응용 프로그램을 시작할 수도 있습니다.

그런 다음 Gaffer를 사용하여 Gunicorn 애플리케이션을 다음과 같이 시작할 수 있습니다:

gaffer start

gafferd가 실행 중인 경우 Procfile을 직접로드할 수도 있습니다.

gaffer load

모든 응용 프로그램은 gafferd에 의해 관리됩니다.

Runit

Gunicorn을 배포하는 인기있는 방법 중 하나는 runit으로 모니터링하도록 설정하는 것입니다. 다음은 예제 서비스 정의입니다:

#!/bin/sh

GUNICORN=/usr/local/bin/gunicorn
ROOT=/path/to/project
PID=/var/run/gunicorn.pid

APP=main:application

if [ -f $PID ]; then rm $PID; fi

cd $ROOT
exec $GUNICORN -c $ROOT/gunicorn.conf.py --pid=$PID $APP

이것을 /etc/sv/[app_name]/run로 저장하고 실행 가능하게 만듭니다 (chmod u+x /etc/sv/[app_name]/run). 그런 다음 ln -s /etc/sv/[app_name] /etc/service/[app_name]을 실행합니다. runit이 설치되어 있으면 심볼릭 링크를 생성하는 즉시 Gunicorn은 자동으로 시작됩니다.

자동으로 시작하지 않으면 문제 해결을 위해 스크립트를 직접 실행하십시오.

Supervisor

Gunicorn을 모니터링하고 제어하는 또 다른 유용한 도구는 Supervisor입니다. 간단한 구성은 다음과 같습니다:

[program:gunicorn]
command=/path/to/gunicorn main:application -c /path/to/gunicorn.conf.py
directory=/path/to/project
user=nobody
autostart=true
autorestart=true
redirect_stderr=true

Upstart

Upstart를 사용하여 Gunicorn을 실행하는 것은 간단합니다. 이 예에서는 가상 환경에서 "myapp" 앱을 실행합니다. 모든 오류는 /var/log/upstart/myapp.log로 이동합니다.

**/etc/init/myapp.conf

**:

description "myapp"

start on (filesystem)
stop on runlevel [016]

respawn
setuid nobody
setgid nogroup
chdir /path/to/app/directory

exec /path/to/virtualenv/bin/gunicorn myapp:app

Systemd

리눅스 시스템에서 점점 더 일반적인 도구인 Systemd를 사용하여 Unix 소켓을 만들어 Gunicorn 요청을 수신하도록 구성할 수 있습니다. Systemd는 이 소켓에서 수신 대기하고 트래픽에 응답하여 Gunicorn을 자동으로 시작합니다. 이어지는 섹션에서는 Nginx를 생성된 Unix 소켓으로 웹 트래픽을 전달하도록 구성하는 방법에 대한 지침이 포함되어 있습니다.

/etc/systemd/system/gunicorn.service:

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

[Service]
Type=notify
# the specific user that our service will run as
User=someuser
Group=someuser
# another option for an even more restricted service is
# DynamicUser=yes
# see http://0pointer.net/blog/dynamic-users-with-systemd.html
RuntimeDirectory=gunicorn
WorkingDirectory=/home/someuser/applicationroot
ExecStart=/usr/bin/gunicorn applicationname.wsgi
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true

[Install]
WantedBy=multi-user.target

/etc/systemd/system/gunicorn.socket:

[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/run/gunicorn.sock
# Our service won't need permissions for the socket, since it
# inherits the file descriptor by socket activation
# only the nginx daemon will need access to the socket
SocketUser=www-data
# Optionally restrict the socket permissions even more.
# SocketMode=600

[Install]
WantedBy=sockets.target

다음으로 소켓을 활성화하고 시작하십시오 (부팅 시 자동으로 시작됨):

systemctl enable --now gunicorn.socket

이제 nginx 데몬이 소켓에 연결할 수 있는지 확인해 봅니다. sudo -u www-data curl --unix-socket /run/gunicorn.sock http를 실행하면 Gunicorn 서비스가 자동으로 시작되며 브라우저에서 http://127.0.0.1:8000/을 방문하여 Nginx와 Gunicorn을 테스트할 수 있어야 합니다.

참고: systemd는 cgroups를 사용하여 서비스의 프로세스를 추적하므로 pid 파일이 필요하지 않습니다. 서비스의 주요 pid를 찾아야 하는 드문 경우에는 systemctl show --value -p MainPID gunicorn.service를 사용할 수 있지만 신호를 보내기만 하려면 systemctl kill -s HUP gunicorn.service와 같은 더 나은 옵션이 있습니다.

참고: www-data는 Debian의 기본 nginx 사용자이며, 다른 배포판은 다른 사용자(예: http 또는 nginx)를 사용합니다. 소켓 사용자와 sudo 명령에 대한 정보를 얻으려면 배포판을 확인하세요.

이제 웹 프록시를 새로 생성된 Gunicorn 소켓으로 트래픽을 보내도록 구성해야 합니다. 다음 내용을 포함하여 nginx.conf를 편집합니다.

/etc/nginx/nginx.conf:

user www-data;
...
http {
    server {
        listen          8000;
        server_name     127.0.0.1;
        location / {
            proxy_pass http://unix:/run/gunicorn.sock;
        }
    }
}
...

참고: 여기에서 사용된 listen 및 server_name은 로컬 머신에 대한 것으로 구성되어 있습니다. 프로덕션 서버에서는 아마도 포트 80에서 듣고 서버 이름으로 URL을 사용하게 될 것입니다.

이제 nginx 서비스를 부팅시 자동으로 시작하도록 활성화합니다.

systemctl enable nginx.service

재부팅하거나 다음 명령을 사용하여 Nginx를 시작합니다.

systemctl start nginx

이제 웹 브라우저에서 http://127.0.0.1:8000/을 방문하여 Nginx와 Gunicorn을 테스트할 수 있어야 합니다. Systemd가 이제 설정되었습니다.

로깅

로그를 구성하려면 구성 문서에 설명된 다양한 플래그를 사용하거나 로그 구성 파일을 생성하면 됩니다. logrotate 유틸리티를 사용하는 경우 로그를 회전시키려면 다음과 같이 USR1 신호를 보냅니다.

kill -USR1 $(cat /var/run/gunicorn.pid)

참고: LOGGING 사전을 재정의하면 disable_existing_loggers: False를 설정하여 Gunicorn 로깅에 영향을 미치지 않도록 주

의해야 합니다.

systemd 사용 시 주의 사항

Systemd를 사용하여 Gunicorn을 관리할 때 주의할 몇 가지 사항이 있습니다. systemd의 최대 실행 시간, 맥시멈 리스폰스 타임, PrivateTmp, 및 다른 설정을 주의깊게 검토하십시오. 이러한 설정을 특히 긴 초기화 또는 종료 시간을 가진 Gunicorn 워커를 사용하는 경우 조정해야 할 수 있습니다. systemd 로깅과 로그 레벨을 확인하고 문제 해결을 위해 해당 로그 파일을 검사하는 것도 중요합니다.

이 문서의 목표는 Gunicorn 애플리케이션을 Systemd와 함께 사용하는 데 필요한 정보를 제공하는 것입니다. 그러나 사용 중인 시스템 및 요구 사항에 따라 설정을 조정해야 할 수 있으므로 최종 구성은 시스템에 따라 달라질 수 있습니다.

0개의 댓글