PythonのWebアプリケーションサーバFlaskをWSGI経由接続(nginxあり・なし)、ダイレクト接続をdocker環境で試して見ました。
環境)Docker Desktop / Mac(arm64)
参考)https://qiita.com/hiren/items/4ed438303659125490b5
PythonプログラムとWSGIがあるAppと、NginxとWSGIに接続するための設定があるWebの二つのコンテナを作成します。
app/Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
FROM python:3.9.10-alpine RUN apk --update-cache add \ gcc \ g++ \ build-base \ linux-headers \ python3-dev \ pcre-dev RUN pip install --upgrade pip \ && pip install --no-cache-dir \ Flask \ uwsgi COPY hello.py ./ COPY uwsgi.ini ./ EXPOSE 3031 CMD uwsgi uwsgi.ini |
app/uwsgi.ini(nginxから接続されるソケットを設定)
1 2 3 4 5 6 |
[uwsgi] env=TZ=UTC-9 socket=0.0.0.0:3031 wsgi-file=./hello.py master=true callable=app |
app/hello.py(pythonコマンドで実行するときport:5000でリッスン)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
from flask import Flask, jsonify app = Flask(__name__) @app.route("/hello") def hello(): return jsonify({ "message": "Hello World!" }) if __name__ == '__main__': PORT = 5000 app.run( threaded=True, debug=True, port=PORT, host='0.0.0.0', ) |
web/Dockerfile
1 2 3 4 5 6 7 8 9 10 11 |
FROM nginx:alpine RUN apk --no-cache add tzdata && \ cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \ apk del tzdata COPY ["uwsgi.conf.template","/tmp/"] EXPOSE 80 ENTRYPOINT ["/bin/sh","-c"] CMD ["envsubst '$$SERVER_NAME $$RESOLVER $$HOST_NAME $$PORT' < /tmp/uwsgi.conf.template > /etc/nginx/conf.d/uwsgi.conf && nginx -g 'daemon off;'"] |
※envsubstコマンドにより、env_listの環境変数をconfに設定
web/uwsgi.conf.template
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
server { listen 80 default_server; server_name ${SERVER_NAME}; location / { include uwsgi_params; resolver ${RESOLVER}; set $url ${HOST_NAME}; uwsgi_pass $url:${PORT}; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } |
web/env_list
1 2 3 4 |
SERVER_NAME=127.0.0.1 RESOLVER=127.0.0.11 HOST_NAME=172.17.0.2 PORT=3031 |
※Dockerのリゾルバについては下記参考
https://stackoverflow.com/questions/35744650/docker-network-nginx-resolver
Appコンテナの作成と起動(172.17.0.2)
1 2 3 4 |
cd app docker build -t hello_flask -f Dockerfile . docker run -itd -p 3031:3031 hello_flask cd .. |
Webコンテナの作成と起動(172.17.0.3)
1 2 3 4 |
cd web docker build -t hello_flask/nginx -f Dockerfile . docker run -itd --env-file=env_list -p 80:80 hello_flask/nginx cd .. |
Webコンテナに入りコマンド実行
# curl http://172.17.0.3/hello
{“message”:”Hello World!”}
docker-composeでビルドしたケースについても確認(イメージは上記で作成済みのものを利用。確認内容は同じ)
docker-compose.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
version: '3' services: app: image: hello_flask networks: hello-app-net: ipv4_address: 172.26.0.2 ports: - "3031:3031" restart: always web: image: "hello_flask/nginx" networks: hello-app-net: ipv4_address: 172.26.0.3 ports: - "80:80" env_file: ./web/env_list restart: always networks: hello-app-net: driver: bridge ipam: driver: default config: - subnet: 172.26.0.0/24 |
web/env_list(IPアドレスは変更)
1 2 3 4 |
SERVER_NAME=127.0.0.1 RESOLVER=127.0.0.11 HOST_NAME=172.26.0.2 PORT=3031 |
同様にcurlでHello Worldを確認。
# curl http://172.26.0.3/hello
{“message”:”Hello World!”}
Nginxなしで、WSGIあり、なし(Flaskにダイレクト)の接続確認
app/uwsgi.ini
1 2 3 4 5 6 |
[uwsgi] env=TZ=UTC-9 http=0.0.0.0:9090 wsgi-file=./hello.py master=true callable=app |
URLの部分に使われているデコレータについても試してみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
def deco_html(func): def _wrap(*args, **kwargs): return '<html>' + func(*args, **kwargs) + '</html>' return _wrap def deco_body(func): def _wrap(*args, **kwargs): return '<body>' + func(*args, **kwargs) + '</body>' return _wrap def deco_tag(tag): def _deco_tag(func): def _wrap(*args, **kwargs): return '<' + tag + '>' + func(*args, **kwargs) + '</' + tag + '>' return _wrap return _deco_tag @deco_html @deco_body @deco_tag('h3') def ftest(str): return str + '!' print(ftest('Hello')) |
実行結果
1 |
<html><body><h3>Hello!</h3></body></html> |
参考)https://qiita.com/mtb_beta/items/d257519b018b8cd0cc2e
以上、メモでした。