docker-composeでresponderを動かしてみた

# 概要
responderの超簡単な動作環境を作成しました。

# 環境
- Docker 18.09.1
- docker-compose 1.23.2
- Python 3.7
- responder 1.2.0

# 手順
## ディレクトリ構成
ディレクトリ構成は非常にシンプル

```
root/
　├ app/
　│ ├ Dockerfile
　│ ├ requirements.txt
　│ ├ app/
　│　 └ sample.py
　└ nginx/
  　├ conf.d/
  　│　└ app.conf
  　└ nginx.conf/
```

各種ファイルの説明は順次行います。

## docker-compose.yml
docker-compose.ymlを記載します。
今回は最小構成ということで、dbも無いシンプルな構成です。

```yml:docker-compose.yml
version: '3.4'

services:
  nginx_proxy:
    hostname: nginx_proxy
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - "./nginx/nginx.conf:/etc/nginx/nginx.conf"
      - "./nginx/conf.d:/etc/nginx/conf.d"
  responder:
    hostname: responder
    build:
      context: "./responder"
    image: "responder"
    expose:
      - "80"
    command: /bin/sh -c "python /root/app/sample.py"
    volumes:
      - "./responder/app:/root/app"
```

## Dockerfile(responder)
responderを可動させるイメージを作成します。
とは言ってもほぼPython3のイメージです。
ASGIはgunicornとかもインストールが必要なのかと思いましたが、uvicornを使用するそうなので不要とのこと。
後々はDB連携もさせたいですね。

```Dockerfile:Dockerfile
FROM python:3.7

MAINTAINER neight

ENV PYTHONUNBUFFERED 1
COPY requirements.txt /opt/app/
RUN pip install --no-cache-dir -r /opt/app/requirements.txt

WORKDIR /root
```

```text:requirements.txt
responder==1.2.0
```

## nginx
nginxを使用してリバースプロキシを行います。
このあたりも特に変わったことはしていないです。

```nginx:nginx.conf
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


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

    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;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}
```

```nginx:app.conf
server {
    listen 80;
    server_name  localhost;

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $http_host;
        proxy_pass http://responder/;
    }
}
```

## sample code
responderの簡単なサンプルコードです。
公式の説明との違いはIPとPortの指定を行っています。
デフォルトだと127.0.0.1:5042となります。

```Python:sample.py
import responder

api = responder.API()

@api.route("/")
def hello_world(req, resp, *, hoge):
    resp.text = "hello, world!"

if __name__ == '__main__':
    # ここだけ違う
    api.run(address='0.0.0.0', port=80)
```

# 起動
起動はdocker-composeを使用してupすれば終わりですね。

```bash:bash
$ docker-compose up -d
```

この状態でブラウザより***localhost***にアクセスすれば確認できると思います。
お疲れ様でした。

# responderの感想
自分はPythonのフレームワークはDjangoしか使用したことがなかったので、これを機に***flask***と***falcom***も使用してみました。
4つのフレームワークを比較した感想としては、

- DjangoはWebサイトを作成するのに特化しているのに対し、他3つはJSONを返す様なAPI作成に向いている(気がする)
- フレームワーク全体が非常にシンプル（ミニマム）である
- responderは書き方に統一感がある、かつ、flascとfalconの良いところを取り込んでいる(作者の意図通り？)
- responderを使用する際は、responderについて調べるというよりも構成ライブラリについて調べるという流れになりそう
- 非同期処理が簡単にかけるのはresponderの強力な長所

他にも、GraphQLも簡単に取り扱えるそうですが、筆者は詳しくないので割愛。

# まとめ
responder良いですね。
筆者はPython初心者でシンタックスシュガーあたりで少し戸惑いましたが、それ以外はシンプルでわかりやすく簡潔に書けるのが非常に好印象です。
Pythonのフレームワーク戦争で勝ち残ってほしい一品です。