それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

/var,/homeに設置した systemd ユニット・ファイルが実行されない

/var に設置した systemdファイルが読み込まれない。いくら正しいサービスファイルを書いても、起動時にサービスが起動しないのである。

色々見ていたら、こんなエラーが遭遇した

systemdはマジ怖い

存在するファイルを実行しない

/etc/systemd/system に設置したサービス・ファイルが「存在するのに」「存在しない」と言われて、起動時に実行されなくて、ずっと悩んでた。

原因がわかった。/home,/varマウントのタイミングだった

systemdが実行されるタイミングと私達が動作チェックするタイミングが異なる。

systemdが、サービスを実行するタイミングでは、ファイルシステムの一部はマウントされてない。そう /home も /var も /optもマウントされてない。

しかし、私たちが、動作チェックをするときは、すべてがマウントされたあとにssh ログインをして動作チェックをしているのだ。

再現方法

  • /home を別ボリュームにする
  • /etc/systemd/systemに /home/takuyaへのシンボリックとしてユニットファイルを設置する

これで、おかしなことができる。ユニットファイルが存在し動作も完璧。しかしsystemdに、file not found. のエラーを吐かせることができる。マウントのタイミングが異なるのだ。

依存関係がおかしいとかではなく、単にファイルが読み出せないのである。ファイルが読めないから依存関係の定義も読めないのである。

サービスファイルのリンク先が見つからない。

$ dmesg
[   11.819468] systemd[1]: smtp_proxy.service: Failed to open /var/repos/smtp-proxy/etc/systemd/smtp_proxy.service: No such file or directory

そうなんですよね。マウント前に、サービスが起動する。リンクをたどってユニットファイルを読み込もうとしても、マウントされてないのである。だから絶対に起動しないのだ。

シンボリックリンクとマウント時点の問題点

シンボリック・リンクを辿れないで systemd service が file not found のエラーを吐く場合

/etc/systemd/system にシンボリックリンクを設置してた場合

$ls -l /etc/systemd/system
iperf3@192.168.2.5.service -> /home/takuya/samples/iperf3@.service

このように、ホームディレクトリに、サンプルで作ったservice ファイルやtimerファイルなどのユニットを設置していた場合

そして、それをシンボリック・リンクで、/etc/systemd/systemに設置した場合。

このsystemdファイルは絶対に実行されない。

homeがマウントされるより先にsystemdファイル実行される

/etc/systemd/system が利用可能になった時点で、systemdはサービスを起動する。

しかし、その時点では/homeは存在するが、マウントされてないので、 /home/takuya はまだ存在してない。

そのために、/etc/systemd/system/に設置したファイルのリンク先を辿れない。

結果として、dmesg に service file not foundが大量に記録されることになる。

/etc/systemd/system とマウントの関係に注意

マウントされるよりさきに/etc/systemd/system が実行されるので、リンクが辿れずに、サービスファイルが見つからなくなる。

サービスファイル内で、いくらafter/wanterd/require を書こうとも、そもそも、ユニットファイルが読み込まれないのだから。お手上げである。

以前は、こんな事は起きなかったのだが・・・ debian 11 をインストールしたときに、インストーラーのおすすめ通りvar homeパーティション分割したので、サービスが一切起動しない結果になった。

怖い・もういや

systemdはまじ怖い。まじめんどくさい。

systemd は窓から投げ捨てたい。っていうか、一般ユーザーがサービスユニットファイルを作るとき、マウント前に起動作業することなど全く殆ど皆無である。起動処理が終わってから実行してほしいのだ。systemdが起動処理を終えてから実行してくれ。確実に起動するエントリポイントを作って欲しい。ユーザーがマウントまで意識してサービス・ユニットファイルを書くようになってるのは絶対におかしい。

/etc/systemd/system 以外に設定箇所作って欲しい。マウントとネットワークの起動処理が、全部終わったら起動する確実なやつください。

systemdは シンボリック・リンクをつかうくせに、私達がシンボリックを使うとバグを踏むのです。別ボリュームの/homeに設置したシンボリック・リンクは、マウント前になってsystemdでは動かせないのです。当たり前だけど、油断してると絶対に気づかないんです。

何も書かなくても、シンボリックリンクなら、マウントされるまで待ってほしい。

そして、なによりマウントディスクに対し systemctl daemon-reload を掛けたのであれば、リロード時にわかるはずである。警告も何も出ない。

そして、/etc/systemd/systemに記載された内容をどこかべつの /lib/systemdにコピーしてsystemd設定ファイルをつくり起動時にロードしてくれればいいのだ。それもしてないのだ。ただただ、分割先が分かりにくい init.d でしか無い。

気づくまで何時間も溶けた・・・

Linux使うならもうdocker のコンテナに引きこもって root 権限でアプリを実行することで各種の地雷を回避するのが最高なんですよねやっぱり。