venv 環境の Python responder アプリケーションを Apache 経由で動作させる
以前に Python + responder + gunicorn + systemd + Nginx で Web アプリを起動する というメモを書きました。 Apache2 + responder に置き換えた内容で改めてメモしておきます。 Python アプリケーションは venv 環境の中に作成します。
Apache2 のインストール
Apache をインストールしておきます。 これで Apache 用のユーザ www-data
が作成されます。
Python3 をインストールする
Python3 をインストールします。 今回は Python 3.9.5 がインストールされました。
| apt -y install python3.9 python3.9-venv python3-pip && \
update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.9 10
|
venv 環境を作成する
venv 環境を作成します。 あわせて gunicorn と responder をインストールしておきます。
| mkdir /opt/hello
cd /opt/hello
python3 -m venv .venv
echo 'source .venv/bin/activate' > .envrc
direnv allow
python3 -m pip install --upgrade pip gunicorn responder typesystem==0.2.5
|
Python スクリプトの配置
必要な Python スクリプトを配置していきます。
/opt/hello/main.py
今回のアプリケーションの実体となる main.py
を配置します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | cat << 'EOF' > /opt/hello/main.py
import responder
api = responder.API()
@api.route("/{who}")
def greet_world(req, resp, *, who):
resp.text = f"Hello, {who}!"
if __name__ == '__main__':
api.run()
EOF
|
/opt/hello/settings.py
gunicorn 用の設定ファイルも用意しておきます。
| cat << 'EOF' > /opt/hello/settings.py
worker_class = 'uvicorn.workers.UvicornWorker'
EOF
|
PID 及び Socket ファイルの用意
後の手順でデーモン化する為、PID ファイルを用意しておきます。
| mkdir /run/hello/
touch /run/hello/pid
chown -R www-data:www-data /run/hello/
|
続いて Socket ファイルも用意しておきます。
| cat << 'EOF' > /etc/systemd/system/hello.socket
[Unit]
Description=hello socket
[Socket]
ListenStream=/run/hello.sock
User=www-data
[Install]
WantedBy=sockets.target
EOF
|
ソケットファイルを有効化しておきます。
| systemctl enable --now hello.socket
|
Apache の準備
Apache を Reverse Proxy として利用する為の設定ファイルを用意しておきます。 今回は UNIX Domain Socket を利用します。
| cat << 'EOF' > /etc/apache2/conf-available/responder.conf
ProxyRequests Off
ProxyPass "/" "unix:/run/hello.sock|http://127.0.0.1/"
ProxyPassReverse "/" "unix:/run/hello.sock|http://127.0.0.1/"
EOF
|
設定を有効化します。 あわせてモジュールの有効化も行います。
| a2enconf responder
a2enmod proxy_http proxy
|
念の為、コンフィグテストを実施して文法に問題が無いことを確認しておきます。
Apache の設定変更を反映しておきます。
サービスの登録
responder アプリケーションを systemctl へデーモンとして登録すべく、設定ファイルを用意します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | cat << EOF > /etc/systemd/system/hello.service
[Unit]
Description=Hello
Requires=hello.socket
After=network.target
[Service]
Type=notify
User=www-data
Group=www-data
Environment="PATH=/opt/hello/.venv/bin"
RuntimeDirectory=gunicorn
WorkingDirectory=/opt/hello
ExecStart=/opt/hello/.venv/bin/gunicorn main:api --config settings.py
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
|
登録したサービスを起動します。
| systemctl daemon-reload
systemctl start hello.service
systemctl enable hello.service
systemctl status hello.service
|
クライアントからアクセスする
curl 等からテストアクセスし、意図したレスポンスが返ってくることを確認します。
| # curl http://127.0.0.1/world
Hello, world!
|
gunicorn を起動する
サービスとして起動せずエラーになる場合は以下のように gunicorn 単体で実行し、問題を切り分けます。
| gunicorn --bind=0.0.0.0:8000 --config settings.py main:api
|