search
LoginSignup
3

More than 1 year has passed since last update.

posted at

updated at

Organization

Unix Domain SocketによるuWSGIとNginxの通信

本記事は東京学芸大学 櫨山研究室 Advent Calendar 2020の16日目の記事になります.

はじめに

本記事はPythonのWebフレームワークであるflaskで作成したアプリケーションをuWSGIサーバを使って動作させる内容を通してUnix Domain Socket通信について学ぶという内容になります.

Unix Domain Socketとは

Unix Domain SocketはPOSIX系のOSに搭載されている機能でTCP/UDPによるソケット通信とは異なり,カーネル内部で完結する高速なネットワークインタフェースを作成します.
カーネル内部で完結するため外部のコンピュータとは接続することはできません.

flaskのアプリケーションの作成

エンドポイント/でアクセスしてHello, Worldとだけ返す簡単なアプリケーションを作成します.

app.py
from flask import Flask
app = Flask(__name__)

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

if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)

そして以下のコマンドを実行することでアプリケーションが起動します.
この時,起動には開発用の組み込みサーバが立ち上がります.

python app.py

http://localhost:5000/
にアクセスしてHello, Worldと表示されれば成功です.

uWSGIを使って動かす

先ほどの例では開発用の組み込みサーバを使用していました.
PythonにはアプリケーションサーバとしてuWSGIがあります.
uWSGIではUnix Domain Socketでの通信がサポートされています.

まずはuWSGIを使って先ほどのアプリケーションを動作させてみます.

pip install uWSGI
app.py
from flask import Flask
app = Flask(__name__)

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

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

uWSGIで先ほどのアプリケーションを起動するには以下のコマンドを入力します.

uwsgi --http=0.0.0.0:4000 --wsgi-file=app.py --callable=app

http://localhost:4000/
にアクセスしてHello, Worldと表示されれば成功です.

uwsgi.iniという設定ファイルを作成することでより短いコマンドで起動することも可能です.

uwsgi.ini
[uwsgi]
wsgi-file=app.py
callable=app

http=0.0.0.0:4000
uwsgi uwsgi.ini

Nginxの導入

さてここからが本題のUnix Domina Socketでのアクセスです.これまでの起動方法ではHTTP通信(TCPソケット)でのアクセスでした.

実際に運用する場合は同一サーバで複数のアプリケーションを動作させることを考慮しNginxをリバースプロキシとする場合が多いでしょう.
この時,同一サーバ内の通信であればUnix Domain Socketを使ってHTTP通信よりも高速にアクセスすることができます.

今回は便宜的にDockerを用いて動作させてみます.

uwsgi.iniの編集

uwsgi.iniを編集してUnix Domain Socketで通信するようにします.
Unix Domain Socketではファイルシステム上の指定した位置にソケットファイルができます.
クライアントはソケットファイルにアクセスを試みます.
つまりIPアドレスとポート番号ではなくファイルパスによって通信相手を決めます.

今回は/var/app/app.sockというソケットファイルを作成するようにします.

uwsgi.ini
[uwsgi]
wsgi-file=app.py
callable=app

http=0.0.0.0:4000
# 追記
socket=/var/app/app.sock

Docker環境の準備

まずは先ほどのflaskのアプリケーションを動作させる環境を用意するDockerfileを用意します.

Dockerfile
FROM python:3.7

ENV LANG C.UTF-8
ENV TZ Asia/Tokyo

WORKDIR /app
ADD app.py ./
ADD uwsgi.ini ./

RUN pip install flask uWSGI

CMD ["uwsgi", "uwsgi.ini"]

nginxも動かしたいのでdocker-compose.ymlを用意します.

docker-compose.yml
version: '3.7'

services:

  app:
    container_name: uds_app
    build:
      context: .
      dockerfile: ./Dockerfile
    volumes:
      - ./tmp/:/var/app/
    tty: true

  nginx:
    container_name: uds_nginx
    image: nginx
    volumes:
      - ./tmp:/var/app/
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
    ports:
      - 80:80
    tty: true

ここで重要なのはホストマシン上の./tmpディレクトリをflaskアプリケーションコンテナとNginxコンテナの両方と共有していることです.

  1. ホストマシン上の./tmpディレクトリ ←→ flaskアプリケーションコンテナの/var/appディレクトリ
  2. ホストマシン上の./tmpディレクトリ ←→ Nginxコンテナの/var/appディレクトリ

これによりNginxコンテナからもソケットファイルを参照できます.

Nginxの設定ファイルを記述し/へのアクセスをflaskのアプリケーションを呼び出すようにします.

nginx.conf
server {
    listen       80 default_server;
    listen       [::]:80 default_server;
    server_name  _;

    location / {
    include uwsgi_params;
    uwsgi_pass unix:/var/app/app.sock;
    }

    error_page 404 /404.html;
    location = /404.html {
    }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    }
}

docker-compose upコマンドで起動してみましょう.

docker-compose up

http://localhost/
にアクセスして先ほどと同様にHello, Worldの文字列が確認できれば成功です.

おわりに

本記事ではflaskで作成したアプリケーションにリバースプロキシのNginxからUnix Domain Socketで通信するということを扱いました.

TCP通信と異なりファイルパスによって通信相手を決めるという部分が伝わればと思います.
また余裕があれば性能も調査してきたいですね.

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
3