delhi09の勉強日記

技術トピック専用のブログです。自分用のメモ書きの投稿が多いです。あくまで「勉強日記」なので記事の内容は鵜呑みにしないでください。

DjangoをEC2インスタンス上で動かす環境を構築する(その5:GunicornでDjangoアプリを起動する。)

参考文献

その5:GunicornでDjangoアプリを起動する。

概要

  • GunicornでDjangoアプリを起動する。
  • Gunicornをsystemdに登録して、systemctlで制御できるようにする。

手順

まずは手動でGunicornでDjangoアプリを起動する。

・前提
「appserver」ユーザーで作業する。

$ sudo su appserver
$ whoami
appserver

・GunicornでDjangoアプリを起動する。

以下の公式ドキュメントによると、manage.pyと同じ階層でgunicorn ${プロジェクト名}.wsgiを実行すると起動できるとのことである。
docs.djangoproject.com

$ cd /var/application/sources/mysite
$ /usr/local/bin/gunicorn mysite.wsgi
[2020-05-25 02:50:10 +0000] [22396] [INFO] Starting gunicorn 20.0.4
[2020-05-25 02:50:10 +0000] [22396] [INFO] Listening at: http://127.0.0.1:8000 (22396)
[2020-05-25 02:50:10 +0000] [22396] [INFO] Using worker: sync
[2020-05-25 02:50:10 +0000] [22399] [INFO] Booting worker with pid: 22399

→ 正常に起動できたように見受けられる。

・確認
以下のように、curlでURLを叩くと302が返ってきて、プロセスも立ち上がっているので、正常に起動していると判断した。

$ curl -I "http://localhost:8000/admin/"
HTTP/1.1 302 Found
Server: gunicorn/20.0.4
Date: Mon, 25 May 2020 02:51:06 GMT
Connection: close
Content-Type: text/html; charset=utf-8
Location: /admin/login/?next=/admin/
Expires: Mon, 25 May 2020 02:51:06 GMT
Cache-Control: max-age=0, no-cache, no-store, must-revalidate, private
X-Frame-Options: DENY
Content-Length: 0
Vary: Cookie
X-Content-Type-Options: nosniff

$ ps aux | grep "python" | grep -v "grep"
appserv+ 22396  0.2  2.3 233980 24160 pts/0    S+   02:50   0:00 /usr/bin/python3 /usr/local/bin/gunicorn mysite.wsgi
appserv+ 22399  0.2  4.0 361756 40520 pts/0    S+   02:50   0:00 /usr/bin/python3 /usr/local/bin/gunicorn mysite.wsgi
$
Gunicornをsystemdに登録する。

・公式ドキュメントは以下
docs.gunicorn.org

・前提
「admin」ユーザーで作業する。

$ whoami
admin

/etc/systemd/system/gunicorn.serviceを作成する。

$ cd /etc/systemd/system/
$ sudo touch gunicorn.service

・他のファイルのパーミッション644になっているので、合わせておく。

$ ls -l /usr/lib/systemd/system/graphical.target
-rw-r--r-- 1 root root 558  23 17:37 /usr/lib/systemd/system/graphical.target
$ sudo chmod 644 gunicorn.service
$ ls -l gunicorn.service
-rw-r--r-- 1 root root 0  525 16:04 gunicorn.service

gunicorn.serviceに以下の内容を設定する。

[gunicorn.service]

[Unit]
Description=gunicorn daemon
After=network.target

[Service]
Type=notify
PIDFile=/run/gunicorn/pid
User=appserver
Group=appserver
RuntimeDirectory=gunicorn
WorkingDirectory=/var/application/sources/mysite
ExecStart=/usr/local/bin/gunicorn \
                --access-logfile - \
                --workers 3 \
                --bind=localhost:8000 \
                mysite.wsgi
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true
Restart=always

[Install]
WantedBy=multi-user.target

RuntimeDirectoryを作成して所有者を「appserver」ユーザーに設定する。
※ これをやっておかないと、service起動時に「appserver」ユーザーが/run直下にgunicornディレクトリを作成しようとしてエラーが発生する。

$ sudo mkdir /run/gunicorn
$ sudo chown appserver:appserver /run/gunicorn
$ ls -ld /run/gunicorn
drwxr-xr-x 2 appserver appserver 40  525 20:25 /run/gunicorn

gunicorn.serviceを登録する。

$ sudo systemctl enable gunicorn.service

・gunicornを起動する。

$ sudo systemctl start gunicorn.service

・ステータスを確認する。

$ sudo systemctl status gunicorn.service
[sudo] admin のパスワード:
● gunicorn.service - gunicorn daemon
   Loaded: loaded (/etc/systemd/system/gunicorn.service; enabled; vendor preset: disabled)
   Active: active (running) since 月 2020-05-25 21:06:37 UTC; 6min ago
 Main PID: 30331 (gunicorn)
   Status: "Gunicorn arbiter booted"
   CGroup: /system.slice/gunicorn.service
           ├─30331 /usr/bin/python3 /usr/local/bin/gunicorn --access-logfile - --workers 3 --bind=localhost:8000 mysite.wsgi
           ├─30334 /usr/bin/python3 /usr/local/bin/gunicorn --access-logfile - --workers 3 --bind=localhost:8000 mysite.wsgi
           ├─30335 /usr/bin/python3 /usr/local/bin/gunicorn --access-logfile - --workers 3 --bind=localhost:8000 mysite.wsgi
           └─30336 /usr/bin/python3 /usr/local/bin/gunicorn --access-logfile - --workers 3 --bind=localhost:8000 mysite.wsgi

 525 21:06:37 ip-172-31-16-161.us-west-2.compute.internal systemd[1]: Starting gunicorn daemon...
 525 21:06:37 ip-172-31-16-161.us-west-2.compute.internal gunicorn[30331]: [2020-05-25 21:06:37 +0000] [30331] [INFO] Starting gunicorn 20.0.4
 525 21:06:37 ip-172-31-16-161.us-west-2.compute.internal systemd[1]: Started gunicorn daemon.
 525 21:06:37 ip-172-31-16-161.us-west-2.compute.internal gunicorn[30331]: [2020-05-25 21:06:37 +0000] [30331] [INFO] Listening at: http://1...0331)
 525 21:06:37 ip-172-31-16-161.us-west-2.compute.internal gunicorn[30331]: [2020-05-25 21:06:37 +0000] [30331] [INFO] Using worker: sync
 525 21:06:37 ip-172-31-16-161.us-west-2.compute.internal gunicorn[30331]: [2020-05-25 21:06:37 +0000] [30334] [INFO] Booting worker with pid: 30334
 525 21:06:37 ip-172-31-16-161.us-west-2.compute.internal gunicorn[30331]: [2020-05-25 21:06:37 +0000] [30335] [INFO] Booting worker with pid: 30335
 525 21:06:38 ip-172-31-16-161.us-west-2.compute.internal gunicorn[30331]: [2020-05-25 21:06:38 +0000] [30336] [INFO] Booting worker with pid: 30336
 525 21:07:53 ip-172-31-16-161.us-west-2.compute.internal gunicorn[30331]: 127.0.0.1 - - [26/May/2020:06:07:53 +0900] "HEAD /admin/ HTTP/1.1...61.1"
Hint: Some lines were ellipsized, use -l to show in full.
$

→ 正常に起動できているように見受けられる。

・プロセスを確認する。

$ ps aux | grep "python3" | grep -v "grep"
appserv+ 30566  0.0  2.3 236688 24008 ?        Ss   21:38   0:00 /usr/bin/python3 /usr/local/bin/gunicorn --access-logfile - --workers 3 --bind=localhost:8000 mysite.wsgi
appserv+ 30569  0.0  3.9 361180 39868 ?        S    21:38   0:00 /usr/bin/python3 /usr/local/bin/gunicorn --access-logfile - --workers 3 --bind=localhost:8000 mysite.wsgi
appserv+ 30570  0.0  3.9 361176 39772 ?        S    21:38   0:00 /usr/bin/python3 /usr/local/bin/gunicorn --access-logfile - --workers 3 --bind=localhost:8000 mysite.wsgi
appserv+ 30571  0.0  3.9 361176 39772 ?        S    21:38   0:00 /usr/bin/python3 /usr/local/bin/gunicorn --access-logfile - --workers 3 --bind=localhost:8000 mysite.wsgi
$

→ 意図した通りappserverユーザーで起動している。

curlで叩いてみる。

$ curl -I "http://localhost:8000/admin/"
HTTP/1.1 302 Found
Server: gunicorn/20.0.4
Date: Mon, 25 May 2020 21:20:52 GMT
Connection: close
Content-Type: text/html; charset=utf-8
Location: /admin/login/?next=/admin/
Expires: Mon, 25 May 2020 21:20:52 GMT
Cache-Control: max-age=0, no-cache, no-store, must-revalidate, private
X-Frame-Options: DENY
Content-Length: 0
Vary: Cookie
X-Content-Type-Options: nosniff

302が返ってきたので、正常に起動していると判断した。

・プロセスの親子関係を確認する。

ワーカー数3で起動したところ、プロセスが4つ立ち上がったので、内訳は

  • 親プロセス : 1個
  • 子プロセス : 3個

かなと思い、ついでに確認してみる。

$ ps auxf | grep "python3" | grep -v "grep"
appserv+ 30566  0.0  2.3 236688 24008 ?        Ss   21:38   0:00 /usr/bin/python3 /usr/local/bin/gunicorn --access-logfile - --workers 3 --bind=localhost:8000 mysite.wsgi
appserv+ 30569  0.0  3.9 361180 39868 ?        S    21:38   0:00  \_ /usr/bin/python3 /usr/local/bin/gunicorn --access-logfile - --workers 3 --bind=localhost:8000 mysite.wsgi
appserv+ 30570  0.0  3.9 361176 39772 ?        S    21:38   0:00  \_ /usr/bin/python3 /usr/local/bin/gunicorn --access-logfile - --workers 3 --bind=localhost:8000 mysite.wsgi
appserv+ 30571  0.0  4.0 362092 40504 ?        S    21:38   0:00  \_ /usr/bin/python3 /usr/local/bin/gunicorn --access-logfile - --workers 3 --bind=localhost:8000 mysite.wsgi
$

→ 予想通りだった。

systemdの設定のデバッグ

起動に失敗した時は、/var/log/messagesにエラーログが出力されている。

$ sudo tail /var/log/messages

備忘録

systemdの設定値に関して、まだいくつか意味が理解できていない項目があり、コピペでとりあえず動いた感があるので、後で設定値の意味をちゃんと理解したい。

systemdの仕組みについては、以下のRed Hatの資料にとても詳しく説明されていたので、こちらも後で読みたい。
redhat.lookbookhq.com

以上で「その5:GunicornでDjangoアプリを起動する」は完了。
その6に続く。