【3日目】お約束のHello World!を表示させる

お約束の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!と表示されました。

やっとここまで来ることができました!

コメント

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