LoginSignup
12
12

More than 3 years have passed since last update.

NginxとGunicornの接続をソケットからHTTPに変更した

Last updated at Posted at 2019-10-27

あらまし

Django + MySQL で開発したアプリケーションの本稼働用の環境を、Ansible を使って Amazon EC2 上に構成しました。
前回の投稿では Nginx と Gunicorn を UNIX ドメインソケットで接続していましたが、これを HTTP 接続に変更しました。

UNIX ドメインソケット接続

これが変更前の構成です。

aws-network-wsgi_all.png

なぜソケットで接続したのか

本来のソケットのメリットは通信が高速であることです。以下のリンクで学習しました。
Unixドメインソケット - Goならわかるシステムプログラミング ― 第9回
調べなきゃ寝れない!と調べたら余計に寝れなくなったソケットの話

しかしソケット接続を選んだ最大の理由は、単純に Gunicorn の公式ドキュメントと Udemy のコース内容に倣ったためでした。

(1) Gunicorn の公式ドキュメント

参考: Deploying Gunicorn (Systemd): http://docs.gunicorn.org/en/latest/deploy.html#systemd

gunicorn-settings.png

(2) Udemy のコース

このコースを購入して学習しました。
「【徹底的に解説!】Djangoの基礎をマスターして、3つのアプリを作ろう!」

HTTP接続

しかしその後、ソケットを削除して下図の構成に変更しました。
(左上の /run/gunicorn ディレクトリは PID ファイルの保存用なので、接続方式とは無関係です)

aws-network-wsgi_http.png

なぜHTTP接続に変更したのか

(1) 構成変更の自由度

  • Nginx と Gunicorn を別インスタンスに配置することが可能になります(ソケットは同一インスタンス内接続のみ)
  • Nginx と Gunicorn の関係を 1対多にすることが可能になります
  • Nginx を ELB(Elastic Load Balancing)などと交換することが可能になります

(2) トラブルシューティングのしやすさ

図のようにクライアントから直接 Gunicorn に接続できるので、問題発生時に原因箇所の切り分けをしやすくなります。また gunicorn.socket への依存がなくなるので、問題の要因自体が減ります。

Ansible Playbookの変更

前回作成した Playbook の Djangoロール から ソケットのユニットファイルをテンプレートから生成するタスク を丸ごと削除して、残った部分を以下のように変更しました。

varsファイル

前回: varsファイル
以下の変数を追加しました。

  • gunicorn_allow_ipaddrは Gunicorn から見た Nginx の IPアドレスで、127.0.0.1 は同一インスタンス内からの接続のみを許可する設定です。0.0.0.0 にすればどこからでも接続できるようになります。
  • gunicorn_listen_ipaddrは Nginx から見た Gunicorn の IPアドレスです。
  • gunicorn_listen_portは Nginx から見た Gunicorn のポートです。
inventories/development/group_vars/all.yml
gunicorn_allowed_ipaddr: '127.0.0.1'  # 開発中は 0.0.0.0 でOK
gunicorn_listen_ipaddr: '127.0.0.1'
gunicorn_listen_port: 8000

Gunicornサービスのユニットファイル

前回: Gunicornサービスのユニットファイルをテンプレートから生成して起動するタスク

ユニットファイルのテンプレートを以下のように変更しました。

  • ソケットへの依存がなくなったので、Requires=gunicorn.socketを削除しました。
  • ExecStart--bindの値をソケットから IPアドレス:ポートに変更し、--bind 127.0.0.1:8000としました。
roles/django/templates/gunicorn.service.j2
[Unit]
Description=gunicorn daemon
After=network.target

[Service]
PIDFile={{ gunicorn_run_dir }}/pid
User={{ service_user }}
Group={{ service_group }}
WorkingDirectory={{ django_project_base_dir }}
ExecStart=/usr/local/bin/gunicorn --pid {{ gunicorn_run_dir }}/pid   \
          --bind {{ gunicorn_allowed_ipaddr }}:{{ gunicorn_listen_port }} \
          {{ django_project_name }}.wsgi
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Nginxの仮想ホスト設定ファイル

前回:Nginxの仮想ホスト設定ファイルをテンプレートから生成するタスク

proxy_passで指定する転送先をソケットから HTTP の IPアドレス:ポートに変更し、proxy_pass http://127.0.0.1:8000;としました。

roles/django/templates/nginx.conf.j2
server {
    listen       80;
    server_name  {{ ansible_host }};
    server_tokens off;

    location / {
        proxy_pass http://{{ gunicorn_listen_ipaddr }}:{{ gunicorn_listen_port }};  # ソケットから変更
        proxy_set_header Host               $host;
        proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host   $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Real-IP          $remote_addr;
    }

    location /static {
        alias {{ django_project_base_dir }}/static;
    }
}

以上で Nginx と Gunicorn の接続をソケットからHTTPに変更することができました。

参考

記事一覧

12
12
2

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
  3. You can use dark theme
What you can do with signing up
12
12