init スクリプトを systemd unit ファイルに変換する
Environment
- Red Hat Enterprise Linux 7
Issue
- Red Hat Enterprise Linux 6 以前のバージョンの init スクリプトを systemd unit ファイルに移植して Red Hat Enterprise Linux 7 以降で動くようにするには
- init スクリプトを systemd unit ファイルに変換するには
- カスタムの init スクリプトを変更して systemd と互換性を持たせるには
Resolution
以下の情報は例として提供されるものであり、すべての状況で正しく動作することが保証されているわけではありません。Red Hat サポートは、unit ファイルの設定と構文に関する質問にはお答えできますが、移植されるスクリプトを提供することは弊社のサポート対象外となります。
Red Hat Enterprise Linux 7 で管理されているすべてのパッケージは、systemd がすでに動作している状態でインストールされます。Red Hat Enterprise Linux 7 で実行することが認定されているソフトウェアを提供しているすべてのサードパーティは、Red Hat Enerprise Linux 7 の systemd unit ファイルを含めて提供すべきであるということになります。サードパーティソフトウェアプロバイダに確認することなくお客様独自に init スクリプトを移植することは行わないでください。事前にサードパーティソフトウェアプロバイダに確認の上、適切な unit ファイルの提供を依頼してください。
以下の例では、簡易的なデーモンをコンパイルして、そのデーモンの init スクリプトを作成します。その後、init スクリプトを systemd unit ファイルに移植します。
I. Hello World のデーモン
RHEL 6 システムを起動して、以下のように、gcc、lsof、wget、および telnet クライアントをインストールします。
yum install gcc lsof wget telnet
次に、以下から取得したものを使用して簡易的なデーモンを作成します。以下で提供されるデーモンは単なる例であり、サポート対象外となりますが、使用することはできます。
http://www.catb.org/esr/cookbook/helloserver.c
このデーモンはポート 30153 でリッスンし、入力したものをエコーバックした後、接続を閉じて引き続き実行します。以下のコマンドでデーモンを作成します。
wget http://www.catb.org/esr/cookbook/helloserver.c
gcc -o hellod helloserver.c
sudo mv hellod /usr/local/bin/
デーモンを起動します。
/usr/local/bin/hellod
実行していることを確認し、PID を取得します。
[root@rhel6 hello]# ps axu | grep hellod
root 2893 0.0 0.1 6164 584 ? S 14:21 0:00 /usr/local/bin/hellod
root 2895 0.0 0.1 103244 828 pts/0 S+ 14:21 0:00 grep hellod
[root@rhel6 hello]#
そのプロセスがどのファイルを開いているかを確認します。
[root@rhel6 hello]# lsof -p 2893
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
hellod 2893 root cwd DIR 253,0 4096 2 /
hellod 2893 root rtd DIR 253,0 4096 2 /
hellod 2893 root txt REG 253,0 17468 145414 /usr/local/bin/hellod
hellod 2893 root mem REG 253,0 65928 133364 /lib64/libnss_files-2.12.so
hellod 2893 root mem REG 253,0 1921216 133348 /lib64/libc-2.12.so
hellod 2893 root mem REG 253,0 154520 133336 /lib64/ld-2.12.so
hellod 2893 root 0u CHR 1,3 0t0 3782 /dev/null
hellod 2893 root 1u CHR 1,3 0t0 3782 /dev/null
hellod 2893 root 2u CHR 1,3 0t0 3782 /dev/null
hellod 2893 root 3u REG 253,0 5 80 /var/run/helloserver.pid
hellod 2893 root 4u unix 0xffff88001de616c0 0t0 18774 socket
hellod 2893 root 5u IPv4 18775 0t0 TCP *:30153 (LISTEN)
[root@rhel6 hello]#
デーモンをテストします。
[root@rhel6 hello]# telnet localhost 30153
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hello
hello
Connection closed by foreign host.
[root@rhel6 hello]#
デーモンを kill して、クリーンアップされたことを確認します。
[root@rhel6 hello]# ls /var/run/ | grep hello
helloserver.pid
[root@rhel6 hello]# kill 2893
[root@rhel6 hello]# ls /var/run/ | grep hello
[root@rhel6 hello]#
これで、init スクリプトを作成するためのデーモンが作成できました。
II. RHEL 6 の Hello World 用 System V Init スクリプト
次に、hellod の init スクリプトを作成します。
touch /etc/init.d/hello
chmod 755 /etc/init.d/hello
以下の行を /etc/init.d/hello に追加します。
#!/bin/bash
#
# chkconfig: 35 90 12
# description: Hello Daemon
以下は注意点になります。
chckconfig
行を追加すると、chckconfig
コマンドでスクリプトを管理できます。35
は、ランレベル 3 および 5 で起動することを示しています。90
は起動優先度です (最後のサービスの一つが起動します)。12
は kill する順番です (最初のサービスの一つが kill されます)。
次に、以下をその次の行に追加し、これ以降の手順で init スクリプトの残りの部分が include することになる functions の 800 行ファイルをここで include しておきます。
./etc/init.d/functions
その後、hellod サービスを起動する次の 8 行を追加します。success ファンクションは /etc/init.d/functions 中で定義されています。
start() {
echo -n "Starting Hello Server: "
/usr/local/bin/hellod
# touch the lock file
touch /var/lock/subsys/hellod
success $"Hello Server startup"
echo
}
次に、hellod サービスを停止する以下の行を追加します。
stop() {
echo -n "Stopping Hello Server: "
killproc hellod
# Remove the lock file
rm -f /var/lock/subsys/hellod
echo
}
最後に、入力が正しく処理され、start および stop ファンクションをコールするよう、以下の 18 行を追加します。killproc ファンクションは /etc/init.d/functions 中で定義されています。
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status servicename
;;
restart|reload|condrestart)
stop
start
;;
*)
echo $"Usage: $0 {start|stop|restart|reload|status}"
exit 1
esac
新しい init スクリプトを保存して、適切に動作することを確認します。
[root@rhel6 ~]# /etc/init.d/hello status
hellod is stopped
[root@rhel6 ~]# /etc/init.d/hello start
Starting Hello Server: [ OK ]
[root@rhel6 ~]# /etc/init.d/hello status
hellod (pid 3780) is running...
[root@rhel6 ~]# telnet localhost 30153
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hello
hello
Connection closed by foreign host.
[root@rhel6 ~]# /etc/init.d/hello stop
Stopping Hello Server: [ OK ]
[root@rhel6 ~]# /etc/init.d/hello status
hellod is stopped
[root@rhel6 ~]#
これで正しく動作する init スクリプトを作成できました。次に、init スクリプトが RHEL 7 で動作するように systemd に移植します。
III. RHEL7 の Hello World 用 Systemd Unit ファイル
/usr/local/bin/hellod のバイナリーを RHEL 6 から RHEL 7 に移動して、動作することを確認します。
unit ファイルを保存する /etc/systemd/system/hellod.service を作成します。パッケージメンテナーの unit ファイルは /usr/lib/systemd/system/ に存在する必要があり、systemd は /etc を優先するため、修正する場合は /etc/systemd/system/ にコピーする必要があります。
touch /etc/systemd/system/hellod.service
chmod 644 /etc/systemd/system/hellod.service
以下の 10 行を /etc/systemd/system/hellod.service に追加します。
[Unit]
Description=Hello Service
After=network.target
[Service]
ExecStart=/usr/local/bin/hellod
Type=forking
PIDFile=/var/run/helloserver.pid
[Install]
WantedBy=multi-user.target
上の 10 行を保存したら unit ファイルは終了です。詳細は、以下のようになります。
最初のセクションである [Unit] には、サービスの説明が含まれます。また、After= タイプの依存関係も設定されます。これは、サーバーでネットワークが実行されるまでこのネットワークサービスが起動しないことを意味します。
2 番目のセクション [Service] では、ExecStart= を使用して、サービスの起動時に実行するバイナリーへのパスを定義しています。元々のプログラムは forking デーモンであるため Type=forking を設定します。その他の種類については systemd.service の man ページを参照してください。forking を使用している場合は PIDFile= オプションを使用して、systemd がデーモンのメインプロセスを特定できるようにすることが推奨されます。上述の lsof
の例では、デーモンによって作成された pid ファイルは /var/run/helloserver.pid でした。それを PIDFile= に明示的に設定します。
3 番目のセクション [Install] では WantedBy= を使用します。これは RHEL6 のランレベル 3 の状態であるマルチユーザーモードでサービスが起動しているべきであることを示しています。
systemd サービスファイルが作成できましたので、以下のコマンドを実行し、それが存在することを systemd に通知する必要があります。
systemctl daemon-reload
新しいサービスを開始します。
systemctl start hellod
テストします。
[root@rhel7 ~]# telnet localhost 30153
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hey
hey
Connection closed by foreign host.
[root@rhel7 ~]#
ステータスを確認します。
[root@rhel7 ~]# systemctl status hellod
hellod.service - Hello Daemon
Loaded: loaded (/etc/systemd/system/hellod.service; disabled)
Active: active (running) since Mon 2014-06-16 17:15:57 EDT; 1min 38s ago
Process: 11812 ExecStart=/usr/local/bin/hellod (code=exited, status=0/SUCCESS)
Main PID: 11814 (hellod)
CGroup: /system.slice/hellod.service
└─11814 /usr/local/bin/hellod
Jun 16 17:15:57 rhel7.example.com systemd[1]: Starting Hello Daemon...
Jun 16 17:15:57 rhel7.example.com systemd[1]: Started Hello Daemon.
[root@rhel7 ~]#
再起動すると PID が変更します。
[root@rhel7 ~]# systemctl restart hellod
[root@rhel7 ~]# systemctl status hellod
hellod.service - Hello Daemon
Loaded: loaded (/etc/systemd/system/hellod.service; disabled)
Active: active (running) since Mon 2014/06/16 17:23:54 EDT; 2s ago
Process: 11898 ExecStart=/usr/local/bin/hellod (code=exited, status=0/SUCCESS)
Main PID: 11900 (hellod)
CGroup: /system.slice/hellod.service
└─11900 /usr/local/bin/hellod
Jun 16 17:23:54 rhel7.example.com systemd[1]: Starting Hello Daemon...
Jun 16 17:23:54 rhel7.example.com systemd[1]: Started Hello Daemon.
[root@rhel7 ~]#
デーモンを停止します。
systemctl stop hellod
基本的な init スクリプトを systemd に移植し、コードの 40 行を 10 行で上書きしました。サービスに対して systemd unit ファイルを書く際のより詳細な情報については systemd.service の man ページを参照してください。
This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.
Comments