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

#1　環境

```console:CentOS版数
[root@master ~]# cat /etc/redhat-release
CentOS Linux release 7.3.1611 (Core)
```

```console:カーネル版数
[root@master ~]# uname -r
3.10.0-514.el7.x86_64
```


#2 事前準備（ユニット定義ファイルの作成）
テスト用のシェルスクリプトを作成します。$1は引数(ユニット名)を表します。

```console:事前準備
[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は置換文字(ユニット名に展開される）を表します。

```console:ユニット定義ファイル作成
[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に変更した設定ファイルを読み込ませる

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

サービスを起動します。

```console:サービスの起動、終了
[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行が追加されたことだけ。

```console:ユニット定義ファイル作成
[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の順でサービスが起動する。

```console: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
```

```console: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 ~]#
```

```console:実行結果
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の順でサービスが起動する。

```console: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
```

```console: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
```

```console:実行結果
システムを再起動する。
[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 サンプルプログラム作成
サンプルプログラムは[ここ](http://therning.org/magnus/posts/2015-09-28-000-systemd-watchdog.html)からダウンロードする。

```
[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コマンドのインストール方法は[ここ](http://qiita.com/hana_shin/items/e3ef3bbaf7d89849a9c5)を参照ください。

```
[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ユニットがどのように動作するのか、ということと、ユニット指定子の意味について確認する。


```console:書式
xxx@yyy.service

xxx:プレフィックス
yyy:インスタンス
xxx@yyy.service:テンプレートユニット
```

```console:テスト用のテンプレートユニット作成
テンプレートユニットを作成する。%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
```

```console:テスト用のシェルスクリプト作成
シェルスクリプトを作成する。$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
```


```console:動作確認
ユニットファイル作成を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
```


```console:ユニット指定子の意味
ユニット指定子の意味は以下のとおりです。詳細は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](https://fedoramagazine.org/systemd-template-unit-files/)
[Understanding Systemd Units and Unit files](https://www.digitalocean.com/community/tutorials/understanding-systemd-units-and-unit-files)
[systemd-archlinux](https://wiki.archlinuxjp.org/index.php/Systemd)
[systemd.service — Service unit configuration](https://www.freedesktop.org/software/systemd/man/systemd.service.html)
[k8sをUbuntu14.04から16.04に移行した](http://blog.ladicle.com/post/systemd-for-upstart/)

[coredump.conf](https://www.freedesktop.org/software/systemd/man/coredump.conf.html)
[systemd-coredump](https://www.freedesktop.org/software/systemd/man/systemd-coredump.html#)
[systemd-coredumpctlでコアダンプしたプロセスのcoreファイルを取得](http://kernhack.hatenablog.com/entry/2013/11/07/012255)
[「Systemd」を理解する ーシステム起動編ー](http://equj65.net/tech/systemd-boot/)