#1 環境
[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の順でサービスが起動する。
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
[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の順でサービスが起動する。
[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
[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」を理解する ーシステム起動編ー