1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

FreeBSDでgunicornのserviceスクリプトを作る

Last updated at Posted at 2022-10-04

プライベート用途でFreeBSDでApache+mod_wsgi+flaskという構成でサーバを建てていたのだけど、gunicornを使ってみようか、と思い始めてきました。
gunicornであれば、アプリケーションの再起動もApacheを再起動しなくても済みますしね。まぁプライベートなんで、再起動しても問題ないんですが。

で、gunicornを使うには、gunicornをサービスプログラムとして起動させなきゃいけません。
ubuntuでも使っていたのだけど、その場合にはsystemdの情報がいくらでもあったので困らないのだけど、FreeBSDの場合、古い情報だったり、英語だったりして、意外に少ない。
あいや、英語だからダメ、じゃコンピュータの仕事をしている人間としてアレなんで、何とか動かすところまで頑張ってみました。
頑張ったので、ホントに動かしてみただけ、正しいやり方かどうかまでは知らないので、あしからず。

とりあえず、本家のまず見るべき資料。

なお、以下は以下の環境で行いました。

FreeBSD test01.localdomain 12.2-RELEASE FreeBSD 12.2-RELEASE r366954 GENERIC  amd64

テストアプリケーション

テストするwsgiアプリケーションを以下のように用意しました。

/public/testweb/testweb.py
# coding: utf-8
from wsgiref.simple_server import make_server, demo_app as application
if __name__ == '__main__':
    with make_server('', 8080, application) as server:
        server.serve_forever()

pythonには、標準でwsgiref.simple_serverという、テスト用のwsgiアプリケーションのモジュールが用意されています。さすが、Python様だねっ!

これを動かすために、python3をインストールします。

pkg install python3

まずは、テストアプリケーションのみを動かしてみます。

python3 /public/testweb/testweb.py

これで、ブラウザより8080ポートにアクセスすると、「Hello world!」のメッセージと、環境変数が表示されます。
特に、「SERVER_SOFTWARE = 'WSGIServer/0.2'」のところに注目。

gunicornのインストール

gunicornをインストールします。
pkgでインストールしてもいいし、pipでインストールしてもいいし。この件に関しては、今回は置いときます。
今回は、pkgでインストールします。

pkg install py39-gunicorn

serviceスクリプトの作成

さて、ここからが本題。

/usr/local/etc/rc.d」ディレクトリ以下に、testwebという名前でスクリプトを作成します。

/usr/local/etc/rc.d/testweb
#!/bin/sh

# PROVIDE: testweb
# REQUIRE: NETWORKING

. /etc/rc.subr

name=testweb
rcvar=${name}_enable
testweb_user=katsuko

pidfile="/var/run/${name}/${name}.pid"

command="/usr/sbin/daemon"
command_args="-P ${pidfile} -r -f /usr/local/bin/gunicorn --bind '0.0.0.0:8080' --pythonpath /public/testweb testweb"

load_rc_config ${name}
run_rc_command "$1"

コメントにある「PROVIDE」は提供するサービスの名前、「REQUIRE」は依存する他のサービス名(rcスクリプト)だそうです。(ここより参照)
gunicornはwebサービスなので、NETWORINGを指定しました。

デフォルトではrootユーザでサービスプログラムが実行されますが、できればrootで動かしたくはないので、その場合には「サービス名_user」に実行ユーザを指定します。
なお、「pidfile」に「/var/run」ディレクトリ以下にディレクトリを作って、そこにファイルを作るようにしているのは、「/var/run」ディレクトリはroot権限でしかファイルを作成できないので、ディレクトリを作って実行ユーザに権限を与えます。

さて、肝となるのは「command」と「command_args」。
これは、サービスの開始コマンドで、以下のように実行されます。

${command} ${command_args}

このコマンドにより実行されたプロセスは、

  1. 実行中のサービスプログラムのプロセスIDを、「pidfile」で指定したファイルに書き込む。
  2. コマンド自体は、即座に終了しなければならない。(つまり、サービスプログラム自体はforkして動かなければならない)

という必要条件があります。

status/stopサブコマンドを実行した際、サービスプログラムのプロセスを探すわけですが、それは pidfileに書かれたプロセスIDで、かつプロセスコマンドがcommandのものかどうか(もしくは、procnameが指定されていればそちらを参照する) で判断されます。
(サービスプログラムがcommandでの実行と違う場合には、procnameを指定する必要があります)
この辺りが正しくないと、startは出来ても、status/stopは出来ず、散々悩むことになります。てか、悩みました。

さて、gunicornはプロセスIDをファイルに出力する設定はありますが、サービスをデーモンプロセスとして起動するやり方は見つけられませんでした。(もしあれば、失礼 ちゃんとありますがな。)
なので、daemonコマンドを使用します。

daemonコマンドは、上記の条件を満たしてくれる、とってもありがたいコマンドです。

最後に、このスクリプトに実行権を与えます。

chmod a+x /usr/local/etc/rc.d/testweb

これで、後はいつものサービス通り、「/etc/rc.conf」に「testweb_enable="YES"」を書き込み、「service testweb start」でサービスを起動し、またブラウザでアクセスしてみます。
先程のように「Hello world!」と環境変数地が表示されますが、中には「SERVER_SOFTWARE = 'gunicorn/20.1.0'」という表示に変わっているはずです。
これで、gunicornが動いていることを確認できます。

終わりに

今回はシンプルな(と思われる)スクリプトの書き方をしましたが、その気になればstartコマンドなどを上書きしてしまうことも出来ます。
まぁそこまでやりたいのであれば、「man rc.subr」を読んだり、「/etc/rc.subr」自体を読みましょう。
自分は疲れたので、ここまでにします。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?