DockerでPython+uWSGI+Nginxの環境を作成

#DockerでPython3.5で作成したWebアプリケーションの検証用環境を作成
PythonでWebアプリケーションを作成することはほんとんどなかった。ノンブロッキングI/Oの（`node.js`や`Golang`との比較検証等を考慮した）動作検証をする際にWebアプリケーションとして用意したかったので、その際、`Docker for Mac`で簡単な環境を構築したので備忘録として記載。
`Docker Compose`でPython3.5+uWSGI+Nginxの動作環境用のコンテナを用意した。
余談だが、uWSGIは「ウエスギ」という読み方が一般化しているようだ。「ユーウイスキー」と読んでいた。

##Docker for Macのインストール
`Docker for Mac`を利用した。[ここ](https://docs.docker.com/docker-for-mac/install/)から`Docker for Mac`をダウンロードして、Macにインストールする。

##Docker Composeの設定ファイルの用意
###ディレクトリ構成
下図が今回のディレクトリ構成。

<img width="274" alt="スクリーンショット 2017-06-28 18.45.27.png" src="https://qiita-image-store.s3.amazonaws.com/0/135559/e3442a78-949b-b3a1-fdc2-a1d4b7cfeffb.png">

###docker-compose.yml
コンテナは1つだけ、コンテナ起動後、ローカルからはポート番号8080でhttpアクセスする。

```yaml:docker_python/docker-compose.yml
version: "2"
services:
  # nginx
  nginx-python:
    build: ./nginx-python
    ports:
      - "8080:80"
    volumes:
      - ./app/:/var/www/html/app/
    environment:
      TZ: "Asia/Tokyo"
```

###Webサーバの構成
CentOSにPython3.5、uWSGI、Nginxをインストールする。

####Dockerfile
CentOS6.8をベースにした。

```docker:docker_python/nginx-python/Dockerfile
FROM centos:6.8

ADD ./conf/nginx.repo /etc/yum.repos.d/

# nginx & python
RUN yum localinstall -y http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
RUN yum install -y https://centos6.iuscommunity.org/ius-release.rpm
RUN yum install -y nginx-1.10.1
RUN yum install -y make gcc
RUN yum install -y libxml2-devel
RUN yum install -y python35u python35u-libs python35u-devel python35u-pip
RUN yum clean all

RUN ln -s /usr/bin/python3.5 /usr/bin/python3
RUN unlink /usr/bin/python
RUN ln -s /usr/bin/python3 /usr/bin/python
RUN ln -s /usr/bin/pip3.5 /usr/bin/pip

RUN pip install uwsgi

# setting nginx
COPY conf/nginx.conf /etc/nginx/nginx.conf
ADD conf/default.conf /etc/nginx/conf.d/default.conf
RUN usermod -u 1000 nginx

EXPOSE 80

ADD ./conf/start.sh /tmp/start.sh

CMD /bin/sh /tmp/start.sh
```

####追加ファイル
```ini:docker_python/nginx-python/conf/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/6/$basearch/
gpgcheck=0
enabled=1
```

```nginx:docker_python/nginx-python/conf/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        off;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

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

```nginx:docker_python/nginx-python/conf/default.conf
server {
    listen 80 default;
    server_name _;

    location / {
        include uwsgi_params;
        uwsgi_pass localhost:8080;
    }

    location = /favicon.ico {
        empty_gif;
    }
}
```

```shell:docker_python/nginx-python/conf/start.sh
#!/bin/sh

/etc/init.d/nginx start
cd /var/www/html/app
chmod -R 777 .
uwsgi --ini uwsgi.ini
```

###アプリケーション
アプリケーション用のディレクトリを用意し、PythonファイルとuWSGIの設定ファイルを配置。コンテナ起動時にマウントされる。
`uwsgi.log`と`uwsgi.pid`は空ファイル（`touch`コマンド）で用意。

```py:docker_python/app/webapp.py
def application(environ, start_response):
    start_response('200 OK', [('Content-Type','text/html')])
    return [b"Hello World"]
```

```ini:docker_python/app/uwsgi.ini
[uwsgi]
master = True
socket = localhost:8080
wsgi-file = webapp.py
stats = localhost:8181
logto = uwsgi.log
pidfile = uwsgi.pid
```

空ファイルを作成。

```shell-session
$ touch docker_python/app/uwsgi.log
$ touch docker_python/app/uwsgi.pid
```

##コンテナの操作
###コンテナのビルドと起動
ビルドと起動両方を実施する場合（`-d`オプションを指定するとバックグラウンドで起動）：

```shell-session
$ docker-compose up --build
```

ビルドのみの場合：

```shell-session
$ docker-compose build
```

起動のみの場合（`-d`オプションを指定するとバックグラウンドで起動）：

```shell-session
$ docker-compose up
```

###コンテナIDの確認
コンテナのビルドが正常に完了した後で実行。

```shell-session
$ docker ps -a
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS                     PORTS                           NAMES
0be4855e99df        dockerpython_nginx-python   "/bin/sh -c '/bin/..."   2 hours ago         Up 2 hours                 0.0.0.0:8088->80/tcp            dockerpython_nginx-python_1
```

###コンテナの停止・開始
上記の”コンテナIDの確認”を例にすると`CONTAINER_ID`に`0be4855e99df`を指定。

停止する場合：

```shell-session
$ docker stop 0be4855e99df
```

開始する場合：

```shell-session
$ docker start 0be4855e99df
```

再起動する場合：

```shell-session
$ docker restart 0be4855e99df
```

###起動しているコンテナにログイン
コンテナに入ることができ、サーバの状態等が確認できる。

```shell-session
$ docker exec -it 0be4855e99df bash
```

###コンテナの削除
コンテナが停止している状態であれば、削除可能。

```shell-session
$docker rm 0be4855e99df
```

##デモ
コンテナを起動して、`http://localhost:8080`にブラウザでアクセスすると、"Hello World"が表示される。