Translated message

A translation of this page exists in English.

init スクリプトを systemd ユニットファイルに変換する方法

Solution In Progress - Updated -

Environment

  • Red Hat Enterprise Linux 7
  • Red Hat Enterprise Linux 8
  • Red Hat Enterprise Linux 9

Issue

  • Red Hat Enterprise Linux 6 以前のバージョン用の init スクリプトがあります。これを systemd ユニットファイルに移植して、Red Hat Enterprise Linux 7 以降で動作するようにしたいと考えています。
  • init スクリプトを systemd ユニットファイルに変換するにはどうしたらよいですか?
  • カスタム init スクリプトを systemd と互換性があるように変更したいと考えています。

Resolution

以下の情報は一例として提示しており、状況を問わず保証されるものではありません。Red Hat サポートは、ユニットファイルの設定と構文に関する質問には対応できますが、移植されたスクリプトはサポート対象外であるため作成しません。

Red Hat が保守するすべての Red Hat Enterprise Linux 7、8、および 9 用パッケージは、すでに systemd が動作している状態でインストールされます。Red Hat Enterprise Linux 7、8、または 9 での実行が認定されたソフトウェアを提供するサードパーティーには、Red Hat Enterprise Linux 7、8、または 9 用の systemd ユニットファイルがすでに含まれているはずです。サードパーティーの init スクリプトの移植を試みる前に、サードパーティーソフトウェアプロバイダーに連絡して関連するユニットファイルの提供を依頼する必要があります。

以下の例では、単純なデーモンをコンパイルし、その init スクリプトを作成します。次に、その init スクリプトを systemd ユニットファイルに移植します。

I. Hello World デーモン

例として (init スクリプトのみを使用する古いシステムの使用方法を示すために)、 まず、RHEL6 システムから始めて、次のように 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]# 

デーモンを強制終了し、デーモンが自身でクリーンアップすることを確認します。

[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. RHEL6 での Hello World 用の System V Init スクリプト

今度は、hellod の init スクリプトを作成します。

touch /etc/init.d/hello 
chmod 755 /etc/init.d/hello 

以下の 4 行を /etc/init.d/hello に追加します。

#!/bin/bash
#
# chkconfig: 35 90 12
# description: Hello Daemon

上記のコマンドは以下のようになります。

  • chkconfig 行により、chckconfig コマンドでスクリプトを管理できるようになります。
  • '35' は、実行レベル 3 および 5 で起動することを意味します。
  • '90' は起動優先度です (最後に起動されるサービスの 1 つ)。
  • '12' は強制終了の優先度です (最初に強制終了されるサービスの 1 つ)。

続いて、次の行に以下を追加して、init スクリプトに含まれる残りの 800 行の関数のファイルを含めます。

. /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 サービスを停止する次の 7 行を追加します。

stop() {
        echo -n "Stopping Hello Server: "
        killproc hellod
        # Remove the lock file
        rm -f /var/lock/subsys/hellod
        echo
}

最後に、次の 18 行を追加して、入力を正しく処理し、start 関数と stop 関数を呼び出すようにします。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 スクリプトを systemd に移植して、RHEL7 で動作するようにします。

III. RHEL7 での Hello World 用の Systemd ユニットファイル

/usr/local/bin/hellod のバイナリーを RHEL6 から RHEL7 に移動し、動作するかどうかをテストします。

ユニットファイルを保持する /etc/systemd/system/hellod.service を作成します。パッケージメンテナーユニットファイルは /usr/lib/systemd/system/ に存在するはずですが、変更する場合はこれを /etc/systemd/system/ にコピーする必要があります。これは systemd が /etc を優先するためです。

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] セクションには、サービスの説明が含まれています。また、After= タイプの依存関係も設定します。これは、ネットワークがサーバーで実行されるまで、このネットワークサービスが起動しないことを意味します。

2 番目の [Service] セクションでは、ExecStart= を使用して、サービスの起動時に実行するバイナリーへのパスを定義します。元のプログラムはフォークデーモンなので、Type=forking を設定します。その他のタイプは、systemd.service の man ページで説明されています。フォークを使用する場合は、systemd がデーモンのメインプロセスを識別できるように、PIDFile= オプションを使用することが推奨されます。上記の 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 ユニットファイルの作成に関する詳細は、systemd.service の man ページを参照してください。

Root Cause

Diagnostic Steps

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