お約束のHello World
まずはじめに、Python + Flask + uWSGI + Nginxの環境で、お約束のHello World!を表示させてみようと思います。
Bard先生にHello World!を表示させるための方法を聞いてみたところ、以下のファイルを作成する必要があることを教えてくれましたのでそれぞれ作成していきます。
- Pythonスクリプト app.py
- uWSGI設定ファイル uwsgi.ini
- nginx設定ファイル helloworld.conf(ファイル名は私が適当につけました)
まずは、ファイル中身は教えてもらったままの内容作成していきます。
ファイルの作成場所
まずはファイルの作成場所についてですが、特に指定はありませんでしたがapp.pyとuwsgi.iniについては、Pythonの仮想環境のために用意した「/home/tamohiko/project_py/HelloWorld」ディレクトリの中に作成していきます。
仮想環境で使用するファイルはまとめておいたほうが管理しやすいですからね。
/home/tamohiko/project_py/ ### このディレクトリの中に仮想環境を作成 └── HelloWorld ### 作成した仮想環境のディレクトリ ├── bin ├── include ├── lib ├── lib64 -> lib └── pyvenv.cfg
Nginxの設定ファイルhelloworld.confについては、/etc/nginx/conf.d/ディレクトリに作成していきます。
Python仮想環境の有効化
2日目に作成したPythonの仮想環境を有効化します。
$ cd ~/project_py $ source HelloWorld/bin/activate (HelloWorld) $
すでに有効化している場合はこの作業は必要ありません。
Pythonのスクリプト作成
仮想環境のディレクトリに移動して、そこでスクリプトをapp.pyという名前で作成していきます。
スクリプトの内容はBard先生に教えてもらった物をそのまま使用します。
(HelloWorld) $ cd HelloWorld (HelloWorld) $ vi app.py
スクリプト中身はこんな感じです。
# Flaskモジュールをインポート from flask import Flask # Flaskアプリケーションをインスタンス化 # __name__は、スクリプトのファイル名を表す変数 app = Flask(__name__) # URLパターンを「/」として定義 @app.route("/") # URLパターンに対応する関数を関数名index()として定義 def index(): # 関数の戻り値を「Hello, World!」に設定 return "Hello, World!" # スクリプトが直接実行された場合にのみ実行するという条件文 if __name__ == "__main__": # Flaskアプリケーションを起動 # debug=Trueでデバッグモードで起動 app.run(debug=True)
動作確認
作成したスクリプトを実行して、単体での動作確認を行ってみます。
$ python ./app.py * Serving Flask app 'app' * Debug mode: on WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on http://127.0.0.1:5000 Press CTRL+C to quit * Restarting with stat * Debugger is active! * Debugger PIN: 113-163-717
表示されたログを見ると「Running on http://127.0.0.1:5000」と表示されているので、5000番ポートにhttpでアクセスすると「Hello, World!」と表示されるはずです。
curlで動作確認
app.pyを実行すると画面にログが表示されたままの状態になり、Ubuntuのコマンドを入力することができなくなります。
なので、別途SSHでサーバに接続して動作確認を行っていきます。
動作確認はcurlでlocalhostの5000番ポートに接続して、「Hello, World!」が表示されるかの確認を行います。
$ curl -v localhost:5000 * Trying 127.0.0.1:5000... * Connected to localhost (127.0.0.1) port 5000 (#0) > GET / HTTP/1.1 > Host: localhost:5000 > User-Agent: curl/7.81.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Server: Werkzeug/3.0.1 Python/3.10.12 < Date: Sat, 18 Nov 2023 02:44:38 GMT < Content-Type: text/html; charset=utf-8 < Content-Length: 13 < Connection: close < * Closing connection 0 Hello, World!
無事「Hello, World!」が表示されました!
スクリプトを実行した画面にも、「127.0.0.1 - - [18/Nov/2023 11:44:25] "GET / HTTP/1.1" 200 -」とログが表示されているので、こちらでもアクセスがあったことが分かります。
* Running on http://127.0.0.1:5000 Press CTRL+C to quit * Restarting with stat * Debugger is active! * Debugger PIN: 113-163-717 127.0.0.1 - - [18/Nov/2023 11:44:25] "GET / HTTP/1.1" 200 -
スクリプトの終了
スクリプト単体での動作確認が終わったので、Ctrl + c で終了させます。
スクリプトを終了させると、Ubuntuのコマンド入力まち状態に戻ります。
* Running on http://127.0.0.1:5000 Press CTRL+C to quit * Restarting with stat * Debugger is active! * Debugger PIN: 113-163-717 127.0.0.1 - - [18/Nov/2023 11:44:25] "GET / HTTP/1.1" 200 - 127.0.0.1 - - [18/Nov/2023 11:44:38] "GET / HTTP/1.1" 200 - ^C(HelloWorld) $
uWSGI設定ファイル作成
uWSGIサーバを使用してスクリプト実行させるために、uWSGIの設定ファイルをuwsgi.iniという名前で作成します。
(HelloWorld) $ vi uwsgi.ini
Bard先生に教えてもらった設定をそのまま使っていきます。
[uwsgi] module = app master = true processes = 4 socket = /tmp/uwsgi.sock chmod-socket = 666 vacuum = true die-on-term = true
uWSGIの起動
作成したuwsgi.iniを設定ファイルとして指定してuWSGIを起動させます。
$ uwsgi --ini ./uwsgi.ini [uWSGI] getting INI configuration from ./uwsgi.ini *** Starting uWSGI 2.0.23 (64bit) on [Sat Nov 18 12:01:02 2023] *** compiled with version: 11.4.0 on 17 November 2023 06:28:39 os: Linux-5.15.0-88-generic #98-Ubuntu SMP Mon Oct 2 15:18:56 UTC 2023 nodename: xxx-xxx-xxx-xxx ### IPアドレスだったのマスクしました machine: x86_64 clock source: unix detected number of CPU cores: 2 current working directory: /home/tamohiko/project_py/HelloWorld detected binary path: /home/tamohiko/project_py/HelloWorld/bin/uwsgi !!! no internal routing support, rebuild with pcre support !!! your processes number limit is 3376 your memory page size is 4096 bytes detected max file descriptor number: 1024 lock engine: pthread robust mutexes thunder lock: disabled (you can enable it with --thunder-lock) uwsgi socket 0 bound to UNIX address /tmp/uwsgi.sock fd 3 Python version: 3.10.12 (main, Jun 11 2023, 05:26:28) [GCC 11.4.0] *** Python threads support is disabled. You can enable it with --enable-threads *** Python main interpreter initialized at 0x55f890c917d0 your server socket listen backlog is limited to 100 connections your mercy for graceful operations on workers is 60 seconds mapped 364520 bytes (355 KB) for 4 cores *** Operational MODE: preforking *** unable to load app 0 (mountpoint='') (callable not found or import error) *** no app loaded. going in full dynamic mode *** *** uWSGI is running in multiple interpreter mode *** spawned uWSGI master process (pid: 1726) spawned uWSGI worker 1 (pid: 1727, cores: 1) spawned uWSGI worker 2 (pid: 1728, cores: 1) spawned uWSGI worker 3 (pid: 1729, cores: 1) spawned uWSGI worker 4 (pid: 1730, cores: 1)
curlで動作確認
uWSGIを起動すると、スクリプトを単体で実行したときと同じでログが表示された状態のままになります。
なのでスクリプトの単体試験を行った時と同じように、別途SSHでサーバに接続してcurlで動作確認を行います。
$ curl -v http://localhost:5000 * Trying 127.0.0.1:5000... * connect to 127.0.0.1 port 5000 failed: Connection refused * Trying ::1:5000... * connect to ::1 port 5000 failed: Connection refused * Failed to connect to localhost port 5000 after 0 ms: Connection refused * Closing connection 0 curl: (7) Failed to connect to localhost port 5000 after 0 ms: Connection refused
Connection refusedで接続できませんでした…
uWSGIの実行画面に表示されているログを確認するとエラーっぽいログがありました。
unable to load app 0 (mountpoint='') (callable not found or import error)
Bard先生に質問してみる
uWSGIを実行すると下記のエラーが表示されますが、原因と対応方法を教えてください unable to load app 0 (mountpoint='') (callable not found or import error)
このエラーの原因は、uWSGIがロードしようとしているアプリケーションが存在しない、またはロードできないことです。
対応としてはcallableという設定を入れれば良いみたいのなので、下記の設定を追加してuWSGIを再起動してみます。
[uwsgi] module = app callable = app ### 追加した設定 master = true processes = 4 socket = /tmp/uwsgi.sock chmod-socket = 666 vacuum = true die-on-term = true
とりあえずエラーは表示されなくなりました。
WSGI app 0 (mountpoint='') ready in 1 seconds on interpreter 0x557426a8cfc0 pid: 1689 (default app)
再度curlで動作確認を行ってみます。
$ curl -v http://localhost:5000 * Trying 127.0.0.1:5000... * connect to 127.0.0.1 port 5000 failed: Connection refused * Trying ::1:5000... * connect to ::1 port 5000 failed: Connection refused * Failed to connect to localhost port 5000 after 0 ms: Connection refused * Closing connection 0 curl: (7) Failed to connect to localhost port 5000 after 0 ms: Connection refused
再度Connection refusedとなってしまいました…
uWSGIが使用しているポートが違うのかなと思い、現在の接続待ちポートの状況をnetstatで確認して見ることにしました。
$ netstat -atn Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 0.0.0.0:25 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:587 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:10022 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:995 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:993 0.0.0.0:* LISTEN tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN tcp 0 80 xxx.xxx.xxx.xxx:10022 xxx.xxx.xxx.xxx:52632 ESTABLISHED tcp 0 0 xxx.xxx.xxx.xxx:10022 xxx.xxx.xxx.xxx:57749 ESTABLISHED tcp6 0 0 :::10022 :::* LISTEN
uWSGIが待受しているようなポートが見当たりませんので、Connection refusedになるのは当たり前ですね。
uWSGIにhttp接続する場合はhttpの設定が必要
設定ファイルにはsocketに関する「socket = /tmp/uwsgi.sock」という設定はありましたが、http接続に関する設定がありませんでした。
もしかしてhttpで接続するためには別途設定が必要なのではと思いBard先生に聞いてみると、やはりhttpに関する設定が別途必要になるようです。
下記の設定はhttpの5000番ポートで接続する場合の設定となります。
http = :5000
httpの設定を追加したものが下記の通りとなります。(socketの設定をコメント化してあります)
[uwsgi] module = app callable = app master = true processes = 4 #socket = /tmp/uwsgi.sock ### 元の設定 http = :5000 ### 追加した設定 chmod-socket = 666 vacuum = true die-on-term = true
これでuWSGIを実行してみます。
$ uwsgi --ini ./uwsgi.ini [uWSGI] getting INI configuration from uwsgi.ini *** Starting uWSGI 2.0.23 (64bit) on [Sun Nov 19 00:30:20 2023] *** compiled with version: 11.4.0 on 17 November 2023 06:28:39 os: Linux-5.15.0-88-generic #98-Ubuntu SMP Mon Oct 2 15:18:56 UTC 2023 nodename: xxx-xxx-xxx-xxx ### IPアドレスはマスクしてあります machine: x86_64 clock source: unix detected number of CPU cores: 2 current working directory: /home/tamohiko/project_py/HelloWorld detected binary path: /home/tamohiko/project_py/HelloWorld/bin/uwsgi !!! no internal routing support, rebuild with pcre support !!! your processes number limit is 3376 your memory page size is 4096 bytes detected max file descriptor number: 1024 lock engine: pthread robust mutexes thunder lock: disabled (you can enable it with --thunder-lock) uWSGI http bound on :5000 fd 4 uwsgi socket 0 bound to TCP address 127.0.0.1:40123 (port auto-assigned) fd 3 Python version: 3.10.12 (main, Jun 11 2023, 05:26:28) [GCC 11.4.0] *** Python threads support is disabled. You can enable it with --enable-threads *** Python main interpreter initialized at 0x557df1062e60 your server socket listen backlog is limited to 100 connections your mercy for graceful operations on workers is 60 seconds mapped 364520 bytes (355 KB) for 4 cores *** Operational MODE: preforking *** WSGI app 0 (mountpoint='') ready in 0 seconds on interpreter 0x557df1062e60 pid: 2804 (default app) *** uWSGI is running in multiple interpreter mode *** spawned uWSGI master process (pid: 2804) spawned uWSGI worker 1 (pid: 2805, cores: 1) spawned uWSGI worker 2 (pid: 2806, cores: 1) spawned uWSGI worker 3 (pid: 2807, cores: 1) spawned uWSGI worker 4 (pid: 2808, cores: 1) spawned uWSGI http 1 (pid: 2809)
uWSGI http bound on :5000 fd 4と表示されたので、httpが使用できるようになっているはずです。
curlで動作テストを行ってみます。
$ curl -v localhost:5000 * Trying 127.0.0.1:5000... * Connected to localhost (127.0.0.1) port 5000 (#0) > GET / HTTP/1.1 > Host: localhost:5000 > User-Agent: curl/7.81.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Content-Type: text/html; charset=utf-8 < Content-Length: 13 < * Connection #0 to host localhost left intact Hello, World!
Hello, World!がやっと表示されました!
Nginx設定ファイル
uWSGIサーバとNginxを連携させるための設定ファイルを作成します。
$ sudo vi /etc/nginx/conf.d/helloworld.conf
設定内容は下記のとおりです。
server { listen 80; server_name hello.server-memo.net; location / { proxy_pass http://127.0.0.1:5000; } }
Nginxを再起動して設定を反映させます。
$ sudo systemctl restart nginx
Webブラウザからの動作確認
Nginxの設定でserver_nameをhello.server-memo.netと設定していますが、このホスト名はDNSには登録していません。
ですので、Webブラウザで接続して動作確認をする前に、クライアント側のhostsを編集してNginxのserver_nameで設定したホスト名の名前解決が出来るようにしておく必要があります。
hostsの設定変更後ブラウザでアクセスすると、無事Hello, World!と表示されました。
やっとここまで来ることができました!
コメント