DjangoNginxPythonuWSGI APIサーバ

Permission エラーの無い uWSGI と Nginx で Django API サーバを構築する方法 |CentOS 7

django-api-server Django
スポンサーリンク

現状・条件

  • CentOS Linux release 7.6.1810 (Core)
  • Python : 仮想環境 ( 3.7.3 ) / System-wide 環境( 2.7.5 → 3.6.8)
  • Nginx : 1.14.0
  • uWSGI : 2.0.18
  • Django : 2.2.5
  • 構築するには、Python 仮想環境 ( Pyenv + Anaconda )と Django REST framework 環境 もしくは Django アプリケーション環境を事前に設定し、正常に動作することを確認してください。
  • uWSGI を Systemd で自動化するため、Python の System-wide 環境バージョンを3.6.8 に変更します。
  • uWSGIemperor モード に設定します。
  • uWSGI + Django + Nginx を使用して API サーバ を構築します。
completed_stacks_nginx_uwsgi_django
▲ API サーバ構成 : Web Client – Nginx – Unix Socket – uWSGI – Django

それでは、Python の仮想環境を構築します。

Python 仮想環境を設定

仮想環境の設定がまだの方は ▼ の記事をご参照ください。

Django Project を作成

Django Project を作成する方法は ▼ の記事をご参照ください。

ここで使用するサーバ IP アドレスは 192.168.10.10 にします。
ユーザ名は admin を使用します。
※ 構築する際には、ご自身の環境に合わせて適宜変更してください。

また、使用するポートは Django 開発サーバのデフォルトポートである 8000/TCP を使用します。

それでは、Python 仮想環境 で uWSGI を設定します。

uWSGI のインストールと設定|仮想環境

Django Project ディレクトリまで移動して仮想環境 ( ここでは py37 ) に入ります。

[admin@centos7 ~]$ cd /reactjs/snowball/backend
[admin@centos7 backend]$ source activate py37

仮想環境で uWSGI をインストール

(py37) [admin@centos7 backend]$ pip install uwsgi

# 問題ないか uwsgi コマンドを実行してみます。
(py37) [admin@centos7 backend]$ uwsgi
*** Starting uWSGI 2.0.18 (64bit) on [Tue Oct 15 11:22:48 2019] ***
compiled with version: 4.8.5 20150623 (Red Hat 4.8.5-36) on 05 September 2019 03:51:37
os: Linux-3.10.0-957.27.2.el7.x86_64 #1 SMP Mon Jul 29 17:46:05 UTC 2019
nodename: centos7
machine: x86_64
clock source: unix
pcre jit disabled
detected number of CPU cores: 4
...

↑エラーがないことを確認してください。
uWSGI の共有ライブラリ エラーの対処方法

uwsgi: error while loading shared libraries: xxxx : cannot open shared object file: No such file or directory エラーが発生した場合、( xxxx : libicui18n.so.58 / libssl.so.1.1 )

uWSGI の基本動作テスト:Python ファイル

basic_stacks_uwsgi_python
▲ uWSGI 基本テスト:Web Client – uWSGI – Python

テスト用のファイルを作成して uWSGI を起動します。

(py37) [admin@centos7 backend]$ vi uwsgi_nginx_test.py
def application(env, start_response):
    start_response('200 OK', [('Content-Type','text/html')])
    return [b"Hello World"] # python3

(py37) [admin@centos7 backend]$ uwsgi --http :8000 --wsgi-file uwsgi_nginx_test.py

http://192.168.10.10:8000 にアクセスします。
画面に Hello World が表示されれば OK です。

問題なければ、control + c コマンドでプロセスを終了しておきます。

uWSGI の基本動作テスト:Django Project

basic_stacks_uwsgi_django
▲ uWSGI 基本テスト:Web Client – uWSGI – Django

まず、Django Project 自体が正常に動作するか次のように確認しておきます。

(py37) [admin@centos7 backend]$ python manage.py runserver 0:8000

http://192.168.10.10:8000 にアクセスします。
画面にあなたの Django アプリ関連ページが表示されれば OK です。

問題なければ、control + c コマンドでプロセスを終了しておきます。

次は、uWSGI を使用して起動します。

(py37) [admin@centos7 backend]$ uwsgi --http :8000 --module snowball.wsgi

同じく、http://192.168.10.10:8000 にアクセスします。
画面にDjango アプリページが表示されれば OK です。

問題なければ、control + c コマンドでプロセスを終了しておきます。

uwsgi コマンドの –module オプションには何を指定するのか?
  • django-admin startproject snowball . コマンドで指定した snowballプロジェクト名 になります。
  • また、プロジェクトは下記のデレクトり構造になっていて、wsgi.py ファイルがデフォルトで存在します。
    /reactjs/snowball/backend/snowball
    .
    ├── init.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py
  • なので、uwsgi コマンドを打つときにはプロジェクトホーム ( /reactjs/snowball/backend/ ) まで移動して、その下の project名.wsgi を指定して uWSGI に認識させます。
  • したがって、ここでは –module snowball.wsgi と書きます。

ここまで、uWSGI を使用して Python コードDjango project を実行してみました。

\お🉐なキャンペーン実施中!/

\お🉐なキャンペーン実施中!/

次は Nginx を設定して本来の WEB サーバで、Django project を実行します。

Nginx を設定

conda deactivate コマンドで仮想環境から出てください。

Nginx をインストール・基本動作テスト

basic_stacks_webclient_webserver
▲ Nginx 基本テスト:Web Client – Web Server
[admin@centos7 ~]$ sudo yum install nginx
[admin@centos7 ~]$ sudo systemctl start nginx

http://192.168.10.10 へアクセスします。
Welcome to nginx! が表示されれば OK です。
もし、80 ポートが使用中であれば、8000 ポートなどに変更しましょう。

Nginx の設定ファイルを作成

uWSGI と連動するため、Conf ファイルを作成します。
※下記の Conf ファイルは の後ろのコメント部分を消して使用してください。

# default.conf ファイルを使わないようにします ( 任意 )
[admin@centos7 conf.d]$ sudo mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf_

# snowball_nginx.conf ファイルを作成します ( ファイル名は任意 )
[admin@centos7 conf.d]$ sudo vi /etc/nginx/conf.d/snowball_nginx.conf

# サーバグループを指定
upstream django {       # django は任意
    #server unix:/run/uwsgi/snowball.sock; # 位置やファイル名は任意
    server 127.0.0.1:8001;  # ポート番号は任意
}

server {
    listen      8000;
    charset utf-8;
    # max upload size
    client_max_body_size 75M;
    server_name 192.168.10.10;
    location / {
        root /reactjs/snowball/backend; # django project ホームを nginx のドキュメントルートに指定
        include /etc/nginx/uwsgi_params;
        uwsgi_pass django;  # 作成した upstream 名を指定
    }
    # Django media
    location /media  {
        alias /reactjs/snowball/backend/media;
    }
    location /static {
        alias /reactjs/snowball/backend/static;
    }
}
[admin@centos7 conf.d]$

# conf ファイルを保存し、設定の誤りがあるかチェックします。( 任意 )
[admin@centos7 conf.d]$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[admin@centos7 conf.d]$

静的ファイルを構成

上記の conf ファイルの media/static 設定は Django 側でも一致させる必要があります。
まず、サイトの静的ファイルを保持するディレクトリ ( static ) を構成するため、Django Project ホームに移動して下記のように実際の静的ファイルを集めておきます。

[admin@centos7 ~]$ cd /reactjs/snowball/backend
[admin@centos7 backend]$ source activate py37

(py37) [admin@centos7 backend]$ vi snowball/settings.py
# 任意のところに下記の一行をコピペしておきます。
STATIC_ROOT = os.path.join(BASE_DIR, "static/")

# ファイルを保存&閉じて、collectstatic コマンドを実行すると自動的に Static ファイルを集めます。
(py37) [admin@centos7 backend]$ ./manage.py collectstatic

157 static files copied to '/reactjs/snowball/backend/static'.
(py37) [admin@centos7 backend]$

Nginx を再起動します。

(py37) [admin@centos7 backend]$ sudo systemctl restart nginx

Nginx 基本テスト

media ディレクトリがなければ作成します。

[admin@centos7 backend]$ mkdir /reactjs/snowball/backend/media

任意の media ファイルをアップロードします。

# Mac で scp を使い、city.jpg ファイルをアップする 例:
try🐶everything backend$ scp  ~/Downloads/city.jpg admin@centos7:/reactjs/snowball/backend/media

http://192.168.10.10:8000/media/city.jpg にアクセスします。
イメージが表示されれば Nginx の動作は問題ないことです!

TCP Port Socket を使用して Python コードを実行する

basic_stacks_webclient_nginx_unixsocket_uwsgi_python
▲ uWSGI 基本テスト:Web Client – Nginx – UnixSocket – uWSGI – Python

次は、Nginx で設定した TCP Port Socket ( server 127.0.0.1:8001 ) をテストします。uWSGI8001 ポートで起動して、冒頭で作成した uwsgi_nginx_test.py を Nginx から表示させます。

Nginx を起動した状態で行います。upstream 設定が http になっていることを確かめてください。Conf ファイルを修正したらまた、Nginx を再起動してください。

(py37) [admin@centos7 backend]$ sudo vi /etc/nginx/conf.d/snowball_nginx.conf
upstream django {
    #server unix:/run/uwsgi/snowball.sock;
    server 127.0.0.1:8001;  # << ここ!
}
...
(py37) [admin@centos7 backend]$ sudo systemctl restart nginx

uWSGI を起動します。

(py37) [admin@centos7 backend]$ uwsgi --socket :8001 --wsgi-file uwsgi_nginx_test.py

http://192.168.10.10:8000 にアクセスします。
画面に Hello World が表示されれば OK です。

問題なければ、control + c コマンドでプロセスを終了しておきます。

これから、
この記事のゴールである Unix Socket を使用した設定を行いますが、Permissionエラー が多すぎてかなり苦労する部分なので Permission エラーが発生する理由や対処方法 をここで紹介します。

Permission エラーが発生する理由や対処方法
  1. 多くの Permission 関連エラーは Socket ファイル絡みで発生 します。
    その他、daemonize 設定で生成される log ファイル絡みです。
  2. Permission 関連エラーの原因は何らかの理由で Socket ファイルの所有権限が変更され WEB サーバがそのファイルにアクセスできなくなるのが原因です。
  • Socket ファイルは uWSGI を実行すると–socket オプションに指定されたファイルが生成されますが、最終的には WEB サーバ側でそのソケットを使用するため、所有者をWEB サーバを実行するユーザに変更する必要があります。
  • 正しい所有権限は以下の通りです。
    ・Socket 用ディレクトリ:uWSGI を実行するユーザ ( 所有者 )
    ・Socket ファイル:WEBサーバを実行するユーザ ( 所有者 )
    ・log ファイル:uWSGI を実行するユーザ ( 所有者 )
  • 上記の内容を踏まえて、正しい所有権限を考えみましょう!
    例えば、admin ユーザが Nginx を WEB サーバとして uWSGI の動作テストを行うとします。その際はどのような所有権限が必要でしょうか?
    答えは、▼ のようになります。
※ Socket ファイルは /run/uwsgi/snowball.sock とします。
※ Log ファイルは /var/log/uwsgi/uwsgi-emperor.log とします。
書式:owner:group

所有権限
/runディレクトリは root:root でいいです。( デフォルトのまま )
/run/uwsgi ディレクトリは admin:nginx で所有者が admin になります。
/run/uwsgi/snowball.sock ファイルは nginx:nginx で所有者が nginx になります。
/var/log/uwsgi/uwsgi-emperor.log ファイルは admin:nginx で所有者が admin になります。

ご自身が考えた答えと一致していますか?
この所有権限さえ理解してしまえばこれからの作業はよりスムーズに行けると思います!

応用問題!
Q:テストユーザは admin2 で、WEBサーバの役割は uWSGI が担当する場合はどうなるのか?
A:/runは変更なし、/run/uwsgiはadmin2:admin2、/run/uwsgi/snowball.sockはadmin2:admin2、logファイルもadmin2:admin2です。( admin2ユーザがWEBサーバ役割のuWSGIを起動するから)

所有権限を変更するコマンド:
sudo chown admin:nginx /run/uwsgi
sudo chown nginx:nginx /run/uwsgi/snowball.sock
sudo chown admin:nginx /var/log/uwsgi/uwsgi-emperor.log

Unix Socket を使用して Python コードを実行する

今回は、Unix socket を使い、uWSGI を再度起動します。

Nginx の conf ファイルを下記のように Unix Socket を使えるように変更してください。

(py37) [admin@centos7 backend]$ sudo vi /etc/nginx/conf.d/snowball_nginx.conf
upstream django {
    server unix:/run/uwsgi/snowball.sock;  # << ここ!
    #server 127.0.0.1:8001;
}
...

# 変更したら nginx を再起動します。
(py37) [admin@centos7 backend]$ sudo systemctl restart nginx 

uwsgi コマンドの –socket オプションは nginx の設定に合わせましょう。

# /run/uwsgiディレクトリを作成して権限を admin:nginx に設定します。
(py37) [admin@centos7 backend]$ sudo mkdir /run/uwsgi
(py37) [admin@centos7 backend]$ sudo chown admin.nginx /run/uwsgi

# uWSGI を起動します。
(py37) [admin@centos7 backend]$ uwsgi --socket /run/uwsgi/snowball.sock --wsgi-file uwsgi_nginx_test.py

ここで、下記のような Permission エラー 発生します。
先ほどの 正しい所有権限 を再度チェックしてみましょう!

Permission エラー

エラー例:
error removing unix socket, unlink(): Permission denied [core/socket.c line 198]
bind(): Address already in use [core/socket.c line 230]
エラー例:
[admin@centos7 ~]$ sudo tail -f /var/log/nginx/error.log

2019/09/10 16:01:38 [crit] 24002#24002: *1 connect() to unix:/run/uwsgi/snowball.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.10.9, server: 192.168.10.10, request: “GET / HTTP/1.1”, upstream: “uwsgi://unix:/run/uwsgi/snowball.sock:”, host: “192.168.10.10:8000”

エラー例:
ブラウザからは 502 Bad Gateway エラー が表示される

先ほどの uwsgi コマンドを実行したのは admin ユーザで、WEBサーバの役割は nginx が担当しています。したがって、
Socket ディレクトリ の所有者は adminSocket ファイル の所有者は nginx が正しいです。

先ほど /run/uwsgi ディレクトリを作成する際に設定済みですが、uwsgi コマンドを実行する前に、sudo chown admin.nginx /run/uwsgi コマンドで Socket ディレクトリの所有者を admin に変更もしくはご確認ください。変更しないと ▼ のようなエラーになります。

bind(): Permission denied [core/socket.c line 230]

Socket ファイルは uWSGI が起動した状態で修正します。
一旦、uWSGI を起動します。

(py37) [admin@centos7 backend]$ uwsgi –socket /run/uwsgi/snowball.sock –wsgi-file uwsgi_nginx_test.py

ブラウザでアクセスすると 502 Bad Gateway が表示され、snowball.sock ファイルは uWSGI を実行した admin が所有者になっているはずです。

[admin@centos7 uwsgi]$ ll
合計 0
srwxrwxr-x 1 admin admin 0 9月 10 16:36 snowball.sock
[admin@centos7 uwsgi]$

uwsgi プロセスを起動したまま、別のウィンドウを開いて Socket ファイルの所有者をnginx に変更します。

[admin@centos7 uwsgi]$ sudo chown nginx snowball.sock
[admin@centos7 uwsgi]$ ll
合計 0
srwxrwxr-x 1 nginx admin 0 9月 10 16:36 snowball.sock
[admin@centos7 uwsgi]$

権限を修正したら、http://192.168.10.10:8000 にアクセスもしくはブラウザをリロードします。
画面に Hello World が表示されれば OK です。

問題なければ、control + c コマンドでプロセスを終了しておきます。

次は、Pythonコードの代わりに、Django アプリを実行します。

\お🉐なキャンペーン実施中!/

\お🉐なキャンペーン実施中!/

Nginx と uWSGI で Django アプリを実行する

completed_stacks_nginx_uwsgi_django
▲ uWSGI 基本テスト:Web Client – Nginx – UnixSocket – uWSGI – Django

Socket ディレクトリの所有者は既に admin に変更済みであるため、今回はそのまま uwsgi コマンドを実行します。

(py37) [admin@centos7 backend]$ uwsgi --socket /run/uwsgi/snowball.sock --module snowball.wsgi

uwsgi プロセスを起動したまま、別のウィンドウを開いて Socket ファイルの所有者を nginx に変更します。

http://192.168.10.10:8000 にアクセスします。
画面に Hello World ではなく、Django アプリ関連ページが表示されれば OK です。

問題なければ、control + c コマンドでプロセスを終了しておきます。

.ini ファイルで uWSGI を実行する

※ ここからは sudo tail -f /var/log/nginx/error.log でエラーログを確認しながらデバッグするとよりスムーズです。

ini ファイル を作成します。ファイルの場所や名前は適宜修正してください。

(py37) [admin@centos7 backend]$ mkdir -p /reactjs/snowball/backend/uwsgi/
(py37) [admin@centos7 backend]$ vi /reactjs/snowball/backend/uwsgi/snowball_uwsgi.ini
[uwsgi]
chdir           = /reactjs/snowball/backend
module          = snowball.wsgi
master          = true
processes       = 5
socket          = /run/uwsgi/snowball.sock
daemonize       = /var/log/uwsgi/uwsgi-emperor.log

(py37) [admin@centos7 backend]$

home オプションは Python 仮想環境が正常動作すればスキップしても自動認識されます。

以下は、daemonize オプションを設定した場合のみ行ってください。

daemonize オプションは必須ではありませんが、デバッグのため追加します。
エラーを防ぐために下記のように空のログファイルを生成し権限を uWSGI を実行するユーザ admin に所有権を変更してください。

(py37) [admin@centos7 backend]$ sudo mkdir /var/log/uwsgi
(py37) [admin@centos7 backend]$ sudo touch /var/log/uwsgi/uwsgi-emperor.log
(py37) [admin@centos7 backend]$ sudo chown admin:nginx /var/log/uwsgi/uwsgi-emperor.log

sudo tail -f /var/log/uwsgi/uwsgi-emperor.log で確認します。

.ini ファイルを使用して uWSGI を実行する

下記のように設定されているか確認します。

sudo systemctl start nginx
sudo chown admin /run/uwsgi
sudo chown nginx /run/uwsgi/snowball.sock
sudo chown admin /var/log/uwsgi/uwsgi-emperor.log

確認できたら起動します。

(py37) [admin@centos7 backend]$ uwsgi --ini ./uwsgi/snowball_uwsgi.ini
–ini オプションで uWSGI を実行すると、よくエラーになるケースを見てみましょう!

1つ目:daemonize で設定した log ファイルの所有者問題

エラー:
(py37) [admin@centos7 backend]$ uwsgi –ini ./uwsgi/snowball_uwsgi.ini
[uWSGI] getting INI configuration from ./uwsgi/snowball_uwsgi.ini
open(“/var/log/uwsgi/uwsgi-emperor.log”): Permission denied [core/logging.c line 288]

対処:uWSGIプロセスを実行するユーザを所有者に設定すること。
[admin@centos7 uwsgi]$ sudo chown admin /var/log/uwsgi/uwsgi-emperor.log
[admin@centos7 uwsgi]$ ll
合計 268
-rw-r—– 1 admin nginx 266446 9月 10 17:20 uwsgi-emperor.log
[admin@centos7 uwsgi]$

2つ目:chown-socket / chmod-socket 問題

ini ファイルに chown-socket = admin:nginx、chmod-socket = 660 を付けるとまた、エラー( ▼ )が出ます。emperor モード を設定するまではこの設定を控えておきましょう。

[admin@centos7 uwsgi]$ sudo tail -f /var/log/uwsgi/uwsgi-emperor.log
chown(): Operation not permitted [core/utils.c line 2649]
# --ini オプションで起動すると uwsgi プロセスはバックグラウンドで実行されます。
(py37) [admin@centos7 backend]$ uwsgi --ini ./uwsgi/snowball_uwsgi.ini
[uWSGI] getting INI configuration from ./uwsgi/snowball_uwsgi.ini
(py37) [admin@centos7 backend]$

# ini ファイルで設定した processes 数の worker プロセスが起動するので、しばらくしてからプロセスを確認できます。
(py37) [admin@centos7 backend]$ ps -ef | grep wusgi
(py37) [admin@centos7 backend]$ ps -ef|grep uwsgi
admin       382     1  0 17:51 ?        00:00:00 uwsgi --ini ./uwsgi/snowball_uwsgi.ini
admin       384   382  0 17:51 ?        00:00:00 uwsgi --ini ./uwsgi/snowball_uwsgi.ini
admin       385   382  0 17:51 ?        00:00:00 uwsgi --ini ./uwsgi/snowball_uwsgi.ini
admin       386   382  0 17:51 ?        00:00:00 uwsgi --ini ./uwsgi/snowball_uwsgi.ini
admin       387   382  0 17:51 ?        00:00:00 uwsgi --ini ./uwsgi/snowball_uwsgi.ini
admin       393   382  0 17:51 ?        00:00:00 uwsgi --ini ./uwsgi/snowball_uwsgi.ini
admin      1187 19347  0 18:00 pts/2    00:00:00 grep --color=auto uwsgi

# エラーになったらプロセスを Kill してから再度 uwsgi コマンドを打ちましょう。
(py37) [admin@centos7 backend]$ ps -ef|grep uwsgi
(py37) [admin@centos7 backend]$ kill -9 382

http://192.168.10.10:8000 にアクセスします。
画面にあなたの Django アプリ関連ページが表示されれば OK です。

問題なければ、control + c コマンドでプロセスを終了しておきます。

これで、Python 仮想環境での設定は完了です。

次は Systemd に登録して自動化するための構成を行います。

System-wide 環境に uWSGI をインストールする

※ 以下は、System-wide 環境Python 仮想環境を構築していないことが条件です。

conda deactivate コマンドで Python 仮想環境から出てください。

(py37) [admin@centos7 backend]$ conda deactivate
[admin@centos7 backend]$ 

System-wide で動作するためは、Python 仮想環境のバージョンと合わせる必要があります。

(py37) [admin@centos7 backend]$ python -V
Python 3.7.3

[admin@centos7 backend]$ sudo python -V
Python 2.7.5

CentOS 7 ではデフォルトの python コマンドが python2 にリンクされています。python3 を追加で設置した後、python3 をデフォルトの python バージョンに変更してから uWSGI をインストールします。

( root ユーザで実行 )
[root@centos7 backend]# yum install epel-release
[root@centos7 backend]# yum search python3 # 設置可能な python パッケージを確認します。

# インストールします。
[root@centos7 backend]# yum -y install python36-devel
[root@centos7 backend]# yum -y install python36-setuptools
[root@centos7 backend]# easy_install-3.6 pip
[root@centos7 ~]# which pip
/usr/local/bin/pip
チェック

※ 新しく /usr/local/bin/pip が設置されましたが、sudo コマンドで使用する /bin/pip はまだ Python2 になっているため、下記のように Python3 用をコピーしておきます。

[admin@centos7 backend]$ sudo which pip
/bin/pip

[admin@centos7 backend]$ sudo cp /usr/local/bin/pip /bin/pip
[admin@centos7 backend]$ cat /bin/pip
#!/usr/bin/python3.6
# EASY-INSTALL-ENTRY-SCRIPT: 'pip==19.2.3','console_scripts','pip'
__requires__ = 'pip==19.2.3'
...

python3 をデフォルトの Python に修正する

必要なのは Symbolic linkpython3.6 に変更するだけです!

( root ユーザで実行 )
# python コマンドの位置を確認します。
[root@centos7 ~]# which python
/bin/python

# python2.7 にリンクされていることを確認します。
[root@centos7 ~]# ll /bin/python*
lrwxrwxrwx 1 root root     9 Sep  5 12:07 /bin/python -> python2.7
...

# リンクを削除して、python3.6 を python にリンクします。
[root@centos7 ~]# rm -f /bin/python
[root@centos7 ~]# cd bin
[root@centos7 bin]# ln -s python3.6 python

# pythonコマンドが3.6バージョンに変更されたことを確認します。
[root@centos7 bin]# ll python*
lrwxrwxrwx 1 root root     9 Sep  5 12:07 /bin/python -> python3.6
...
yum コマンドは python3 で実行できないため編集しておきます。
[root@centos7 bin]# cd
[root@centos7 ~]# which yum
/bin/yum

[root@centos7 ~]# ll /usr/bin/python*
lrwxrwxrwx 1 root root     9 Sep  7 11:22 /usr/bin/python -> python3.6
-rwxr-xr-x 1 root root  7216 Jun 21 05:28 /usr/bin/python2.7
...

[root@centos7 ~]# vi /bin/yum
#!/usr/bin/python
↓↓
#!/usr/bin/python2.7
...
[root@centos7 ~]# yum
エラーがないことを確認します。

また、yum install <package名>コマンドを実行できるように下記のように修正しておきます。

[root@centos7 ~]# vi /usr/libexec/urlgrabber-ext-down

#! /usr/bin/python
↓↓
#! /usr/bin/python2.7
...

Python バージョンを確認します。

[root@centos7 bin]# python -V
Python 3.6.8
[root@centos7 bin]#

System-wide に uWSGI をインストールします。

( root ユーザで実行 )
[root@centos7 ~]# yum install python-devel gcc
[root@centos7 ~]# pip install uwsgi  # or, /usr/local/bin/pip install uwsgi

# /usr/local/lib/python3.6/site-packages 以下に設置されたことを確認してください。
( 3.6の数字は環境によって異なります )

uwsgi コマンドを実行してエラーが出ないか確認します。

( root ユーザで実行 )
[root@centos7 ~]# which uwsgi
/usr/local/bin/uwsgi

# uwsgi コマンドを実行
[root@centos7 ~]# uwsgi
< エラーがないことを確認!! >
チェック

Python 仮想環境で sudo コマンドを使用して uwsgi を実行する際、/bin/uwsgi を参照することになっているので、新しい uwsgi に変更しておきます。

[admin@centos7 backend]$ sudo uwsgi
[sudo] admin のパスワード:
sudo: uwsgi: コマンドが見つかりません

[admin@centos7 backend]$ sudo which uwsgi
/bin/uwsgi
[admin@centos7 backend]$ sudo cp /usr/local/bin/uwsgi /bin/uwsgi

[admin@centos7 backend]$ sudo uwsgi 
*** Starting uWSGI 2.0.18 (64bit) on [Wed Sep 11 18:03:45 2019] ***
...
< sudo uwsgi コマンドが実行できたら OK です >

※ この設定をしない場合は、以下の作業は root ユーザの権限が必要です。

snowball_uwsgi.ini ファイルを修正して、Socket ファイルの所有者を nginx に変更して保存します。

chmod-socket = 664
chown-socket = nginx:nginx
[admin@centos7 backend]$ vi uwsgi/snowball_uwsgi.ini
[uwsgi]

chdir           = /reactjs/snowball/backend
module          = snowball.wsgi
master          = true
processes       = 5
socket          = /run/uwsgi/snowball.sock
chmod-socket    = 664
chown-socket    = nginx:nginx
vacuum          = true
daemonize       = /var/log/uwsgi/uwsgi-emperor.log

[admin@centos7 backend]$ 

System-wide 環境で、ini ファイルを使って uWSGI を再度起動します

表示されるメッセージにエラーがないことを確認します。
特に、Python version:で始まる行に 3.x と表示されていることを確認してください。

# uwsgi プロセスが起動中であれば閉じます。
[admin@centos7 backend]$ ps -ef|grep uwsgi
admin       382     1  0 17:51 ?        00:00:00 uwsgi --ini ./uwsgi/snowball_uwsgi.ini
admin       384   382  0 17:51 ?        00:00:00 uwsgi --ini ./uwsgi/snowball_uwsgi.ini
admin       385   382  0 17:51 ?        00:00:00 uwsgi --ini ./uwsgi/snowball_uwsgi.ini
admin       386   382  0 17:51 ?        00:00:00 uwsgi --ini ./uwsgi/snowball_uwsgi.ini
admin       387   382  0 17:51 ?        00:00:00 uwsgi --ini ./uwsgi/snowball_uwsgi.ini
admin       393   382  0 17:51 ?        00:00:00 uwsgi --ini ./uwsgi/snowball_uwsgi.ini
[admin@centos7 backend]$ sudo kill -9 382

# uWSGI を起動します。
[admin@centos7 backend]$ sudo uwsgi --ini ./uwsgi/snowball_uwsgi.ini
[uWSGI] getting INI configuration from ./uwsgi/snowball_uwsgi.ini
ModuleNotFoundError: No module named ‘django’ エラーに対処

sudo uwsgi –ini uwsgi/snowball_uwsgi.ini コマンドを実行した後、uwsgi のログファイルに ModuleNotFoundError エラー ( ▼ ) が発生、またブラウザでは Internal Server Error が発生した場合、

[admin@centos7 ~]$ tail -f /var/log/uwsgi/uwsgi-emperor.log

Traceback (most recent call last):
File “./snowball/wsgi.py”, line 12, in
from django.core.wsgi import get_wsgi_application
ModuleNotFoundError: No module named ‘django’

Python 仮想環境にインストールされたパッケージを System-wide 環境にも設置してください。

[admin@centos7 backend]$ sudo pip install -r ./requirements.txt

uWSGIを再度起動します。

[admin@centos7 backend]$ sudo uwsgi –ini ./uwsgi/snowball_uwsgi.ini
[uWSGI] getting INI configuration from ./uwsgi/snowball_uwsgi.ini

http://192.168.10.10:8000 にアクセスします。
画面にあなたの Django アプリ関連ページが表示されれば OK です。

問題なければ、control + c コマンドでプロセスを終了しておきます。

Emperor モード

uWSGIemperor モードで実行できます。 このモードでは、uWSGI 構成ファイルのディレクトリを監視し、見つかった各インスタンス ( vassals ) を生成します。

Emperor モードを設定する

[admin@centos7 backend]$ sudo mkdir /etc/uwsgi
[admin@centos7 backend]$ sudo mkdir /etc/uwsgi/vassals
[admin@centos7 backend]$ sudo chown -R admin.nginx /etc/uwsgi

# symlink from the default config directory to your config file
[admin@centos7 backend]$ sudo ln -s /reactjs/snowball/backend/uwsgi/snowball_uwsgi.ini /etc/uwsgi/vassals/

emperor モードで実行する

実行する前に、下記をご確認ください。

sudo systemctl start nginx
sudo chown admin.nginx /run/uwsgi
iniファイルに chown-socket、chmod-socket 設定を追加したため、不要になります。
sudo chown nginx /run/uwsgi/snowball.sock
[admin@centos7 backend]$ sudo uwsgi --emperor /etc/uwsgi/vassals

http://192.168.10.10:8000 にアクセスします。
画面にあなたの Django アプリ関連ページが表示されれば OK です。

問題なければ、control + c コマンドでプロセスを終了しておきます。

uWSGI サービス自動起動を設定する

uWSGI の Systemd Unit File を作成する

[admin@centos7 backend]$ cat /etc/systemd/system/uwsgi.service
[Unit]
Description=uWSGI Emperor service
After=syslog.target

[Service]
ExecStartPre=/usr/bin/bash -c 'mkdir -p /run/uwsgi; chown nginx:nginx /run/uwsgi'
ExecStart=/usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals --uid nginx --gid nginx
Restart=always
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all

[Install]
WantedBy=multi-user.target

[admin@centos7 backend]$

uWSGI デーモン を起動する前に、uwsgi-emperor.log ファイルを生成し、所有者を下記のように設定してください。

[admin@centos7 backend]$ sudo touch /var/log/uwsgi/uwsgi-emperor.log
[admin@centos7 backend]$ sudo chown nginx.nginx /var/log/uwsgi/uwsgi-emperor.log

uWSGI デーモンを起動します。

[admin@centos7 backend]$ sudo systemctl start uwsgi.service

http://192.168.10.10:8000 にアクセスします。
画面に Django アプリ関連ページが表示されれば OK です。

モニタリングするなら、

sudo tail -f /var/log/nignx/error.log
sudo tail -f /var/log/uwsgi/uwsgi-emperor.log
journalctl -f -u uwsgi | nginx
sudo systemctl status uwsgi | nginx

問題なく動作するなら、付加オプションをつけましょう!( 任意 )

pidfile ファイルを生成

[admin@centos7 backend]$ vi uwsgi/snowball_uwsgi.ini
...
# create a pidfile
safe-pidfile = /run/uwsgi/snowball.pid

[admin@centos7 backend]$

Python Threads と Thunder Lock 機能を有効にする

[admin@centos7 backend]$ vi uwsgi/snowball_uwsgi.ini
...
enable-threads  = true
thunder-lock    = true

[admin@centos7 backend]$

よければ他の追加オプションも試してみてください。

env = DJANGO_SETTINGS_MODULE=mysite.settings # set an environment variable
harakiri = 20 # respawn processes taking more than 20 seconds
limit-as = 128 # limit the project to 128 MB
max-requests = 5000 # respawn processes after serving 5000 requests

emperor モード用 snowball_nginx.ini の完成版

[uwsgi]

# Django-related settings
# the base directory (full path)
chdir           = /reactjs/snowball/backend
# Django's wsgi file
module          = snowball.wsgi
# the virtualenv (full path)
#home           = /home/admin/.pyenv/versions/anaconda3-2019.03

# process-related settings
# master
master          = true
# maximum number of worker processes
processes       = 5
# the socket (use the full path to be safe
socket          = /run/uwsgi/snowball.sock
# socket permissions - when run nginx
chmod-socket    = 664
chown-socket    = nginx:nginx
# clear environment on exit
vacuum          = true

# python threads support
enable-threads  = true
# uwsgi thunder lock
thunder-lock    = true

# create a pidfile
safe-pidfile    = /run/uwsgi/snowball.pid

# background the process & log
daemonize       = /var/log/uwsgi/uwsgi-emperor.log                                                    

uWSGI デーモン を再起動して、サイトが正常に動作するか再度確認します。

[admin@centos7 backend]$ sudo systemctl restart uwsgi.service

問題なければ API サーバ の構築はこれで完了です。
お疲れ様でした!

スポンサーリンク

※ 2019/12/18 追記:
この後は、Nginx と連動してメール方式や Twitter アカウントでのユーザ認証機能を実装しました。興味のある方はご参考にどうぞ!▼

Django REST framework API サーバと Nginx WEB サーバを連動する|CentOS 7

メール認証方式のユーザ登録機能を実装する〜Reactjs + Django 環境|macOS〜

Twitter ソーシャルログイン機能を実装する〜Reactjs + Django〜

参考文献

How to deploy with WSGI
How to use Django with uWSGI
Setting up Django and your web server with uWSGI and nginx


WiMAX +5GをはじめるならBIGLOBE
公式特典!初期工事費実質0円!最大41,250円割引!おトクにauひかりをスタートできる!

コメント

タイトルとURLをコピーしました