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 {
}
}
}
```