以前に Python + responder + gunicorn + systemd + Nginx で Web アプリを起動する というメモを書きました。 Apache2 + responder に置き換えた内容で改めてメモしておきます。 Python アプリケーションは venv 環境の中に作成します。
Apache2 のインストール
Apache をインストールしておきます。 これで Apache 用のユーザ www-data
が作成されます。
apt -y install apache2
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
を配置します。
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
念の為、コンフィグテストを実施して文法に問題が無いことを確認しておきます。
apache2ctl configtest
Apache の設定変更を反映しておきます。
systemctl reload apache2
サービスの登録
responder アプリケーションを systemctl へデーモンとして登録すべく、設定ファイルを用意します。
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
コメント