LoginSignup
3
1

More than 5 years have passed since last update.

Amazon Linux で Falcon + Gunicorn + Supervisord + nginx を設定する

Last updated at Posted at 2018-01-31

AWS EC2 を使用してクラウド上にREST-APIを用意してあれこれしたいと思った時、最速で実装できる様にメモを残します。
Pythonは2.7系です。

インストールは以下

$ sudo yum update
$ sudo yum install nginx
$ sudo yum --enablerepo=epel install supervisor
$ sudo service supervisord start
$ pip install gunicorn
$ pip install falcon

nginxの自動起動を設定

$ sudo systemctl enable nginx
$ sudo systemctl start nginx
$ sudo chkconfig nginx on

まず Falcon で REST-API のサンプルコードを実装します。

これはそのまま、 python ajax.py で動作します。外部からREST-APIとして動きます。
これをデーモン化してサーバ起動時に自動で動く様にします。

cd
/home/ec2-user
vim ajax.py

以下のサンプルコードでは、ajaxの1番目・2番目のアクセスURLに対してGETパラメータで、colorを指定します。colorの値は、 green_on,red_on の2種類としています。

値をセットする例としては、1番目にgreen_on、2番目にred_onを指定したい場合は、以下の様に指定します。

http://サーバドメイン/ajax/1/?color=green_on
http://サーバドメイン/ajax/2/?color=red_on

次に値をゲットする例としては、1番目、2番目は、以下の様に指定します。すると、セットした値がjsonで帰ってきます。

http://サーバドメイン/ajax/1/
{
result: "green_on"
}
http://サーバドメイン/ajax/2/
{
result: "red_on"
}

この様な動作を行うソースが以下となります。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
##
## REST API Sample
##
import json
import falcon
from datetime import datetime

##
## route 指定パラメータとGETパラメータの混合サンプル
##
class HelloResource(object):
    def on_get(self, req, resp, name):
        param = req.get_param('color')
        if (param):
            ## getパラメータがあれば保存処理
            f = open('/tmp/ajax'+name+'.txt','w')
            f.write(param)
            f.close()
            resp.body = '{"result": "' + param + '"}'
        else:
            ## パラメータ無しなら保存したデータを返す
            f = open('/tmp/ajax'+name+'.txt','r')
            ret = f.read()
            resp.body = '{"result": "' + ret + '"}'
        resp.status = falcon.HTTP_200

app = falcon.API()
app.add_route("/ajax/{name}", HelloResource())

if __name__ == "__main__":
    from wsgiref import simple_server
    httpd = simple_server.make_server("0.0.0.0", 80, app)
    httpd.serve_forever()

Supervisord の起動設定を記述します。

Supervisord はコマンドをサーバプロセス化してくれます。が、それ自体のデーモン記述が無いので以下の様に書きます。

cd /etc/init.d
vim supervisord 
#!/bin/bash
. /etc/rc.d/init.d/functions

RETVAL=0

start() {
        echo -n $"Starting supervisord: "
        daemon supervisord
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ] && touch /var/lock/subsys/supervisord
}

stop() {
        echo -n $"Stopping supervisord: "
        killproc supervisord
        echo
        [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/supervisord
}

restart() {
        stop
        start
}

case "$1" in
  start)
        start
        ;;
  stop) 
        stop
        ;;
  restart|force-reload|reload)
        restart
        ;;
  condrestart)
        [ -f /var/lock/subsys/supervisord ] && restart
        ;;
  status)
        status supervisord
        RETVAL=$?
        ;;
  *)
        echo $"Usage: $0 {start|stop|status|restart|reload|force-reload|condrestart}"
        exit 1
esac

exit $RETVAL

Supervisordの設定を記述します。

デーモン化した後に設定ファイルも無いので記述します。

[etc]# vim supervisord.conf

[unix_http_server]
file=/tmp/supervisor.sock   ; the path to the socket file

[supervisord]
logfile=/tmp/supervisord.log ; main log file; default $CWD/supervisord.log
logfile_maxbytes=50MB        ; max main logfile bytes b4 rotation; default 50MB
logfile_backups=10           ; # of main logfile backups; 0 means none, default 10
loglevel=info                ; log level; default info; others: debug,warn,trace
pidfile=/tmp/supervisord.pid ; supervisord pidfile; default supervisord.pid
nodaemon=false               ; start in foreground if true; default false
minfds=1024                  ; min. avail startup file descriptors; default 1024
minprocs=200                 ; min. avail process descriptors;default 200

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL  for a unix socket

[include]
files = /etc/supervisord.d/*.conf

Supervisor のアプリ毎の設定を記述します。

目的のアプリについての設定ファイルを記述します。pythonダイレクト指定もコメントアウトで例示します。

mkdir /etc/supervisord.d
cd /etc/supervisord.d

[supervisord.d]# vim falcon.conf

[program:ajax]
# pythonをダイレクト指定する(gunicorn,nginx不使用)場合は以下
# command=/root/.pyenv/versions/2.7.14/bin/python /home/ec2-user/ajax.py
command=/root/.pyenv/shims/python /home/ec2-user/ajax.py
# gunicornで起動する場合は以下
command=/root/.pyenv/versions/2.7.14/bin/gunicorn ajax:app --config /home/ec2-user/guniconf.py
directory=/home/ec2-user/
user=root

gunicorn のコンフィグファイルを記述します。

[ec2-user]# vim guniconf.py

import multiprocessing

# Server Socket
bind = 'unix:/tmp/gunicorn_ajax.sock'
backlog = 2048

# Worker Processes
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = 'sync'
worker_connections = 1000
max_requests = 0
timeout = 30
keepalive = 2
debug = True
spew = False

# Logging
errorlog = '/var/log/gunicorn_error.log'
loglevel = 'debug'
accesslog = '/var/log/gunicorn_access.log'

# Process Name
proc_name = 'ajax'

nginx の設定を記述します。

[nginx]# vim nginx.conf

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    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  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

    index   index.html index.htm;

    upstream app_server {
        server unix:/tmp/gunicorn_ajax.sock;
    }

    server {
#        listen       80 default_server;
#        listen       [::]:80 default_server;
#        server_name  localhost;
#        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
            # 以下4行を追加
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_redirect off;
            proxy_pass   http://app_server;
        }

        # redirect server error pages to the static page /40x.html
        #
        error_page 404 /404.html;
            location = /40x.html {
        }

        # redirect server error pages to the static page /50x.html
        #
        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }
}
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1