CentOS7の/etc/fstabのnofailオプション（あるいはsystemd）

#結論（ショートカット）
ディスクのマウントに失敗してもブートしてほしいときには、`/etc/fstab`で`nofail`オプションを付けます。

#何をしたかったか
　サーバ運用を行っていると、OS用とは別にデータディスクを追加することがあると思います。アプリケーションサーバやサービスが使用するデータとOSを分けておくためです。データディスクはRAIDだったり、エンクロージャだったり、AWSでEBSだったりします。
　ところがRAIDは崩壊したり、エンクロージャは線が抜けていたり、EBSは別のインスタンスを立ち上げるときにつけ忘れたりします。そのため、CentOS6ではデータディスクは/etc/fstabで第5オプションと第6オプションを`0 0`にしていたのでした。（正確には起動時に無視するかどうかは第6オプション）

```shell-session:CentOS6での/etc/fstab（抜粋）
/dev/system/root        /                       ext3    defaults        1 1
/dev/system/var         /var                    ext3    noatime         1 2
tmpfs                   /dev/shm                tmpfs   size=4G         0 0
...
# 追加ディスク
/dev/xvda               /data                   ext4    defaults        0 0
```

　こうしておくと、起動時に`/dev/xvda`ディスクが無いか、破損して`mount`できなくてもサーバは起動してくれます。ところがCentOS7はそんな事情を組んでくれず、`0 0`だろうとあっさりemergencyモードに入ります。この状態では当然sshdは起動していません。
![emergency.png](https://qiita-image-store.s3.amazonaws.com/0/25493/8e55aaff-0b6c-46c6-3331-5cfcfaf3a356.png)
　したがってシリアルコンソールなどの回復手段が無かった場合にはサーバまで走るか、AWSのような環境では一度ディスクイメージを操作する必要があります。泣きたくなる日ですね。

#なんでこうなるの？
**systemd**

　適当に調べた限りでは、`fstab`（やmount）がsystemdの担当になり、`local-fs.target`というスペシャルユニットになり、そこにこう書かれているからです。

```ini:/usr/lib/systemd/system/local-fs.target（抜粋）
[Unit]
Description=Local File Systems
...
Conflicts=shutdown.target
OnFailure=emergency.target
...
```

#回避方法
　`local-fs.target`に手を出すのはヤバそうですし、`/`や`/var`などが`mount`できないなら確かにエマージェンシーになっても仕方ないでしょう。
　力技回避としては`noauto`にして 手動`mount`が思い当ります。cronの`@reboot`とかが良さそうですね。しかしできればアプリケーションサーバやサービスの起動前に確実性を持って`mount`していてほしいです。
　cronの`@reboot`が立ち上がるのはどのタイミングでしょうか。万が一にも逆順になると、`df`と`du`の結果が食い違うような割とやっかいなトラップになります。もしこうなるのならいっそ`mount`してくれない方がマシなようにも思います。

##解決策
　諦めてサービスやアプリケーションサーバを起動するsupervisordのsystemdのユニットの依存関係に`mount`を実行するように記述するか？と思っていろいろ探してると今回の挙動に関する説明を見つけました。
`> man systemd.mount`
http://www.freedesktop.org/software/systemd/man/systemd.mount.html
（※URLはCentOS7とはバージョンが異なるので注意）

　これによると、どうやら新しい`/etc/fstab`にはいくつかのマウントオプションが加わったようです。今回やりたいことからすると、使えそうなのは次の2つのどちらかでしょう。以下意訳

>nofail
>> nofail付のマウントはlocal-fs.targetやremote-fs.targetにとってWantsであり、Requiresではありません。したがって、このマウントポイントのマウントに失敗してもブートは続行されます。
>
>x-systemd.automount
>> そのファイルシステム用のautomountエントリーが作られます。詳細はsystemd.automount(5)

　無視させるには`nofail`で十分そうです。`nofail`を設定したところ、すんなり起動しました。

```shell-session:CentOS7での/etc/fstab（抜粋）
/dev/system/root        /                       xfs     defaults        1 1
/dev/system/var         /var                    xfs     defaults        1 2
...
# 追加ディスク
/dev/xvda               /data                   xfs     nofail          0 0
```
　ちなみに、`nofail`自体は大昔からあり、起動時に無視してもよい場合は`nofail`にするのが正しい(?)流儀のようです。CentOS6でも、fstabやmountの英語版のmanpageには`nofail`のことが（ブートには触れられていませんが）書かれています…(; ･3･)ｱﾙｪｰ

#おまけ
　なお、systemdでは`mount`コマンドを実行するユニットを作るのではなく、mountユニットという専用のユニットタイプがあります。automount用のユニットタイプもあります。~~なぜそこまでsystemdがやるのか…というかsystemdってホント何なの。~~このmountユニットはユニットファイルを書いてもいいらしいのですが、`/etc/fstab`を読んで自動で作ってくれるので、いつもどおり`/etc/fstab`に書くのが推奨されています。そりゃそうだ。

　ところで、依存関係をきちんと考えると、本来は`mount`に失敗した時にはアプリケーションサーバを立ち上げたくはありません。かといってsupervisordのユニットファイルにsupervisordの子であるアプリケーションサーバの依存関係を書くのは不本意でしょう。（supervisordユニットは`rc.local`に依存しているので`rc.local`を使うことはできますが、`rc.local`ももはやレガシーです。）
　いろいろ考えるとsupervisord（の類）は基本的にはお役御免で、systemdでアプリケーションサーバを立ち上げるのがベストということになります。いや、そういう意味でmountをsystemdがやる必要があるのはわかるんですが…systemdのユニット作成は簡単かつさすがの高機能です。起動しなかった場合の通知や標準出力・標準エラー出力方法は今後の課題…

```ini:/etc/systemd/system/myservice.service
[Unit]
Description=My Service
#マウントできない場合は起動させない systemd.unit(5)
RequiresMountsFor=/data
# => または、Requires/After？(noautoの場合)

#ディスクのディレクトリ構造を起動条件に含めることも可能 systemd.unit(5)
ConditionPathExists=/data/myapp

[Service]
ExecStart=/path/to/app
Restart=always
TimeoutSec=60
User=http

#こういう指定/制限が可能 systemd.exec(5), systemd.service(5)
LimitNOFILE=2048

[Install]
WantedBy=multi-user.target
```