LoginSignup
32
44

More than 3 years have passed since last update.

ユニット定義ファイルの使い方

Last updated at Posted at 2017-04-24

1 環境

CentOS版数
[root@master ~]# cat /etc/redhat-release
CentOS Linux release 7.3.1611 (Core)
カーネル版数
[root@master ~]# uname -r
3.10.0-514.el7.x86_64

2 事前準備(ユニット定義ファイルの作成)

テスト用のシェルスクリプトを作成します。$1は引数(ユニット名)を表します。

事前準備
[root@master ~]# vi /usr/local/bin/hoge.sh
[root@master ~]# cat /usr/local/bin/hoge.sh
#!/usr/bin/bash

while :
do
    logger "test(PID=`echo $$`,Unit=$1)"
    sleep 30
done

[root@master ~]# chmod 744 /usr/local/bin/hoge.sh

ユニット定義ファイルを作成します。%nは置換文字(ユニット名に展開される)を表します。

ユニット定義ファイル作成
[root@master ~]# vi /etc/systemd/system/test1.service
[root@master ~]# cat /etc/systemd/system/test1.service
[Unit]
Description=test1
After=network.service

[Service]
Type=simple
Restart=on-success
ExecStart=/usr/local/bin/hoge.sh %n

[Install]
WantedBy=multi-user.target

systemdに変更した設定ファイルを読み込ませる

設定ファイル変更通知
[root@master ~]# systemctl daemon-reload

サービスを起動します。

サービスの起動、終了
[root@master ~]# systemctl start test1.service
[root@master ~]# systemctl is-active test1.service
active

もう1つターミナルを開く。
[root@master ~]# tail -f /var/log/messages
Apr 25 20:18:24 master systemd: Started test1.
Apr 25 20:18:24 master systemd: Starting test1...
Apr 25 20:18:24 master logger: test(PID=4821,Unit=test1.service)
-以下、略-

サービスを終了する。
[root@master ~]# systemctl stop test1.service
[root@master ~]# systemctl is-active test1.service
unknown

3 依存関係(Requires,Wants)の確認

RequiresとWantsの違いについて確認します。

3.1 Requiresの場合

test2を作成する。test1との違いは、Requiresの1行が追加されたことだけ。

ユニット定義ファイル作成
[root@master ~]# cat /etc/systemd/system/test2.service
[Unit]
Description=test2
After=network.service
Requires=test1.service

[Service]
Restart=always
ExecStart=/usr/local/bin/hoge.sh

[Install]
WantedBy=multi-user.target

systemdに変更した設定ファイルを読み込ませる
[root@master ~]# systemctl daemon-reload

test1の状態を確認する。
[root@master ~]# systemctl is-active test1.service
unknown

test2の状態を確認する。
[root@master ~]# systemctl is-active test2.service
unknown

test2を起動する。
[root@master ~]# systemctl start test2.service
[root@master ~]# systemctl is-active test2.service
active

test1の状態を確認する。test1も起動したことがわかる。
[root@master ~]# systemctl is-active test1.service
active

test1を停止する。
[root@master ~]# systemctl stop test1.service
[root@master ~]# systemctl is-active test1.service
unknown

test2も停止したことがわかる。
[root@master ~]# systemctl is-active test2.service
unknown

3.2 Wantsの場合

[root@master ~]# cat /etc/systemd/system/test2.service
[Unit]
Description=test2
After=network.service
Wants=test1.service

[Service]
Restart=always
ExecStart=/usr/local/bin/hoge.sh

[Install]
WantedBy=multi-user.target

systemdに変更した設定ファイルを読み込ませる
[root@master ~]# systemctl daemon-reload

test1の状態を確認する。停止した状態であることがわかる。
[root@master ~]# systemctl is-active test1.service
unknown

test2の状態を確認する。停止した状態であることがわかる。
[root@master ~]# systemctl is-active test2.service
unknown

test2を起動する。
[root@master ~]# systemctl start test2.service

test1の状態を確認する。動いていることがわかる。
[root@master ~]# systemctl is-active test1.service
active

test2の状態を確認する。動いていることがわかる。
[root@master ~]# systemctl is-active test2.service
active

test1を停止する。
[root@master ~]# systemctl stop test1.service

test1の状態を確認する。停止したことがわかる。
[root@master ~]# systemctl is-active test1.service
inactive

test2の状態を確認する。
test2は動いたままであることがわかる。★ここがRequiresとの違い
[root@master ~]# systemctl is-active test2.service
active

4 順序関係(After,Before)の確認

AfterとBeforeの違いについて確認する。

4.1 After

test1に"After=test2.service"と設定すると、test2,test1の順でサービスが起動する。

test1のUNIT定義ファイル
test2との違いは、"After=test2.service"の部分だけ。
[root@master ~]# cat /etc/systemd/system/test1.service
[Unit]
Description=test1
After=test2.service

[Service]
Type=simple
Restart=always
ExecStart=/usr/local/bin/hoge.sh %n

[Install]
WantedBy=multi-user.target

systemdに変更した設定ファイルを読み込ませる
[root@master ~]# systemctl daemon-reload
test2のUNIT定義ファイル
[root@master ~]# cat /etc/systemd/system/test2.service
[Unit]
Description=test2

[Service]
Restart=always
ExecStart=/usr/local/bin/hoge.sh %n

[Install]
WantedBy=multi-user.target
[root@master ~]#
実行結果
test1の自動起動を有効にする。
[root@master ~]# systemctl enable test1
Created symlink from /etc/systemd/system/multi-user.target.wants/test1.service to /etc/systemd/system/test1.service.

test2の自動起動を有効にする。
[root@master ~]# systemctl enable test2
Created symlink from /etc/systemd/system/multi-user.target.wants/test2.service to /etc/systemd/system/test2.service.

再起動する。
[root@master ~]# shutdown -r now

test2,test1の順序でサービスが起動していることがわかる(期待値)
[root@master ~]# journalctl -b0 -u test1 -u test2
-- Logs begin at 金 2017-03-17 21:18:32 JST, end at 火 2017-04-25 21:14:09 JST. --
 4月 25 21:13:20 master systemd[1]: Started test2.
 4月 25 21:13:20 master systemd[1]: Starting test2...
 4月 25 21:13:20 master systemd[1]: Started test1.
 4月 25 21:13:20 master systemd[1]: Starting test1...
 4月 25 21:13:50 master logger[1084]: test(PID=509,Unit=test1.service)

4.2 Before

test1に"Before=test2.service"と設定すると、test1,test2の順でサービスが起動する。

test1のUNIT定義ファイル
[root@master ~]# cat /etc/systemd/system/test1.service
[Unit]
Description=test1
Before=test2.service

[Service]
Type=simple
Restart=always
ExecStart=/usr/local/bin/hoge.sh %n

[Install]
WantedBy=multi-user.target
test2のUNIT定義ファイル
[root@master ~]# cat /etc/systemd/system/test2.service
[Unit]
Description=test2

[Service]
Restart=always
ExecStart=/usr/local/bin/hoge.sh %n

[Install]
WantedBy=multi-user.target
[root@master ~]#

systemdに変更した設定ファイルを読み込ませる
[root@master ~]# systemctl daemon-reload
実行結果
システムを再起動する。
[root@master ~]# shutdown -r now

test1,test2の順序でサービスが起動していることがわかる(期待値)。
[root@master ~]# journalctl -b0 -u test1 -u test2
-- Logs begin at 金 2017-03-17 21:18:32 JST, end at 火 2017-04-25 21:21:06 JST. --
 4月 25 21:18:17 master systemd[1]: Started test1.
 4月 25 21:18:17 master systemd[1]: Starting test1...
 4月 25 21:18:17 master systemd[1]: Started test2.
 4月 25 21:18:17 master systemd[1]: Starting test2...
 4月 25 21:19:36 master logger[1589]: test(PID=489,Unit=test1.service)
 4月 25 21:19:36 master logger[1601]: test(PID=502,Unit=test2.service)

5 Serviceユニットの再起動

再起動のタイプには、always,no,on-success,on-failure等がある。
ここでは、always,no,on-success,on-failureの違いについて、具体例をあげて確認する。

5.1 alwaysの場合

サービスが正常終了しても異常終了しても、サービスを再起動する。

テスト用のユニット定義ファイルを作成する。Restartにalwaysを指定する。
%nは置換文字(ユニット名に展開される)です。
[root@master ~]# cat /etc/systemd/system/test1.service
[Unit]
Description=test1
After=network.service

[Service]
Type=simple
Restart=always
ExecStart=/usr/local/bin/hoge.sh %n

[Install]
WantedBy=multi-user.target

テスト用のシェルスクリプトを作成する。$1は引数(ユニット名)です。
[root@master ~]# cat /usr/local/bin/hoge.sh
#!/usr/bin/bash

while :
do
    logger "test(PID=`echo $$`,Unit=$1)"
    sleep 30
done

systemdに変更した設定ファイルを読み込ませる
[root@master ~]# systemctl daemon-reload

test1にSIGKILL(9),SIGTERM(15),SIGSEGV(11)を送信する。
シグナル送信先のPIDは、/var/log/messagesを見ながら決める。
[root@master ~]# systemctl start test1.service
[root@master ~]# kill -9 4880
[root@master ~]# kill -15 4885
[root@master ~]# kill -11 4890

ターミナルをもう1つ開く。test1が正常終了(SIGTERM受信)しても異常終了(SIGKILL,SIGSEGV受信)しても、
サービスが再起動していることがわかる。
[root@master ~]# tail -f /var/log/messages
Apr 25 20:25:51 master systemd: Started test1.
Apr 25 20:25:51 master systemd: Starting test1...
Apr 25 20:25:51 master logger: test(PID=4880,Unit=test1.service)
Apr 25 20:25:57 master systemd: test1.service: main process exited, code=killed, status=9/KILL
Apr 25 20:25:57 master systemd: Unit test1.service entered failed state.
Apr 25 20:25:57 master systemd: test1.service failed.
Apr 25 20:25:57 master systemd: test1.service holdoff time over, scheduling restart.
Apr 25 20:25:57 master systemd: Started test1. ★SIGKILLを受信して、test1が再起動している
Apr 25 20:25:57 master systemd: Starting test1...
Apr 25 20:25:57 master logger: test(PID=4885,Unit=test1.service)
Apr 25 20:26:08 master systemd: test1.service holdoff time over, scheduling restart.
Apr 25 20:26:08 master systemd: Started test1. ★SIGTERMを受信して、test1が再起動している。
Apr 25 20:26:08 master systemd: Starting test1...
Apr 25 20:26:08 master logger: test(PID=4890,Unit=test1.service)
Apr 25 20:26:16 master systemd: test1.service: main process exited, code=killed, status=11/SEGV
Apr 25 20:26:16 master systemd: Unit test1.service entered failed state.
Apr 25 20:26:16 master systemd: test1.service failed.
Apr 25 20:26:16 master systemd: test1.service holdoff time over, scheduling restart.
Apr 25 20:26:16 master systemd: Started test1. ★SIGSEGVを受信して、test1が再起動している。
Apr 25 20:26:16 master systemd: Starting test1...
Apr 25 20:26:16 master logger: test(PID=4896,Unit=test1.service)

5.2 noの場合

サービスが正常終了しても、異常終了しても再起動をしない。

-----------------------------------------
1. 事前準備(ユニット定義ファイルの作成)
-----------------------------------------
テスト用のユニット定義ファイルを作成する。Restartにnoを指定する。
[root@master ~]# cat /etc/systemd/system/test1.service
[Unit]
Description=test1
After=network.service

[Service]
Type=simple
Restart=no
ExecStart=/usr/local/bin/hoge.sh %n

[Install]
WantedBy=multi-user.target
[root@master ~]#

systemdに変更した設定ファイルを読み込ませる
[root@master ~]# systemctl daemon-reload

-----------------------------------------
2. 異常終了の場合(SIGKILLを受信した場合)
-----------------------------------------
test1を起動する。
[root@master ~]# systemctl start test1.service
[root@master ~]# systemctl is-active test1.service
active

SIGKILL(9)をtest1に送信する。
[root@master ~]# kill -9 9200
[root@master ~]# systemctl is-active test1.service
failed

サービスの状態を確認する。サービスが終了したことがわかる。
[root@master ~]# tail -f /var/log/messages
Apr 26 19:51:29 master logger: test(PID=9200,Unit=test1.service)
Apr 26 19:51:43 master systemd: test1.service: main process exited, code=killed, status=9/KILL
Apr 26 19:51:43 master systemd: Unit test1.service entered failed state.
Apr 26 19:51:43 master systemd: test1.service failed.

-----------------------------------------
3. 正常終了の場合(SIGTERMを受信した場合)
-----------------------------------------
test1を起動する。
[root@master ~]# systemctl start test1.service
[root@master ~]# systemctl is-active test1.service
active

SIGTERM(15)をtest1に送信する。
[root@master ~]# kill -15 9213
[root@master ~]# systemctl is-active test1.service
unknown

サービスの状態を確認する。サービスが終了したことがわかる。
[root@master ~]# tail -f /var/log/messages
Apr 26 19:53:16 master systemd: Started test1.
Apr 26 19:53:16 master systemd: Starting test1...
Apr 26 19:53:16 master logger: test(PID=9213,Unit=test1.service)

5.3 on-successの場合

サービスが正常終了したときだけ、サービスの再起動を行う。

-----------------------------------------
1. 事前準備(ユニット定義ファイルの作成)
-----------------------------------------
テスト用のユニット定義ファイルを作成する。Restartにon-successを指定する。
[root@master ~]# cat /etc/systemd/system/test1.service
[Unit]
Description=test1
After=network.service

[Service]
Type=simple
Restart=on-success
ExecStart=/usr/local/bin/hoge.sh %n

[Install]
WantedBy=multi-user.target

systemdに変更した設定ファイルを読み込ませる
[root@master ~]# systemctl daemon-reload

-----------------------------------------
2. 正常終了の場合(SIGTERMを受信した場合)
-----------------------------------------
正常終了した場合は、サービスが自動的に再起動されていることがわかる。
[root@master ~]# systemctl start test1.service
[root@master ~]# kill -15 4983
[root@master ~]# systemctl is-active test1.service
active
[root@master ~]# kill -15 4987
[root@master ~]# systemctl is-active test1.service
active
[root@master ~]# kill -15 4994
[root@master ~]# systemctl is-active test1.service
active

-----------------------------------------
3. 異常終了の場合(SIGKILLを受信した場合)
-----------------------------------------
異常終了した場合、サービスは再起動しないことがわかる。
[root@master ~]# kill -9 5000
[root@master ~]# systemctl is-active test1.service
failed

-----------------------------------------
4. ログの確認
-----------------------------------------
[root@master ~]# tail -f /var/log/messages
Apr 25 20:36:12 master systemd: Started test1.
Apr 25 20:36:12 master systemd: Starting test1...
Apr 25 20:36:12 master logger: test(PID=4983,Unit=test1.service)
Apr 25 20:36:18 master systemd: test1.service holdoff time over, scheduling restart.
Apr 25 20:36:18 master systemd: Started test1. ★SIGTERMを受信して、test1が再起動している
Apr 25 20:36:18 master logger: test(PID=4987,Unit=test1.service)
Apr 25 20:36:18 master systemd: Starting test1...
Apr 25 20:36:28 master systemd: test1.service holdoff time over, scheduling restart.
Apr 25 20:36:28 master systemd: Started test1. ★SIGTERMを受信して、test1が再起動している
Apr 25 20:36:28 master systemd: Starting test1...
Apr 25 20:36:28 master logger: test(PID=4994,Unit=test1.service)
Apr 25 20:36:36 master systemd: test1.service holdoff time over, scheduling restart.
Apr 25 20:36:36 master systemd: Started test1. ★SIGTERMを受信して、test1が再起動している
Apr 25 20:36:36 master logger: test(PID=5000,Unit=test1.service)
Apr 25 20:36:36 master systemd: Starting test1...
★SIGKILLを受信して、test1が終了していることがわかる。
Apr 25 20:37:47 master systemd: test1.service: main process exited, code=killed, status=9/KILL
Apr 25 20:37:47 master systemd: Unit test1.service entered failed state.
Apr 25 20:37:47 master systemd: test1.service failed.

5.4 on-failureの場合

-----------------------------------------
1. 事前準備(ユニット定義ファイルの作成)
-----------------------------------------
テスト用のユニット定義ファイルを作成する。Restartにon-failureを指定する。
[root@node1 system]# pwd
/etc/systemd/system
[root@node1 system]# vi keepalived.service
[root@node1 system]# cat keepalived.service
[Unit]
Description=LVS and VRRP High Availability Monitor
After=syslog.target network.target

[Service]
Type=forking
Restart=on-failure
PIDFile=/var/run/keepalived.pid
KillMode=process
EnvironmentFile=-/etc/sysconfig/keepalived
ExecStart=/usr/sbin/keepalived $KEEPALIVED_OPTIONS
ExecReload=/bin/kill -HUP $MAINPID

[Install]
WantedBy=multi-user.target
[root@node1 system]#

systemdに変更した設定ファイルを読み込ませる
[root@node1 system]# systemctl daemon-reload
[root@node1 system]# systemctl start keepalived
[root@node1 system]# systemctl is-active keepalived
active

-----------------------------------------
2. 異常終了の場合(SIGKILLを受信した場合)
-----------------------------------------
プロセス(keepalived)の状態を確認する。
[root@node1 system]# ps -C keepalived
   PID TTY          TIME CMD
  6830 ?        00:00:00 keepalived
  6831 ?        00:00:00 keepalived
  6832 ?        00:00:02 keepalived

keepalivedを異常終了する。
[root@node1 system]# pkill -9 keepalived

プロセス(keepalived)の状態を確認する。
SIGKILL(9)を受信して異常終了したあと、再起動していることがわかる。
[root@node1 system]# ps -C keepalived
   PID TTY          TIME CMD
 10248 ?        00:00:00 keepalived
 10249 ?        00:00:00 keepalived
 10250 ?        00:00:00 keepalived
[root@node1 system]#

-----------------------------------------
3. 正常終了の場合(SIGKILLを受信した場合)
-----------------------------------------
プロセス(keepalived)の状態を確認する。
[root@node1 system]# ps -C keepalived
   PID TTY          TIME CMD
 10248 ?        00:00:00 keepalived
 10249 ?        00:00:00 keepalived
 10250 ?        00:00:00 keepalived

keepalivedを正常終了する。
[root@node1 system]# pkill -15 keepalived

プロセス(keepalived)の状態を確認する。
正常終了ではkeepalivedが再起動していないことがわかる(期待値)
[root@node1 system]# ps -C keepalived
   PID TTY          TIME CMD

5.5 on-watchdogの場合(作成中)

5.5.1 事前準備

[root@node1 ~]# yum -y install systemd-devel.x86_64

5.5.2 サンプルプログラム作成

サンプルプログラムはここからダウンロードする。

[root@node1 ~]# vi test.c
[root@node1 ~]# cat test.c
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <systemd/sd-daemon.h>

int main(int ac, char **av)
{
  (void)ac;

  char *e = getenv("WATCHDOG_USEC");
  if(!e) {
    printf("No WATCHDOG_USEC set!\n");
    exit(1);
  } else
    printf("WATCHDOG_USEC: %s\n", e);

  int i = atoi(e);
  i /= 2;
  printf("* Barking every %i usec.\n", i);

  bool cont = true;
  while(cont) {
    usleep(i);

    struct stat b;
    int r = stat(av[1], &b);
    if(0 == r) {
      continue;
    } else {
      r = sd_notify(0, "WATCHDOG=1");
      printf("Barked!!! (%i)\n", r);
    }
  }

  return 0;
}

5.5.3 サンプルプログラムのコンパイル

pkg-configコマンドのインストール方法はここを参照ください。

[root@node1 ~]# ls /usr/lib64/pkgconfig/
libsystemd-daemon.pc  libsystemd-id128.pc  libsystemd-journal.pc  libsystemd-login.pc  libsystemd.pc  libudev.pc  systemd.pc

[root@node1 ~]# export PKG_CONFIG_PATH=/usr/lib64/pkgconfig
[root@node1 ~]# gcc -o test test.c $(pkg-config --libs libsystemd)
[root@node1 ~]# echo $?
0
[root@node1 ~]# ls test
test

6 EnvironmentFileに指定する"-"の使い方

6.1 "-"なし場合(EnvironmentFile=/tmp/test1.conf)

"-"なしの場合、定義ファイルがないと、サービスの起動ができない。

[root@master ~]# cat /etc/systemd/system/test1.service
[Unit]
Description=test1

[Service]
Type=simple
Restart=always
ExecStart=/usr/local/bin/hoge.sh %n
EnvironmentFile=/tmp/test1.conf

[Install]
WantedBy=multi-user.target

テスト用の定義ファイルを作成する。
[root@master ~]# touch /tmp/test1.conf
[root@master ~]# systemctl start test1
[root@master ~]# systemctl is-active test1
active
[root@master ~]# systemctl stop test1

テスト用の定義ファイルを削除する。
[root@master ~]# rm /tmp/test1.conf
rm: 通常の空ファイル `/tmp/test1.conf' を削除しますか? y

サービスを起動する。定義ファイルがないと、サービスが起動できないことがわかる。
[root@master ~]# systemctl start test1
Job for test1.service failed because a configured resource limit was exceeded. See "systemctl status test1.service" and "journalctl -xe" for details.
[root@master ~]#

6.2 "-"ありの場合(EnvironmentFile=-/tmp/test1.conf)

"-"ありの場合、定義ファイルがなくても、サービスを起動することができる。

[root@master ~]# cat /etc/systemd/system/test1.service
[Unit]
Description=test1

[Service]
Type=simple
Restart=always
ExecStart=/usr/local/bin/hoge.sh %n
EnvironmentFile=-/tmp/test1.conf

[Install]
WantedBy=multi-user.target
[root@master ~]#

テスト用の定義ファイルを作成する。
root@master ~]# touch /tmp/test1.conf

[root@master ~]# systemctl start test1
[root@master ~]# systemctl is-active test1
active
[root@master ~]# systemctl stop test1

テスト用の定義ファイルを削除する。
[root@master ~]# rm /tmp/test1.conf
rm: 通常の空ファイル `/tmp/test1.conf' を削除しますか? y

サービスを起動する。定義ファイルがなくても、サービスを起動することができる。
[root@master ~]# systemctl start test1
[root@master ~]# systemctl is-active test1
active

7 RemainAfterExitの使い方

RemainAfterExitとは状態を保つためのものである。
Typeにoneshotを指定した場合、RemainAfterExit=yesとして一緒に使うのが定番のようです。
言葉でうまく説明できないので、RemainAfterExit設定あり/なしの場合の実行例を示したので、確認してほしい。

7.1 RemainAfterExitを設定あり(yes)の場合

状態をactiveのままに保つことができる。

ユニット定義ファイルを作成する。
[root@node2 ~]# vi /etc/systemd/system/test1.service
[root@node2 ~]# cat /etc/systemd/system/test1.service
[Unit]
Description=test1

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/bash -c '/usr/local/bin/test.sh start'
ExecStop=/usr/bin/bash -c '/usr/local/bin/test.sh stop'

[Install]
WantedBy=multi-user.target


テスト用のシェルスクリプトを作成する。
[root@node2 ~]# vi /usr/local/bin/test.sh
[root@node2 ~]# chmod 700 /usr/local/bin/test.sh
[root@node2 ~]# cat /usr/local/bin/test.sh
#!/usr/bin/bash

case $1 in
    "start")
        logger "start (PID=`echo $$`, Unit=$1)"
        ;;
    "stop")
        logger "stop (PID=`echo $$`, Unit=$1)"
        ;;
    *)
        logger "other (PID=`echo $$`, Unit=$1)"
esac

ユニット定義ファイルの変更をsystemdに通知する。
[root@node2 ~]# systemctl daemon-reload

サービスを起動する。
[root@node2 ~]# systemctl start test1.service

サービスの状態を確認する。
Typeにoneshotを指定しているため、サービスがactiveの状態のままであることがわかる。
[root@node2 ~]# systemctl is-active test1.service
active

サービスを停止する。
[root@node2 ~]# systemctl stop test1.service

ログを確認する。start/stop時の両方のログがでていることがわかる。
RemainAfterExit未設定だと、start時のログしかでない。
この理由は、startコマンド完了時点で、サービスがactiveからinactiveに状態遷移してしまい、
stopコマンドが実行できないため。
[root@node2 test]# journalctl -f
 5月 19 20:31:05 node2 systemd[1]: Starting test1...
 5月 19 20:31:05 node2 logger[3353]: start (PID=3351, Unit=start)
 5月 19 20:31:05 node2 systemd[1]: Started test1.

 5月 19 20:31:37 node2 systemd[1]: Stopping test1...
 5月 19 20:31:38 node2 logger[3380]: stop (PID=3378, Unit=stop)
 5月 19 20:31:38 node2 systemd[1]: Stopped test1.

7.2 RemainAfterExit設定なしの場合

状態がactiveからinactiveに遷移してしまう。

ユニット定義ファイルを作成する。
[root@node2 ~]# vi /etc/systemd/system/test1.service
[root@node2 ~]# cat /etc/systemd/system/test1.service
[Unit]
Description=test1

[Service]
Type=oneshot
ExecStart=/usr/bin/bash -c '/usr/local/bin/test.sh start'
ExecStop=/usr/bin/bash -c '/usr/local/bin/test.sh stop'

[Install]
WantedBy=multi-user.target

テスト用のシェルスクリプトを作成する。
[root@node2 ~]# vi /usr/local/bin/test.sh
[root@node2 ~]# chmod 700 /usr/local/bin/test.sh
[root@node2 ~]# cat /usr/local/bin/test.sh
#!/usr/bin/bash

case $1 in
    "start")
        logger "start (PID=`echo $$`, Unit=$1)"
        ;;
    "stop")
        logger "stop (PID=`echo $$`, Unit=$1)"
        ;;
    *)
        logger "other (PID=`echo $$`, Unit=$1)"
esac

ユニット定義ファイルの変更をsystemdに通知する。
[root@node2 ~]# systemctl daemon-reload

サービスを起動する。
[root@node2 ~]# systemctl start test1

サービスの状態を確認する。
Typeにoneshotを指定しているので、activeになったあと、inactiveに状態遷移している。
[root@node2 ~]# systemctl is-active test1.service
inactive

inactiveの状態でstopを実行しても、実行できない。
ログを確認すると、start時のログしかでていうない。stop時はログがでていない。
[root@node2 ~]# systemctl stop test1.service
[root@node2 test]# journalctl -f
 5月 19 20:21:39 node2 systemd[1]: Starting test1...
 5月 19 20:21:39 node2 logger[3273]: start (PID=3271, Unit=start)
 5月 19 20:21:39 node2 logger[3277]: stop (PID=3275, Unit=stop)
 5月 19 20:21:39 node2 systemd[1]: Started test1.

8 Pathユニット

Pathユニットは、ファイルやディレクトリ作成を契機にサービスを起動します。

8.1 事前準備


Pathユニットを作成する。
[root@master1 ~]# vi /etc/systemd/system/file_check.path
[root@master1 ~]# cat /etc/systemd/system/file_check.path
[Unit]
Description=File Check Unit

[Path]
PathModified=/tmp/test.txt

[Install]
WantedBy=multi-user.target

Pathユニットに対応したサービスユニットを作成する。
[root@master1 ~]# vi /etc/systemd/system/file_check.service
[root@master1 ~]# cat /etc/systemd/system/file_check.service
[Unit]
Description=File Cheker

[Service]
ExecStart=/usr/local/bin/file_check.sh

サービスユニットから呼び出すシェルスクリプトを作成する。
[root@master1 ~]# vi /usr/local/bin/file_check.sh
[root@master1 ~]# cat /usr/local/bin/file_check.sh
#!/usr/bin/bash
logger "test"

[root@master1 ~]# chmod 700 /usr/local/bin/file_check.sh

設定変更をsystemdに通知する。
[root@master1 system]# systemctl daemon-reload

8.2 確認

Pathユニットを起動する。
[root@master1 system]# systemctl start file_check.path
[root@master1 system]# systemctl status file_check.path
● file_check.path - File Check Unit
   Loaded: loaded (/etc/systemd/system/file_check.path; disabled; vendor preset: disabled)
   Active: active (waiting) since 月 2017-05-22 21:10:12 JST; 2s ago

 5月 22 21:10:12 master1 systemd[1]: Started File Check Unit.
 5月 22 21:10:12 master1 systemd[1]: Starting File Check Unit.

/tmp/test.txtファイルにデータを書き込む
[root@master1 ~]# echo aa > /tmp/test.txt

ログ出力を監視する。echoコマンド実行完了時に★印のログが出力される。
[root@master1 ~]# journalctl -f
 5月 22 21:22:36 master1 systemd[1]: Started File Cheker.
 5月 22 21:22:36 master1 systemd[1]: Starting File Cheker...
 5月 22 21:22:36 master1 logger[1925]: test ★

9 Targetユニット

Targetユニットとは、複数のユニットをグループ化するときに使います。
以下の例は、httpd.serviceとpostfix.serviceをtest.targetでグループ化しています。
test.targetを起動することで、httpd.serviceとpostfix.serviceが起動することが確認できます。

9.1 事前準備

[root@admin ~]# yum -y install httpd
[root@admin ~]# systemctl enable httpd.service
[root@admin ~]# systemctl is-active httpd.service
inactive

[root@admin ~]# yum -y install postfix
[root@admin ~]# systemctl enable postfix.service
[root@admin ~]# systemctl is-active postfix.service
inactive

9.2 targetユニット作成

[root@admin ~]# vi /etc/systemd/system/test.target
[root@admin ~]# cat /etc/systemd/system/test.target
[Unit]
Description=Target Unit test
Requires=httpd.service postfix.service

[Install]
WantedBy=multi-user.target

targetユニットの作成をsystemdに通知する。
[root@admin ~]# systemctl daemon-reload

9.3 tagetユニットの効果確認

test.targetを起動することで、httpdとpostfixが起動することを確認する。
しかし、test.targetを停止しても、httpdとpostfixは動作したままです。
test.targetを停止したら、httpdとpostfixも停止したい場合は、
次に説明するPartOfを使います。

test.tagetを起動する。
[root@admin ~]# systemctl start test.target
[root@admin ~]# systemctl is-active test.target
active

httpdユニットの状態を確認する。起動していることがわかる。
[root@admin ~]# systemctl is-active httpd.service
active

postfixユニットの状態を確認する。起動していることがわかる。
[root@admin ~]# systemctl is-active postfix.service
active

次に、test.targetを停止すると、httpdとpostfixが停止するかどうかを確認する。
[root@admin ~]# systemctl stop test.target

httpdユニットの状態を確認する。
test.targetを停止しても、httpdはactiveであることがわかる。
[root@admin ~]# systemctl is-active httpd
active

postfixユニットの状態を確認する。
test.targetを停止しても、postfixはactiveであることがわかる。
[root@admin ~]# systemctl is-active postfix.service
active

9.4 PartOfの効果確認

test.targetを停止したら、httpdとpostfixも停止したい場合は、PartOfを使います。

ユニット定義ファイルをカスタマイズ用のディレクトリにコピーする。
[root@admin system]# pwd
/etc/systemd/system
[root@admin system]# cp /usr/lib/systemd/system/httpd.service .
[root@admin system]# cp /usr/lib/systemd/system/postfix.service .

httpdのユニット定義ファイルにPartOfを定義する。
[root@admin system]# vi httpd.service
[Unit]
-中略-
PartOf=test.target

postfixのユニット定義ファイルにPartOfを定義する。
[root@admin system]# vi postfix.service
[Unit]
-中略-
PartOf=test.target

設定変更をsystemdに通知する。
[root@admin system]# systemctl daemon-reload

test.targetを起動する。
[root@admin system]# systemctl start test.target
[root@admin system]# systemctl is-active test.target
active

httpdの状態を確認する。activeになったことがわかる。
[root@admin system]# systemctl is-active httpd.service
active

postfixの状態を確認する。activeになったことがわかる。
[root@admin system]# systemctl is-active postfix.service
active

test.targetを停止する。
[root@admin system]# systemctl stop test.target

httpdの状態を確認する。inactiveになったことがわかる。PartOfの効果が確認できた。
[root@admin system]# systemctl is-active httpd.service
inactive

postfixの状態を確認する。inactiveになったことがわかる。PartOfの効果が確認できた。
[root@admin system]# systemctl is-active postfix.service
inactive

10 Templateユニット

Templateユニットがどのように動作するのか、ということと、ユニット指定子の意味について確認する。

書式
xxx@yyy.service

xxx:プレフィックス
yyy:インスタンス
xxx@yyy.service:テンプレートユニット
テスト用のテンプレートユニット作成
テンプレートユニットを作成する。%n %p %i %H %t %fはユニット指定子(意味は後述)です。
[root@admin ~]# vi /etc/systemd/system/test@.service
[root@admin ~]# cat /etc/systemd/system/test@.service
[Unit]
Description=Test for Template Unit
After=network.service

[Service]
Type=simple
Restart=on-success
ExecStart=/usr/local/bin/hoge.sh %n %p %i %H %t %f

[Install]
WantedBy=multi-user.target
テスト用のシェルスクリプト作成
シェルスクリプトを作成する。$1,$2,...,$6は、シェルスクリプトへの引数です。
[root@admin ~]# vi /usr/local/bin/hoge.sh
[root@admin ~]# cat /usr/local/bin/hoge.sh
#!/usr/bin/bash

while :
do
    logger "%n=$1, %p=$2, %i=$3, %H=$4, %t=$5, %f=$6"
    sleep 3
done
動作確認
ユニットファイル作成をsystemdに通知する。
[root@admin ~]# systemctl daemon-reload

test@test55ユニットを起動する。
[root@admin ~]# systemctl start test@test55.service

別ターミナルを開く。
[root@admin ~]# journalctl -f
 7月 29 21:44:21 admin logger[3297]: %n=test@test55.service, %p=test, %i=test55, %H=admin, %t=/run, %f=/test55
 7月 29 21:44:24 admin logger[3300]: %n=test@test55.service, %p=test, %i=test55, %H=admin, %t=/run, %f=/test55
 7月 29 21:44:27 admin logger[3303]: %n=test@test55.service, %p=test, %i=test55, %H=admin, %t=/run, %f=/test55

test@test99ユニットを起動する。
[root@admin ~]# systemctl start test@test99.service

別ターミナルを開く。
[root@admin ~]# journalctl -f
7月 29 21:45:03 admin logger[3346]: %n=test@test99.service, %p=test, %i=test99, %H=admin, %t=/run, %f=/test99
7月 29 21:45:04 admin logger[3349]: %n=test@test55.service, %p=test, %i=test55, %H=admin, %t=/run, %f=/test55
7月 29 21:45:06 admin logger[3352]: %n=test@test99.service, %p=test, %i=test99, %H=admin, %t=/run, %f=/test99
7月 29 21:45:07 admin logger[3355]: %n=test@test55.service, %p=test, %i=test55, %H=admin, %t=/run, %f=/test55

test@test1,test@test1ユニットを停止する。
[root@admin ~]# systemctl stop test@test55.service
[root@admin ~]# systemctl stop test@test99.service
ユニット指定子の意味
ユニット指定子の意味は以下のとおりです。詳細はsystemd.unit(5)を参照ください。

%nはユニット名を表す。以下の場合、%nは"test@test99.service"を表す。
%pはプレフィックス名を表す。以下の場合、%pは"test"を表す。
%iはインスタンス名を表す。以下の場合、%iは"test99"を表す。
  test@test99.service

%Hはホスト名を表す。本テストを実施したゲストマシンのホスト名は以下のとおり。
  [root@admin ~]# hostname
  admin

11 ユニットの起動順序を調べる方法(list-dependencies)

修正中

12. 起動に失敗したユニットを調べる方法(--state=failed)

本オプションの有用性がいまいちよくわかりませんが、実験をしてみました。

テスト用のユニットファイルを作成する。
EnvironmentFileに指定したファイルは存在しないので、ユニットファイルは起動できません。
[root@admin ~]# vi /etc/systemd/system/test1.service
[root@admin ~]# cat /etc/systemd/system/test1.service
[Unit]
Description=test1

[Service]
Type=simple
Restart=always
ExecStart=/usr/local/bin/hoge.sh %n
EnvironmentFile=/tmp/test1.conf

[Install]
WantedBy=multi-user.target

[root@admin ~]# cat /tmp/test1.conf
cat: /tmp/test1.conf: そのようなファイルやディレクトリはありません

ユニットファイルの変更をsystemdに通知する。
[root@admin ~]# systemctl daemon-reload

ユニットを起動する。
[root@admin ~]# systemctl start test1.service
Job for test1.service failed because a configured resource limit was exceeded. See "systemctl status test1.service" and "journalctl -xe" for details.

起動に失敗したユニットを調べる。起動に失敗したユニットはtest1.serviceであることがわかる。
[root@admin ~]# systemctl --state=failed
  UNIT          LOAD   ACTIVE SUB    DESCRIPTION
● test1.service loaded failed failed test1

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

1 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.

13 coredumpctlコマンドの使い方

13.1 事前準備(core file採取のための準備)

設定ファイルの初期状態を確認する。
[root@admin ~]# cat /proc/sys/kernel/core_pattern
core

core fire採取のための設定をする。
[root@admin ~]# echo '|/usr/lib/systemd/systemd-coredump %p %u %g %s %t %e' > /proc/sys/kernel/core_pattern
[root@admin ~]# cat /proc/sys/kernel/core_pattern
|/usr/lib/systemd/systemd-coredump %p %u %g %s %t %e

テスト用のhttpdをインストールする。
[root@admin ~]# yum -y installs httpd
[root@admin ~]# systemctl start httpd
[root@admin ~]# ps -C httpd
   PID TTY          TIME CMD
  1415 ?        00:00:00 httpd
  1416 ?        00:00:00 httpd
  1417 ?        00:00:00 httpd
  1418 ?        00:00:00 httpd
  1419 ?        00:00:00 httpd
  1420 ?        00:00:00 httpd  

httpdにSIGSEGVを送信して、core fileを出力する。
[root@admin ~]# pkill -SIGSEGV httpd
[root@admin ~]# ps -C httpd
   PID TTY          TIME CMD


ちなみに、systemd-coredumpctlはcoredumpctlへのシンボリックリンクになっている。
[root@s01 ~]# ls -l /usr/bin/systemd-coredumpctl
lrwxrwxrwx. 1 root root 11  7月 22 09:14 /usr/bin/systemd-coredumpctl -> coredumpctl

13.2 core file一覧の表示方法(list)

[root@admin ~]# coredumpctl list
TIME                            PID   UID   GID SIG PRESENT EXE
日 2017-07-30 11:24:33 JST    1415     0     0  11 * /usr/sbin/httpd


ちなみに、systemdはcore fileを下記ディレクトリに保存しています。
[root@s01 ~]# ls /var/lib/systemd/coredump/
core.httpd.0.cb273bd83a3b442e9666ed39f9b4224f.1415.1501381470000000.xz

13.3 core fileの詳細情報の表示方法(info)

PIDを指定して、coredumpctl infoコマンドを実行する。
[root@admin ~]# coredumpctl info 1415
           PID: 1415 (httpd)
           UID: 0 (root)
           GID: 0 (root)
        Signal: 11 (SEGV)
     Timestamp: 日 2017-07-30 11:24:30 JST (6h ago)
  Command Line: /usr/sbin/httpd -DFOREGROUND
    Executable: /usr/sbin/httpd
-以下、略-

13.4 coreファイルの保存方法(dump)

ジャーナルに保存されたcoreファイルを/tmp配下のファイルに保存する。
[root@admin ~]# coredumpctl -o /tmp/core.1415 dump 1415

ファイルに保存したcoreファイルを確認する。/tmp配下に保存されていることがわかる。
[root@admin ~]# ls /tmp/core.*
/tmp/core.1415

13.5 デバッガを起動する方法(gdb)

coredumpctlからgdbを直接起動することで、core fileのデバッグができる。

[root@s01 ~]# coredumpctl gdb 1415
-中略-
Program terminated with signal 11, Segmentation fault.
#0  0x00007fb25ca45b83 in __select_nocancel () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install httpd-2.4.6-45.el7.centos.4.x86_64
(gdb) bt
#0  0x00007fb25ca45b83 in __select_nocancel () from /lib64/libc.so.6
#1  0x00007fb25d15c585 in apr_sleep () from /lib64/libapr-1.so.0
#2  0x00007fb25e47f781 in ap_wait_or_timeout ()
#3  0x00007fb25409913e in prefork_run () from /etc/httpd/modules/mod_mpm_prefork.so
#4  0x00007fb25e47ef6e in ap_run_mpm ()
#5  0x00007fb25e477d76 in main ()
(gdb)

14 systemdの制御

14.1 設定ファイルの再読み込み

ユニット定義ファイルの作成や変更したら実行する。systemdにユニット定義ファイルの作成、変更を知らせる。

[root@master ~]# systemctl daemon-reload

14.2 systemdの再起動

[root@master ~]# systemctl daemon-reexec
[root@master ~]#

x 参考情報

systemd: Template unit files
Understanding Systemd Units and Unit files
systemd-archlinux
systemd.service — Service unit configuration
k8sをUbuntu14.04から16.04に移行した

coredump.conf
systemd-coredump
systemd-coredumpctlでコアダンプしたプロセスのcoreファイルを取得
「Systemd」を理解する ーシステム起動編ー

32
44
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
32
44