Nginx + Gunicorn + Flaskの環境構築を行った際のメモ。
流れは、Client => Nginx => Gunicorn => Flask
NginxとGunicornの接続については以下のサイトが参考になった。
Nginx + Gunicorn + Django + Aurora (MySQL) の本番環境をAnsible Playbookで構成する - Qiita
NginxとGunicornの接続をソケットからHTTPに変更した - Qiita
Gunicorn用のSystemdソケットとサービスファイルの作成 - Qiita
Socket接続とHTTP接続があるが、
NginxとGunicornを別々のサーバ上に分けて設定しない限りは、Socket接続のほうが早いので、Socket接続を採用する。
Nginxの設定
やり方は省略するが、nginx用のユーザである「nginx」ユーザを作成する。
そして以下のページと同じ設定を行い、
upstreamの箇所を以下のように変更するだけ。
upstream app_server { server unix:/run/gunicorn/socket fail_timeout=0; }
Gunicornの設定
Pythonの環境は以下のページを参考に「pyenv + pipenv」で構築
thoames.hatenadiary.jp
defaults/main.yml (※gunicorn_app_pathは任意)
--- gunicorn_version: "20.0.4" gunicorn_bin: "{{ working_direcory }}/.venv/bin/gunicorn" gunicorn_app_name: "gunicorn" gunicorn_app_path: "run:app" # app module in run.py gunicorn_run_dir: "/run/gunicorn" gunicorn_config_dir: "/etc/gunicorn" gunicorn_socket: "gunicorn.socket" gunicorn_bind: "unix:/run/{{gunicorn_app_name}}/socket" gunicorn_user: "{{ admin_user }}" gunicorn_dynamic_workers: False gunicorn_cpu_coefficient: 2 gunicorn_workers: 1 # [Log]: use nginx log functions gunicorn_loglevel: False gunicorn_errorlog: False gunicorn_accesslog: False # gunicorn_loglevel: "info" # gunicorn_errorlog: "/var/log/gunicorn/error.log" # gunicorn_accesslog: "/var/log/gunicorn/access.log" gunicorn_reload: False # only for 'development' gunicorn_timeout: 600 # because of scraping
tasks/main.yml
--- - name: Check exist pipenv command shell: type pipenv register: exist_pipenv failed_when: false tags: gunicorn - name: Install Gunicorn shell: bash -lc "pipenv install gunicorn=={{ gunicorn_version }}" args: chdir: "{{ working_direcory }}" when: exist_pipenv is success tags: gunicorn - name: Make gunicorn config directory file: path={{ gunicorn_config_dir }} state=directory tags: [gunicorn, gunicorn_config] - name: Configure gunicorn template: src=gunicorn.py.j2 dest={{ gunicorn_config_dir }}/{{ gunicorn_app_name }}.py notify: - restart socket - restart gunicorn tags: [gunicorn, gunicorn_config] - name: Configure gunicorn socket template: src=gunicorn.socket.j2 dest=/etc/systemd/system/{{ gunicorn_socket }} notify: - restart socket - restart gunicorn tags: [gunicorn, gunicorn_config] - name: Configure systemd service template: src=systemd.conf.j2 dest=/etc/systemd/system/{{ gunicorn_app_name }}.service mode="0755" notify: - restart socket - restart gunicorn tags: [gunicorn, gunicorn_config] - name: Enable gunicorn service service: name="{{ gunicorn_app_name }}.service" enabled=yes tags: [gunicorn, gunicorn_config]
handlers/main.yml
--- - name: restart gunicorn service: name={{ gunicorn_app_name }} state=restarted daemon_reload=yes - name: restart socket systemd: name={{gunicorn_app_name}}.socket enabled=yes state=restarted daemon_reload=yes
gunicorn.socket
[Unit] Description=gunicorn socket [Socket] ListenStream={{ gunicorn_run_dir }}/socket [Install] WantedBy=sockets.target
gunicorn.py (gunicorn用の設定ファイル)
import multiprocessing bind = '{{ gunicorn_bind }}' timeout = {{gunicorn_timeout}} {% if gunicorn_loglevel %} loglevel = '{{ gunicorn_loglevel }}' {% endif %} {% if gunicorn_accesslog %} accesslog = '{{ gunicorn_accesslog }}' {% endif %} {% if gunicorn_errorlog %} errorlog = '{{ gunicorn_errorlog }}' {% endif %} reload = {% if gunicorn_reload %}True{% else %}False{% endif %} {% if gunicorn_dynamic_workers %} workers = ({{gunicorn_cpu_coefficient}} * multiprocessing.cpu_count()) + 1 {% else %} workers = {{gunicorn_workers}} {% endif %}
gunicorn.service (systemd用のサービス設定)
[Unit] Description = {{ gunicorn_app_name }} Requires = {{ gunicorn_socket }} After = network.target [Service] PermissionsStartOnly = true User = {{ gunicorn_user }} Group = {{ gunicorn_user }} RuntimeDirectory = {{ gunicorn_app_name }} PIDFile = {{ gunicorn_run_dir }}/{{ gunicorn_app_name }}.pid WorkingDirectory = {{ working_direcory }} ExecStart = {{ gunicorn_bin }} --pid {{ gunicorn_run_dir }}/{{ gunicorn_app_name }}.pid \ --config {{ gunicorn_config_dir }}/{{ gunicorn_app_name }}.py \ {{ gunicorn_app_path }} ExecReload = /bin/kill -s HUP $MAINPID ExecStop = /bin/kill -s TERM $MAINPID PrivateTmp = true [Install] WantedBy = multi-user.target
[その他参考]
GitHub - azavea/ansible-gunicorn: An Ansible role for installing and configuring gunicorn.
Django + Nginx + Gunicorn でアプリケーションを立ち上げる | WEBカーテンコール
ansible/gunicorn.service.j2 at master · UTNkar/ansible · GitHub
Deploying Gunicorn — Gunicorn 20.0.4 documentation