Skip to content

venv 環境の Python responder アプリケーションを Apache 経由で動作させる

以前に Python + responder + gunicorn + systemd + Nginx で Web アプリを起動する というメモを書きました。 Apache2 + responder に置き換えた内容で改めてメモしておきます。 Python アプリケーションは venv 環境の中に作成します。

Apache2 のインストール

Apache をインストールしておきます。 これで Apache 用のユーザ www-data が作成されます。

1
apt -y install apache2

Python3 をインストールする

Python3 をインストールします。 今回は Python 3.9.5 がインストールされました。

1
2
apt -y install python3.9 python3.9-venv python3-pip && \
update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.9 10

venv 環境を作成する

venv 環境を作成します。 あわせて gunicornresponder をインストールしておきます。

1
2
3
4
5
6
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 用の設定ファイルも用意しておきます。

1
2
3
cat << 'EOF' > /opt/hello/settings.py
worker_class = 'uvicorn.workers.UvicornWorker'
EOF

PID 及び Socket ファイルの用意

後の手順でデーモン化する為、PID ファイルを用意しておきます。

1
2
3
mkdir /run/hello/
touch /run/hello/pid
chown -R www-data:www-data /run/hello/

続いて Socket ファイルも用意しておきます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
cat << 'EOF' > /etc/systemd/system/hello.socket
[Unit]
Description=hello socket

[Socket]
ListenStream=/run/hello.sock
User=www-data

[Install]
WantedBy=sockets.target
EOF

ソケットファイルを有効化しておきます。

1
systemctl enable --now hello.socket

Apache の準備

Apache を Reverse Proxy として利用する為の設定ファイルを用意しておきます。 今回は UNIX Domain Socket を利用します。

1
2
3
4
5
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

設定を有効化します。 あわせてモジュールの有効化も行います。

1
2
a2enconf responder
a2enmod proxy_http proxy

念の為、コンフィグテストを実施して文法に問題が無いことを確認しておきます。

1
apache2ctl configtest

Apache の設定変更を反映しておきます。

1
systemctl reload apache2

サービスの登録

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

登録したサービスを起動します。

1
2
3
4
systemctl daemon-reload
systemctl start hello.service
systemctl enable hello.service
systemctl status hello.service

クライアントからアクセスする

curl 等からテストアクセスし、意図したレスポンスが返ってくることを確認します。

1
2
# curl http://127.0.0.1/world
Hello, world!

gunicorn を起動する

サービスとして起動せずエラーになる場合は以下のように gunicorn 単体で実行し、問題を切り分けます。

1
gunicorn --bind=0.0.0.0:8000 --config settings.py main:api