docker + nginx + uwsgi + flask の構築

環境

software version
Ubuntu 18.04
Docker 18.09.0
docker-compose 1.23.2

ディレクトリ構成

┣ myServer
    ┣ app
        ┣ Dockerfile
        ┣ main.py
        ┣ requirements.txt
        ┣ uwsgi.ini
    ┣ docker-compose.yaml
    ┣ nginx
        ┣ Dockerfile
        ┣ nginx.conf

1. docker-compose.yamlの作成

version: "3"
services:

  uwsgi:
    # ビルドするDockerfileのでディレクトリ相対パス
    build: ./app
    # 指定したパスをコンテナにマウントする。"ホストのパス:コンテナのパス"となる
    volumes:
      - ./app:/var/www/
    # 解放するポートを指定。"ホスト:コンテナ"のマッピング となる
    ports:
      - "3031:3031"
    # コンテナ内の環境変数を指定する
    environment:
      TZ: "Asia/Tokyo"

  nginx:
    build: ./nginx
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      # nginxのログをホストOSの /tmp/nginx_log に出力する
      - /tmp/nginx_log:/var/log/nginx
    links:
      - uwsgi
    ports:
      - "4231:80"
    environment:
      TZ: "Asia/Tokyo"

2. app の設定

Dockerfile

# ベースイメージ
FROM python:3.6

RUN mkdir /var/www
# workdirの指定
WORKDIR /var/www

# 依存Pythonライブラリ一覧コピー
COPY requirements.txt ./

# 依存Pythonライブラリインストール
RUN pip install --no-cache-dir -r requirements.txt

CMD ["uwsgi","--ini","/var/www/uwsgi.ini"]
  • --no-cache-dir: キャッシュを無効にする

  • -r: requirements.txtに記載されているパッケージを一括インストールする

main.py

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run()

requirements.txt

Flask
uwsgi

uwsgi.ini

[uwsgi]
wsgi-file = main.py
callable = app
master = true
processes = 1
socket = :3031
chmod-socket = 666
vacuum = true
die-on-term = true
py-autoreload = 1
  • wsgi-file: Flaskアプリケーションファイル
  • callable: このファイル内のFlaskアプリケーションオブジェクトの名前
  • master: オプションを指定すると、アプリケーションサーバーとして起動したとき、ソケットを閉じずに再起動したりできるようにします。
  • processes: uWSGIの最大ワーカープロセス数
  • socket: WEBサーバとWEBアプリケーションをつなぐポートもしくはUNIXソケットファイルを指定する
  • chmod-socket: UNIXソケットのファイルパーミッション。指定が無い場合はデフォルトで 666 になる
  • vacuum: プロセス終了時に生成されたすべてのファイル/ソケットを削除する
  • die-on-term: Upstartでプロセスが期待通りに処理されるために設定。uWSGIはプロセスを再ロードせずに強制終了します。
  • py-autoreload: コードの自動リロード機能。チェックサイクルごとにモジュールツリー全体をスキャンします。

余談

filesocket (/file/path/uwsgi.sock) を使った nginx -> uWSGI の通信の確立の仕方が分からなかった。

試したこと

  • server unix:///tmp/uwsgi.sock
  • server uwsgi:/tmp/uwsgi.sock

参考

3. nginx の設定

Dockerfile

FROM nginx
CMD ["nginx", "-g", "daemon off;", "-c", "/etc/nginx/nginx.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        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    upstream uwsgi {
        server uwsgi:3031;
    }

    server {
        listen 80;
        charset utf-8;

        location / {
            include uwsgi_params;
            uwsgi_pass uwsgi;
        }

    }
}

4. dockerコンテナのビルドと実行

docker-compose.yaml と Dockerfile の内容に従ってコンテナをビルドする。

$ sudo docker-compose build
Building uwsgi
Step 1/6 : FROM python:3.6
 ---> 1ec4d11819ad
Step 2/6 : RUN mkdir /var/www
 ---> Using cache
 ---> 0cba8c49bdd8
Step 3/6 : WORKDIR /var/www
 ---> Using cache
 ---> 8d210dacf801
Step 4/6 : COPY requirements.txt ./
 ---> Using cache
 ---> 21c64fe227f5
Step 5/6 : RUN pip install --no-cache-dir -r requirements.txt
 ---> Using cache
 ---> 2836363b7b84
Step 6/6 : CMD ["uwsgi","--ini","/var/www/uwsgi.ini"]
 ---> Using cache
 ---> 1f55d63545b3
Successfully built 1f55d63545b3
Successfully tagged myserver_uwsgi:latest
Building nginx
Step 1/2 : FROM nginx
 ---> 568c4670fa80
Step 2/2 : CMD ["nginx", "-g", "daemon off;", "-c", "/etc/nginx/nginx.conf"]
 ---> Using cache
 ---> ac6b828f2312
Successfully built ac6b828f2312
Successfully tagged myserver_nginx:latest
$

docker-compose.yaml のコンテナを実行する。

$ sudo docker-compose up -d
Creating network "myserver_default" with the default driver
Creating myserver_uwsgi_1 ... done
Creating myserver_nginx_1 ... done
$

-d: バックグラウンドで実行する

実行中のdockerコンテナのプロセスを確認。

$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
28901248f4c9        myserver_nginx      "nginx -g 'daemon of…"   53 seconds ago      Up 52 seconds       0.0.0.0:4231->80/tcp     myserver_nginx_1
860cd0fe644e        myserver_uwsgi      "uwsgi --ini /var/ww…"   54 seconds ago      Up 52 seconds       0.0.0.0:3031->3031/tcp   myserver_uwsgi_1
$

nginx にアクセスして検証する。

f:id:dafukui:20181220145051p:plain

表示できた。

$ cat /tmp/nginx_log/access.log
xxx.xx.73.51 - - [20/Dec/2018:14:49:10 +0900] "GET / HTTP/1.1" 200 12 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 OPR/57.0.3098.91" "-"
$

アクセスログもホストOSで確認することができた。