Jaybanuan's Blog

どうせまた調べるハメになることをメモしていくブログ

systemdのユニットファイルをテンプレート化する

はじめに

複数のサービスを自作してsystemdで管理するときに、作成するユニットファイルの中身が大体同じということがある。 こういう場合はユニットファイルのテンプレート化が有効なので、そのやり方をメモしておく。 動作確認は簡単にしたいので、ここではWebサーバのポート番号を変数化したユニットファイルを作成することにした。

環境

$ cat /etc/os-release | grep PRETTY_NAME
PRETTY_NAME="Ubuntu 18.04.4 LTS"

$ python3 --version
Python 3.6.9

事前準備

いろいろWebサーバを探してみたものの、ポート番号を引数に渡して起動できる手頃なWebサーバが見当たらなかったので、自前で作成することにした。 まずは、以下の内容で/opt/test-web-server/test-web-server.pyを作成する。

#!/usr/bin/env python3

from sys import argv
from http.server import BaseHTTPRequestHandler
from http.server import HTTPServer

class ServerAddressHandler(BaseHTTPRequestHandler):

    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/plain')
        self.end_headers()

        text = 'server_address = ' + str(self.server.server_address) + '\r\n'
        self.wfile.write(text.encode('utf-8'))


if __name__ == '__main__':
    port = int(argv[1])

    httpd = HTTPServer(('0.0.0.0', port), ServerAddressHandler)
    httpd.serve_forever()

このファイルに実行権限をつけておく。

$ chmod a+x /opt/test-web-server/test-web-server.py

動作確認のために、待受ポートの10080を引数に指定して、このWebサーバを起動する。

$ /opt/test-web-server/test-web-server.py 10080

別のターミナルからcurlでWebサーバにアクセスすると、待ち受けているIPアドレスとポート番号を取得できる。

$ curl http://localhost:10080
server_address = ('0.0.0.0', 10080)

これで事前準備は完了。 起動したWebサーバを停止しておく。

ユニットファイルの作成と、ひとつめのサービスの登録

次の内容でファイル/etc/systemd/system/test-web-server@.serviceを作成する。

[Unit]
Description=Test Web Server with port %i

[Service]
Type=simple
ExecStart=/opt/test-web-server/test-web-server.py %i

[Install]
WantedBy=multi-user.target

具体化されたサービスの作成方法は、コマンドラインを見た方が分かりやすい。 例えば、ポート番号10080で待ち受けるサービスを登録するには以下のようにする。

$ sudo systemctl enable --now test-web-server@10080
Created symlink /etc/systemd/system/multi-user.target.wants/test-web-server@10080.service → /etc/systemd/system/test-web-server@.service.

つまり、ユニットファイルのファイル名、すなわちサービス名の@以降が変数%iに割り当てられる。 ここで登録したサービスの状態を確認するには、同様にサービス名の@以降に10080を指定してsystemctl statusを実行すればよい。

$ systemctl status test-web-server@10080
● test-web-server@10080.service - Test Web Server with port 10080
   Loaded: loaded (/etc/systemd/system/test-web-server@.service; indirect; vendor preset: enabled)
   Active: active (running) since Sat 2020-02-08 17:29:13 JST; 5min ago
 Main PID: 4632 (python3)
    Tasks: 1 (limit: 4637)
   CGroup: /system.slice/system-test\x2dweb\x2dserver.slice/test-web-server@10080.service
           └─4632 python3 /opt/test-web-server/test-web-server.py 10080

 2月 08 17:29:13 ubuntu1804 systemd[1]: Started Test Web Server with port 10080.

想定通り%i10080に置き換わっていることが分かる。 では、curlを実行してWebサーバの動作確認をしてみる。

$ curl http://localhost:10080
server_address = ('0.0.0.0', 10080)

事前準備の時と同様に、待ち受けているIPアドレスとポート番号が正しく表示された。

ふたつめのサービスの登録

次はポート番号20080で待ち受ける、ふたつめのサービスを登録してみる。

$ sudo systemctl enable --now test-web-server@20080
Created symlink /etc/systemd/system/multi-user.target.wants/test-web-server@20080.service → /etc/systemd/system/test-web-server@.service.

確認のため、名前がtest-web-server@から始まるサービスをリストする。

$ systemctl list-units -t service 'test-web-server@*'
UNIT                          LOAD   ACTIVE SUB     DESCRIPTION                    
test-web-server@10080.service loaded active running Test Web Server with port 10080
test-web-server@20080.service loaded active running Test Web Server with port 20080

(以下略)

想定通り、ポート番号が10080のサービスと20080のサービスが表示されている。 では、curlを実行してWebサーバの動作確認をしてみる。

$ curl http://localhost:10080
server_address = ('0.0.0.0', 10080)

$ curl http://localhost:20080
server_address = ('0.0.0.0', 20080)

ポート番号が10080のWebサーバも、20080のWebサーバも正しく動作していることが分かる。

参考