概要
参考文献
- 『Pythonプロフェッショナルプログラミング 第3版』の「Chapter 11 環境構築とデプロイの自動化」
- 『現場で使える Django の教科書《実践編》』の「第7章 デプロイ」
その7:Gunicornの前段にNginxを配置する。
手順
Nginxの設定ファイルのバックアップをとる。
これからnginx.conf
を編集するが、変更箇所の差分がわかるようにインストールした初期状態のnginx.conf
のバックアップを取っておく。
$ sudo cp nginx.conf /tmp/nginx.conf.`date +"%Y%m%d%H%M%S"`.bk
Nginxの設定ファイルを編集する。
・nginx.conf
を以下の内容で上書きする。
user webserver; worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx/pid; include /usr/share/nginx/modules/*.conf; events { worker_connections 1024; } http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; include /etc/nginx/conf.d/*.conf; server { listen 10080; server_name localhost xxx.xxx.xxx.xxx; # EC2インスタンスのグローバルIPアドレス include /etc/nginx/default.d/*.conf; location / { proxy_pass http://unix:/run/gunicorn/gunicorn.sock; } } }
・重要な変更点
- 起動ユーザーを
nginx
→webserver
に変更している。 - PIDファイルのパスを
/run/nginx.pid
→/run/nginx/pid
に変更している。 - masterプロセスも含めてrootではないユーザー(「webserver」ユーザー)で起動するので、80ポートではなく10080ポートでListenするように設定している。
※ 詳細は以下のstackoverflowのQAを参照
stackoverflow.com
nginx.service
を編集する。
/etc/systemd/system/〜
配下にnginxのserviceファイルが存在しないなと疑問に思い、以下のコマンドで探したところ、/usr/lib/systemd/system/nginx.service
に存在した。
$ systemctl cat nginx # /usr/lib/systemd/system/nginx.service [Unit] Description=The nginx HTTP and reverse proxy server After=network.target remote-fs.target nss-lookup.target [Service] Type=forking PIDFile=/run/nginx.pid # Nginx will fail to start if /run/nginx.pid already exists but has the wrong # SELinux context. This might happen when running `nginx -t` from the cmdline. # https://bugzilla.redhat.com/show_bug.cgi?id=1268621 ExecStartPre=/usr/bin/rm -f /run/nginx.pid ExecStartPre=/usr/sbin/nginx -t ExecStart=/usr/sbin/nginx ExecReload=/bin/kill -s HUP $MAINPID KillSignal=SIGQUIT TimeoutStopSec=5 KillMode=mixed PrivateTmp=true [Install] WantedBy=multi-user.target >||
・PIDファイルのパスを/run/nginx.pid
→/run/nginx/pid
に変更する。
$ diff /tmp/nginx.service.bak /usr/lib/systemd/system/nginx.service 7c7 < PIDFile=/run/nginx.pid --- > PIDFile=/run/nginx/pid 11c11 < ExecStartPre=/usr/bin/rm -f /run/nginx.pid --- > ExecStartPre=/usr/bin/rm -f /run/nginx/pid $
・起動ユーザーをwebserver
ユーザーに設定する。
以下を追加する。
... [Service] User=webserver ...
・nginx.service
を変更しているのでリロードする。
$ sudo systemctl daemon-reload
gunicorn.service
を編集する。
・gunicorn.service
を編集する。
$ cd /etc/systemd/system
$ sudo vi gunicorn.service
・変更点①
gunicorn.socket
への依存関係を設定する。
Description=gunicorn daemon Requires=gunicorn.socket #この行を追加
・変更点②
起動方法をIP・ポートからUnixドメインソケットに変更する。
$ diff /tmp/gunicorn.service.bak gunicorn.service 15c15 < --bind=localhost:8000 \ --- > --bind unix:/run/gunicorn/gunicorn.sock \ $
・gunicorn.socket
を作成する。
・/etc/systemd/system
直下にgunicorn.socket
ファイルを作成して、パーミッションを644
に設定する。
$ pwd /etc/systemd/system $ sudo touch gunicorn.socket $ sudo chmod 644 gunicorn.socket $ ls -l gunicorn.socket -rw-r--r-- 1 root root 0 5月 26 16:16 gunicorn.socket
・以下を設定する。
[Unit] Description=gunicorn socket [Socket] ListenStream=/run/gunicorn/gunicorn.sock [Install] WantedBy=sockets.target
・serviceに登録する。
・gunicorn.service
の設定内容を変更しているのでリロードする。
$ sudo systemctl daemon-reload
・gunicorn.socket
をserviceに登録する。
$ sudo systemctl enable gunicorn.socket
・Nginx関連の各種ディレクトリの作成および、所有者・パーミッションの設定を行う。
・/run/nginx
ディレクトリを作成して、所有者をwebserver:webserver
に変更する。
$ sudo mkdir /run/nginx $ sudo chown webserver:webserver /run/nginx $ ls -ld /run/nginx drwxr-xr-x 2 webserver webserver 40 5月 26 17:05 /run/nginx
・/var/log/nginx
ディレクトリの所有者をwebserver:webserver
、パーミッションを755
に変更する。
$ ls -ld /var/log/nginx drwxrwx--- 2 nginx root 71 5月 26 03:41 /var/log/nginx $ sudo chown webserver:webserver /var/log/nginx $ sudo chmod 755 /var/log/nginx $ ls -ld /var/log/nginx drwxr-xr-x 2 webserver webserver 6 5月 26 17:45 /var/log/nginx
・/var/lib/nginx
以下の所有者をwebserver:webserver
に変更する。
$ ls -ld /var/lib/nginx drwxrwx--- 3 nginx root 17 5月 24 18:59 /var/lib/nginx $ sudo chown -R webserver:webserver /var/lib/nginx $ ls -ld /var/lib/nginx drwxrwx--- 3 webserver webserver 17 5月 24 18:59 /var/lib/nginx
・/etc/nginx
以下のディレクトリの所有者をwebserver:webserver
に変更する。
$ ls -ld /etc/nginx drwxr-xr-x 4 root root 4096 5月 26 16:59 /etc/nginx $ sudo chown -R webserver:webserver /etc/nginx $ ls -ld /etc/nginx drwxr-xr-x 4 webserver webserver 4096 5月 26 16:59 /etc/ngin
※ 今回はキャッシュ機能は使用しないが、キャッシュ機能を使用する場合はキャッシュファイルを保存するディレクトリにもパーミッションの設定が必要な場合がある。
Nginxの設定ファイルをシンタックスチェックする。
・シンタックスエラーがないことを確認する。
$ sudo nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful $
Nginxを起動する。
・起動
$ sudo systemctl start nginx.service
・status確認
$ sudo systemctl status nginx.service ● nginx.service - The nginx HTTP and reverse proxy server Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled) Active: active (running) since 火 2020-05-26 17:48:40 UTC; 2min 43s ago Process: 2556 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS) Process: 2553 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS) Process: 2552 ExecStartPre=/usr/bin/rm -f /run/nginx/pid (code=exited, status=0/SUCCESS) Main PID: 2559 (nginx) CGroup: /system.slice/nginx.service ├─2559 nginx: master process /usr/sbin/nginx └─2561 nginx: worker process 5月 26 17:48:39 ip-172-31-16-161.us-west-2.compute.internal systemd[1]: Starting The nginx HTTP and reverse proxy server... 5月 26 17:48:39 ip-172-31-16-161.us-west-2.compute.internal nginx[2553]: nginx: [warn] the "user" directive makes sense only if the master pro...onf:1 5月 26 17:48:39 ip-172-31-16-161.us-west-2.compute.internal nginx[2553]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok 5月 26 17:48:39 ip-172-31-16-161.us-west-2.compute.internal nginx[2553]: nginx: configuration file /etc/nginx/nginx.conf test is successful 5月 26 17:48:39 ip-172-31-16-161.us-west-2.compute.internal nginx[2556]: nginx: [warn] the "user" directive makes sense only if the master pro...onf:1 5月 26 17:48:39 ip-172-31-16-161.us-west-2.compute.internal systemd[1]: Failed to read PID from file /run/nginx/pid: Invalid argument 5月 26 17:48:40 ip-172-31-16-161.us-west-2.compute.internal systemd[1]: Started The nginx HTTP and reverse proxy server. Hint: Some lines were ellipsized, use -l to show in full. $
→ 「Failed to read PID from file /run/nginx/pid: Invalid argument」という警告が気になるが、とりあえず起動はしているように見受けられる。
・プロセス確認
$ ps aux | grep "nginx" | grep -v "grep" webserv+ 2559 0.0 0.2 121432 2168 ? Ss 17:48 0:00 nginx: master process /usr/sbin/nginx webserv+ 2561 0.0 0.3 121888 3208 ? S 17:48 0:00 nginx: worker process $
→ master process
・worker process
ともに「webserver」ユーザーで起動している。
・ログ確認
$ ls -l /var/log/nginx 合計 4 -rw-r--r-- 1 webserver webserver 0 5月 26 17:48 access.log -rw-r--r-- 1 webserver webserver 326 5月 26 17:48 error.log $ cat /var/log/nginx/error.log 2020/05/26 17:48:39 [warn] 2553#0: the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:1 2020/05/26 17:48:39 [warn] 2556#0: the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:1 $
→ ログも正常に出力されている。「nginx.conf
の「user」ディレクティブはmasterプロセスをrootではないユーザーで起動している場合には無視されますよ」という警告が出ているが、これは害のある警告ではないので無視する。
Guniconを起動する。
・起動
$ sudo systemctl start gunicorn.service
・status確認
$ sudo systemctl status gunicorn.service ● gunicorn.service - gunicorn daemon Loaded: loaded (/etc/systemd/system/gunicorn.service; enabled; vendor preset: disabled) Active: active (running) since 火 2020-05-26 20:09:34 UTC; 1min 3s ago Process: 3394 ExecStop=/bin/kill -s TERM $MAINPID (code=exited, status=0/SUCCESS) Main PID: 3417 (gunicorn) Status: "Gunicorn arbiter booted" CGroup: /system.slice/gunicorn.service ├─3417 /usr/bin/python3 /usr/local/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn/gunicorn.sock mysite.wsgi ├─3420 /usr/bin/python3 /usr/local/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn/gunicorn.sock mysite.wsgi ├─3421 /usr/bin/python3 /usr/local/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn/gunicorn.sock mysite.wsgi └─3422 /usr/bin/python3 /usr/local/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn/gunicorn.sock mysite.wsgi 5月 26 20:09:34 ip-172-31-16-161.us-west-2.compute.internal systemd[1]: Starting gunicorn daemon... 5月 26 20:09:34 ip-172-31-16-161.us-west-2.compute.internal gunicorn[3417]: [2020-05-26 20:09:34 +0000] [3417] [INFO] Starting gunicorn 20.0.4 5月 26 20:09:34 ip-172-31-16-161.us-west-2.compute.internal gunicorn[3417]: [2020-05-26 20:09:34 +0000] [3417] [INFO] Listening at: unix:/run/...3417) 5月 26 20:09:34 ip-172-31-16-161.us-west-2.compute.internal gunicorn[3417]: [2020-05-26 20:09:34 +0000] [3417] [INFO] Using worker: sync 5月 26 20:09:34 ip-172-31-16-161.us-west-2.compute.internal systemd[1]: Started gunicorn daemon. 5月 26 20:09:34 ip-172-31-16-161.us-west-2.compute.internal gunicorn[3417]: [2020-05-26 20:09:34 +0000] [3420] [INFO] Booting worker with pid: 3420 5月 26 20:09:34 ip-172-31-16-161.us-west-2.compute.internal gunicorn[3417]: [2020-05-26 20:09:34 +0000] [3421] [INFO] Booting worker with pid: 3421 5月 26 20:09:34 ip-172-31-16-161.us-west-2.compute.internal gunicorn[3417]: [2020-05-26 20:09:34 +0000] [3422] [INFO] Booting worker with pid: 3422 Hint: Some lines were ellipsized, use -l to show in full. ]$
$ ls -l /run/gunicorn/ 合計 0 srwxrwxrwx 1 appserver appserver 0 5月 26 20:09 gunicorn.sock $
curlで動作確認
・curlで叩いてみる。
$ curl -I "http://localhost:10080/polls/" HTTP/1.1 200 OK Server: nginx/1.16.1 Date: Tue, 26 May 2020 20:13:44 GMT Content-Type: text/html; charset=utf-8 Content-Length: 109 Connection: keep-alive X-Frame-Options: DENY X-Content-Type-Options: nosniff $
→ 200が返ってくる。
・Nginxのアクセスログ
$ tail /var/log/nginx/access.log 127.0.0.1 - - [26/May/2020:20:13:44 +0000] "HEAD /polls/ HTTP/1.1" 200 0 "-" "curl/7.61.1" "-" $
・Djangoのアプリケーションログ
$ tail /var/log/django/app.log 2020-05-27 05:16:46,366 [INFO] Hello world! $
画面から動作確認
・セキュリティグループのインバウンドの設定に以下を追加する。
※ セキュリティホールがあると怖いので、自宅のIPアドレスのみに絞っておく。
タイプ | プロトコル | ポート範囲 | ソース | 説明 - オプション |
---|---|---|---|---|
カスタムTCP | TCP | 10080 | ${自宅のIPアドレス}/32 | - |
・ブラウザでアクセスしてみる。
※ ドメインはNginxのserver_name
に設定していないので、ドメインではアクセスできないので注意。
http://${EC2インスタンスのグローバルIP}:10080/admin/login/?next=/admin/
・結果
以下のようにコンテンツは取得できたが、CSSが適用されておらず、静的コンテンツが取得できていないように見受けられる。
→ 実際にCSSファイルにアクセスしてみると、以下のように404が返される。
この問題の解決はその8に続く。