systemd使ってOS起動時にansible打とうぜ

# Overview
長いので目次みた方が良いかも。

## 目的
大量のNodeを立てる際に少しでも楽できないもんだろうか。
例えば OSはPXEで入れたとしてアプリケーションのインストールはどこぞのserverからansibleなどを実行する。
という感じでオペレータが介在すると思われる。（今だとk8sとかで自動でやられるんだろうか）

別にこれが普通なんか知らんけど、DeployするNodeが多ければ多い分、
OSインストールとアプリケーションインストールという動作が交差する。

時代遅れなことを自分はまだやっているのかも判らん状況だけど。

**アプリケーションインストールをOS起動時に勝手にやってくれないもんか。**

というのをテーマに考えてみた。

ただ、やっぱりこれって小手先なきがしてて今のトレンド的なやつが一番知りたい。
OSのセッティング〜アプリケーションのインストールとか人が介在するのはもう無い時代だと思ってるんだけど。。

**みんなどうやってるんだろうなぁ（＝＝；**

## 手段
PXEによるOSインストール時にansible実行環境を対象のNodeに構築しておく。
systemdに自動Deploy機構（単にansibleをキックするサービス）を仕込んでおいて当該サービスを自動起動設定する。

今回はこの仕込みの部分を考えてみた。

## systemdにした理由
rc.local等、起動時に色んなもので構築系のスクリプトはキック可能。systemdを採用した理由は以下である。

- 出来るだけスクリプト系は使いたく無い。（汎用性は得るが管理が面倒）
- ansibleはssh.service等のサービス起動後に実施する必要がある。故にサービス実行順序を制御したい
- 成功要否を容易く見れるようにしたい(systemd statusで結構わかりやすく見れた）

## 確認環境
- conoha VPS(break & buildで重宝させていただいてます（：DTZ
- OS : ubuntu16.04.5
- ansible : 2.7.7(using pip)

----

# Result
細かくは後に書くとして、以下のunit fileと変数ファイルを用意したらansibleの実行は行えた。
要点を本項では記述していく

```shell:auto-deploy.service
root@118-27-10-158:~/auto-deploy_ansible/ansible# cat /etc/systemd/system/auto-deploy.service
[Unit]
Description = Auto Deploy using Ansible.
After = ssh.service apt-daily-upgrade.timer apt-daily.timer

[Service]
EnvironmentFile = /etc/default/auto-deploy
ExecStart = /usr/local/bin/ansible-playbook -i inventories/staging/hosts ${PLAYBOOK} -t ${TAG} -l ${HOSTNAME}
WorkingDirectory = /root/auto-deploy_ansible/ansible/
Type = oneshot

[Install]
WantedBy = multi-user.target
root@118-27-10-158:~/auto-deploy_ansible/ansible#

```

```text:/etc/default/auto-deploy
root@118-27-10-158:~/auto-deploy_ansible/ansible# cat /etc/default/auto-deploy
TAG="auto-deploy"
PLAYBOOK="auto-deploy.yml"
HOSTNAME="118-27-10-158"
root@118-27-10-158:~/auto-deploy_ansible/ansible#
```

## unit fileの要点

- 変数化した方が扱い易いので`EnvironmentFile`に変数定義ファイルを用意する 
- `ExecStart`はansibleのフルパスを指定する。（パスが通っててもNG）
- `WorkingDirectory`にansibleの実行パスを記述する。
- `ansible.cfg`は`WorkingDirectory`配下もしくは「/etc/ansible」等実行時に参照出来る状況にする
- `After`の節は`ssh.service`起動後が前提条件
- `apt-daily-upgrade.time`の記述理由は当該サービスがEnableの場合、aptのインストール時に競合する可能性があるから待つ。
- `Type`を`oneshot`にしているのは1回のみ実行に明示的に定義するため。(成否問わず1回のみだ）

## サービス実行時のログ 成功時
サービス実行時にansibleが実行される。
実行後は`inactive(loaded)`にステータスは変わる。
**直近のログにansible実行ログが出力される**ので判る

```text:successパターン
root@118-27-10-158:~# systemctl start auto-deploy.service
root@118-27-10-158:~# systemctl status auto-deploy.service
● auto-deploy.service - Auto Deploy using Ansible.
   Loaded: loaded (/etc/systemd/system/auto-deploy.service; disabled; vendor preset: enabled)
   Active: inactive (dead)

Feb 11 15:19:40 118-27-10-158 ansible-playbook[6990]: ok: [118-27-10-158]
Feb 11 15:19:40 118-27-10-158 ansible-playbook[6990]: TASK [systemd : disable auto-deploy service] ***********************************
Feb 11 15:19:41 118-27-10-158 ansible-playbook[6990]: ok: [118-27-10-158]
Feb 11 15:19:41 118-27-10-158 ansible-playbook[6990]: TASK [apt : Only run "update_cache=yes"(apt-get update)] ***********************
Feb 11 15:19:43 118-27-10-158 ansible-playbook[6990]: changed: [118-27-10-158]
Feb 11 15:19:43 118-27-10-158 ansible-playbook[6990]: TASK [libvirt : Install libvirt-bin] *******************************************
Feb 11 15:19:44 118-27-10-158 ansible-playbook[6990]: ok: [118-27-10-158]
Feb 11 15:19:44 118-27-10-158 ansible-playbook[6990]: PLAY RECAP *********************************************************************
Feb 11 15:19:44 118-27-10-158 ansible-playbook[6990]: 118-27-10-158              : ok=6    changed=1    unreachable=0    failed=0
Feb 11 15:19:44 118-27-10-158 systemd[1]: Started Auto Deploy using Ansible..
root@118-27-10-158:~#
```
## サービス実行時のログ 失敗時
導入は成功時と同じ。
実行後は`Active: failed`となり、成否はここを参照したら判る。

```text:failedパターン
root@118-27-10-158:~/auto-deploy_ansible/ansible# systemctl start auto-deploy.service
Job for auto-deploy.service failed because the control process exited with error code. See "systemctl status auto-deploy.service" and "journalctl -xe" for details.
root@118-27-10-158:~/auto-deploy_ansible/ansible# systemctl status auto-deploy.service
● auto-deploy.service - Auto Deploy using Ansible.
   Loaded: loaded (/etc/systemd/system/auto-deploy.service; disabled; vendor preset: enabled)
   Active: failed (Result: exit-code) since Mon 2019-02-11 15:24:11 JST; 8s ago
  Process: 7742 ExecStart=/usr/local/bin/ansible-playbook -i inventories/staging/hosts ${PLAYBOOK} -t ${TAG} -l ${HOSTNAME} (code=exited, status=4)
 Main PID: 7742 (code=exited, status=4)

Feb 11 15:24:10 118-27-10-158 systemd[1]: Starting Auto Deploy using Ansible....
Feb 11 15:24:11 118-27-10-158 ansible-playbook[7742]: ERROR! Syntax Error while loading YAML.
Feb 11 15:24:11 118-27-10-158 ansible-playbook[7742]:   found unexpected end of stream
Feb 11 15:24:11 118-27-10-158 ansible-playbook[7742]: The error appears to have been in '/root/auto-deploy_ansible/ansible/roles/common/tasks/debug/debug_mes.yml': line 4, column 1,
Feb 11 15:24:11 118-27-10-158 ansible-playbook[7742]: be elsewhere in the file depending on the exact syntax problem.
Feb 11 15:24:11 118-27-10-158 ansible-playbook[7742]: (specified line no longer in file, maybe it changed?)
Feb 11 15:24:11 118-27-10-158 systemd[1]: auto-deploy.service: Main process exited, code=exited, status=4/NOPERMISSION
Feb 11 15:24:11 118-27-10-158 systemd[1]: Failed to start Auto Deploy using Ansible..
Feb 11 15:24:11 118-27-10-158 systemd[1]: auto-deploy.service: Unit entered failed state.
Feb 11 15:24:11 118-27-10-158 systemd[1]: auto-deploy.service: Failed with result 'exit-code'.
root@118-27-10-158:~/auto-deploy_ansible/ansible#
```

## ansible log管理
本ページの目的では無い。通常通り、ansible.cfgでログの出力先を定義する。
これにより通常のansible実行時と同様にログは確保される。

----
# hands on
何回も実験するの面倒だからサンプル資材作ったので共有しとく。
[auto-deploy_using ansible](https://github.com/maki0922/auto-deploy_ansible)

本実行手順は上記の資材を使用する前提で記述する

## ansible自動実行環境準備
やっていることはansibleのパッケージインストールとsystemd関係のファイルの配置。
次に自分自身に対してsshのNoPass設定&確認
最後にansibleのinventoryにhostnameを入れておけば準備完了。
資材の中身は大したことかいてないのでgithub見れば判るレベル。

- `git clone https://github.com/maki0922/auto-deploy_ansible`
- `cd auto-deploy_ansible/prepare/`
- `bash -x setting_systemd.yml`
- `bash -x prepare_pip.sh`
- `bash -x install_package.sh`
- `ssh-keygen -t rsa -b 4096 -C "your_email@example.com"`
- `ssh-copy-id <hostname>`
- `ssh <hostname>`
- `exit`
- edit `../ansible/inventories/staging/hosts` (add hostname to `computer` block)

### service status
以下のように自動起動設定(`enable`)されてればOK

```text:status
root@118-27-24-70:~/auto-deploy_ansible/prepare# systemctl status auto-deploy.service
● auto-deploy.service - Auto Deploy using Ansible.
   Loaded: loaded (/etc/systemd/system/auto-deploy.service; enabled; vendor preset: enabled)
   Active: inactive (dead)
root@118-27-24-70:~/auto-deploy_ansible/prepare#
root@118-27-24-70:~/auto-deploy_ansible/prepare#
```

## 自動実行開始
`reboot`コマンドでOS再起動を行う。（本来PXEによる構築後の再起動でここは賄うのだろう）

### service status(after deploy)
以下の様に`auto-deploy.service`が完了していることが判る。
※前述の通り、失敗している場合は`failed`になる。

```
root@118-27-24-70:~# systemctl status auto-deploy.service
● auto-deploy.service - Auto Deploy using Ansible.
   Loaded: loaded (/etc/systemd/system/auto-deploy.service; disabled; vendor preset: enabled)
   Active: inactive (dead)

Feb 11 16:00:52 118-27-24-70 ansible-playbook[1195]: changed: [118-27-24-70]
Feb 11 16:00:52 118-27-24-70 ansible-playbook[1195]: TASK [systemd : disable auto-deploy service] ***********************************
Feb 11 16:00:53 118-27-24-70 ansible-playbook[1195]: changed: [118-27-24-70]
Feb 11 16:00:53 118-27-24-70 ansible-playbook[1195]: TASK [apt : Only run "update_cache=yes"(apt-get update)] ***********************
Feb 11 16:00:55 118-27-24-70 ansible-playbook[1195]: changed: [118-27-24-70]
Feb 11 16:00:55 118-27-24-70 ansible-playbook[1195]: TASK [libvirt : Install libvirt-bin] *******************************************
Feb 11 16:01:08 118-27-24-70 ansible-playbook[1195]: changed: [118-27-24-70]
Feb 11 16:01:08 118-27-24-70 ansible-playbook[1195]: PLAY RECAP *********************************************************************
Feb 11 16:01:08 118-27-24-70 ansible-playbook[1195]: 118-27-24-70               : ok=6    changed=4    unreachable=0    failed=0
Feb 11 16:01:08 118-27-24-70 systemd[1]: Started Auto Deploy using Ansible..
root@118-27-24-70:~#
```

### ansible log
`ansible.cfg`にて定義したログを見てみた。`failed`は０件。良さそうだ（恍惚）

```
root@118-27-24-70:~# cat /tmp/ansible_logfile
2019-02-11 16:00:49,466 p=1195 u=root |  PLAY [auto-deploy] *************************************************************
2019-02-11 16:00:49,478 p=1195 u=root |  TASK [Gathering Facts] *********************************************************
2019-02-11 16:00:51,718 p=1195 u=root |  ok: [118-27-24-70]
2019-02-11 16:00:51,736 p=1195 u=root |  TASK [common : debug messages] *************************************************
2019-02-11 16:00:51,861 p=1195 u=root |  ok: [118-27-24-70] => {
    "msg": "auto deploy start."
}
2019-02-11 16:00:51,878 p=1195 u=root |  TASK [common : sample template 001] ********************************************
2019-02-11 16:00:52,461 p=1195 u=root |  changed: [118-27-24-70]
2019-02-11 16:00:52,477 p=1195 u=root |  TASK [systemd : disable auto-deploy service] ***********************************
2019-02-11 16:00:53,243 p=1195 u=root |  changed: [118-27-24-70]
2019-02-11 16:00:53,259 p=1195 u=root |  TASK [apt : Only run "update_cache=yes"(apt-get update)] ***********************
2019-02-11 16:00:55,654 p=1195 u=root |  changed: [118-27-24-70]
2019-02-11 16:00:55,671 p=1195 u=root |  TASK [libvirt : Install libvirt-bin] *******************************************
2019-02-11 16:01:08,084 p=1195 u=root |  changed: [118-27-24-70]
2019-02-11 16:01:08,091 p=1195 u=root |  PLAY RECAP *********************************************************************
2019-02-11 16:01:08,091 p=1195 u=root |  118-27-24-70               : ok=6    changed=4    unreachable=0    failed=0
root@118-27-24-70:~#
```

### 資材上の要点 001
aptパッケージのインストールに成功しているところがやはり大きい。
chefとかでも競合していたが`apt-daily-upgrade.time`などの自動でaptが勝手に
動作するサービスと競合させない様に出来るのがsystemdの設定の良いところ。
ログ上も無事`libvirt-bin`パッケージが入っている。

```text:log
2019-02-11 16:00:55,671 p=1195 u=root |  TASK [libvirt : Install libvirt-bin] *******************************************
2019-02-11 16:01:08,084 p=1195 u=root |  changed: [118-27-24-70]
```

### 資材上の要点 002
`auto-deploy`サービスをdisableにしている。
*「これはOSインストール後の再起動でDeployする」*という目的の基、Deploy後は勝手に起動しないための設定である。
`mask`設定するのも有りかもしれないが`disable`設定にしている。（ここは用途と好みだな）

```
root@118-27-24-70:~# systemctl is-enabled auto-deploy.service
disabled
root@118-27-24-70:~#
```