Ubuntu Weekly Recipe

第598回systemdユニットの設定を変える

第557回では、systemdユニットの依存関係を読む方法を紹介しました。 今回は、systemdユニットの設定を変更する方法を紹介します。

事前準備

systemdユニットの設定変更は最悪の場合、システムが正常に起動しなくなる恐れもあります。したがって手順を実際に試す際には、壊れても大丈夫なように検証用の仮想マシンなどを用意してください

また、本稿では題材としてApacheの設定を変更する手順を解説しますので、以下のようにインストールしておきます。

$ sudo apt -y install apache2

systemdユニットの設定の在り処

さて、apache2パッケージのインストールが完了したら、systemdユニットを見てみましょう。ここは第557回のおさらいです。 インストール直後の状態だと以下のように表示されているはずです。

$ systemctl cat apache2.service
# /lib/systemd/system/apache2.service
[Unit]
Description=The Apache HTTP Server
(略)

ユニットの設定ファイルのパスとして/lib/systemd/system/apache2.serviceが表示されています。これを変更すれば……と思った方はちょっと待ってください! そもそも、/lib/systemd/system/apache2.serviceはどこから来たものなのでしょうか? 答えは以下のコマンドで確認できます。

$ dpkg -S /lib/systemd/system/apache2.service
apache2: /lib/systemd/system/apache2.service

この結果は/lib/systemd/system/apache2.serviceファイルは先ほどインストールしたapache2パッケージにより配置されたものであることを示しています。 つまり、この設定ファイルをせっかくカスタマイズしても、apache2パッケージが更新されるたびにパッケージのデフォルト設定に置き換えられてしまうため、設定を維持できません

このようにUbuntuでは[1]/lib/systemd/system/配下にはパッケージ由来のユニット設定ファイルを置くというルールになっており、これらを直接変更することはしません。

ユニット設定の変え方

では、ユニット設定を変えたい場合、どのような方法があるのでしょうか?

具体的な方法は、ユニット設定ファイルをまるごと上書きする方法と、drop-inファイルで一部を書き換える方法の2つがあります。それぞれ順に説明します。

ユニット設定ファイルをまるごと上書きする

/lib/systemd/system/のほかにもsystemdがユニット設定ファイルを読み込むパスの1つとして/etc/systemd/systemがあります[2]⁠。そして、systemdは同名のユニット設定ファイルがある場合/lib/systemd/system/よりも/etc/systemd/systemを優先して読み込みます。

そのため、/lib/systemd/system/apache2.serviceファイルを/etc/systemd/system/apache2.serviceとしてコピーして、後者をお好み通りに書き換えることで、ユニット設定をまるごと上書きする(差し替える)ことができます。

それでは、実際にやってみましょう。 ユニットの説明を記載するDescription=ディレクティブは変更しても無害と考えられますので、今回はこれを変更します。

まずは改めて変更前の状態を確認します。

$ systemctl cat apache2.service
# /lib/systemd/system/apache2.service
[Unit]
Description=The Apache HTTP Server
(略)
$ systemctl status apache2
● apache2.service - The Apache HTTP Server
(略)

この結果より以下がわかります。

  • systemdはapache2.serviceの設定ファイルとして/lib/systemd/system/apache2.serviceを読み込んでいる。
  • systemctl statusで表示されるユニット情報は/lib/systemd/system/apache2.serviceに記載されているとおりapache2.service - The Apache HTTP Serverとなっている。

それでは、このユニット設定を書き換えます。どこパスのファイルを読み込んでいるかをわかりやすくするため、Description=(This unit file is in /etc/systemd/system)を追記します。

$ sudo cp /lib/systemd/system/apache2.service /etc/systemd/system/apache2.service
$ sudo vi /etc/systemd/system/apache2.service # Desciprion= の内容を書き換える
$ diff /lib/systemd/system/apache2.service /etc/systemd/system/apache2.service # 変更差分を確認する
2c2
< Description=The Apache HTTP Server
---
> Description=The Apache HTTP Server(This unit file is in /etc/systemd/system)
$ sudo systemctl daemon-reload # ユニット設定をリロードする

同じく、上書き後の状態を確認します。

$ systemctl cat apache2.service
# /etc/systemd/system/apache2.service
[Unit]
Description=The Apache HTTP Server(This unit file is in /etc/systemd/system)
(略)
$ systemctl status apache2
● apache2.service - The Apache HTTP Server(This unit file is in /etc/systemd/system)
(略)

この結果から以下のことがわかります。

  • systemdはapache2.serviceの設定ファイルとして/etc/systemd/system/apache2.serviceのみを読み込んでいる。
  • systemctl statusで表示されるユニット情報は/etc/systemd/system/apache2.serviceに記載されている通りapache2.service - The Apache HTTP Server(This unit file is in /etc/systemd/system)となっている。

ユニットのマスク 〜特殊な上書き〜

ユニット設定の書き換えというわけではないですが、ここまでに紹介したまるごと上書きの特殊例として、ユニットのマスクを紹介します。

systemctl disableコマンドを使うことで、ユニットの無効化ができますが、この状態でも例えば手動で起動できます。 このdisableコマンドより強力なものとしてmaskコマンドがあります。これは手動での起動やユニットの有効化も不可にするコマンドです。

実際に試してみましょう。

$ sudo systemctl mask apache2.service
Created symlink /etc/systemd/system/apache2.service → /dev/null.

/etc/systemd/system/apache2.serviceというパスで/dev/nullへのシンボリックリンクが張られました[3]⁠。ここまでの解説同様、/dev/nullへのシンボリックリンクとなっている/etc/systemd/system/apache2.service/lib/systemd/system/apache2.serviceをまるごと上書きしていると言えます。

なお、マスクされたユニットは有効化することも手動で起動することもできません。 ユニットのマスクを解除するにはsystemctl unmaskを使います。

drop-inファイルで一部を書き換える

続いて、drop-inファイルを使ってユニット設定の一部を変更する方法を紹介します。

drop-inファイルを使う方法では、ユニット設定全体ではなく、変更したい設定箇所だけを上書きできます。 drop-inファイルは/etc/systemd/system/ユニット名.d/内に作成された.confという拡張子を持つファイルです。このdrop-inファイルではユニット設定ファイルの記述と同じ階層構造・形式[]でセクションを区切る、ディレクティブ=値で記載する)で設定変更箇所を記入します。

まずは、先ほど作業した/etc/systemd/system/apache2.serviceは掃除して、設定を読み込み直しておきます。

$ sudo rm /etc/systemd/system/apache2.service
$ sudo systemctl daemon-reload

それでは実際にdrop-inファイルを作ってみます。

$ sudo mkdir /etc/systemd/system/apache2.service.d # drop-inファイルを配置するディレクトリを作成する
$ sudo vi /etc/systemd/system/apache2.service.d/description.conf # drop-inファイルを作成する
$ cat /etc/systemd/system/apache2.service.d/description.conf
[Unit]
Description=The Apache HTTP Server(Overridden by drop-in file)
$ sudo systemctl daeamon-reload

状況を確認します。 読み込まれている設定ファイルを確認します。

$ systemctl cat apache2.service
# /lib/systemd/system/apache2.service
[Unit]
Description=The Apache HTTP Server
(略)

# /etc/systemd/system/apache2.service.d/description.conf
[Unit]
Description=The Apache HTTP Server(Overridden by drop-in file)

このように/lib/systemd/system/apache2.service/etc/systemd/system/apache2.service.d/description.confの両方が読み込まれていることを確認できます。

では実際にどちらのDescription=が有効になっているかを確認します。 再びsystemctl statusを使っても良いのですが、今回はsystemdが認識しているユニット情報を表示するsystemctl showコマンドで確認してみます[4]⁠。

$ systemctl show apache2.****service --property Description
Description=The Apache HTTP Server(Overridden by drop-in file)

この結果からわかるとおり、Description=はdrop-inファイルの設定で書き換えられています。

確認の結果をまとめると、以下のとおりです。

  • systemdはapache2.serviceの設定ファイルとして/lib/systemd/system/apache2.serviceとdrop-inファイル/etc/systemd/system/apache2.service.d/description.confの両方を読み込んでいる。
  • Description=/etc/systemd/system/apache2.service.d/description.confの内容が優先され、Description=The Apache HTTP Server(Overridden by drop-in file)となっている。

drop-inファイルに関するTips

ユニット設定のうち、複数回繰り返すことでリストにできる設定は、同じようにdrop-inすると変更ではなく追加されます。 ゼロから設定し直したい場合は、一度設定を空にしてから、再設定する必要があります。

リストにできる設定の有名な例がExecStart=[5]で、具体的には以下のように設定を一度クリアすることで、ゼロから設定できます。

[Service]
ExecStart=
ExecStart=/bin/echo 'Hello world from drop-in!'

なお、依存関係やアクティベート順序もリストにできる設定ですが、これらは空の値を許容しません。そのため上記の手法のように、drop-inでいったん消してゼロから再設定することはできませんので、まるごと上書きする方法を使ってください[6]⁠。

また、必要とされる場面は多くないと考えられるものの、/etc/systemd/systemのユニット設定ファイルとdrop-inファイルは併用できます。 今回の記事の手順でいえば、/etc/systemd/system/apache2.serviceの掃除せずにdrop-inファイルで書き換える作業を始めてしまった人は、以下のようにdrop-inのほうが優先されていることがわかります。

$ systemctl cat apache2.service
# /etc/systemd/system/apache2.service
[Unit]
Description=The Apache HTTP Server(This unit file is in /etc/systemd/system)
(略)
# /etc/systemd/system/apache2.service.d/description.conf
[Unit]
Description=The Apache HTTP Server(Overridden by drop-in file)
$ systemctl status apache2
● apache2.service - The Apache HTTP Server(Overridden by drop-in file)
(略)

なお、drop-inファイルは複数配置することが可能です。しかし、パスではなくファイル名の辞書順で読み込まれます[7]⁠。

まるごと上書きとdrop-inの比較

最後に、ユニット設定ファイルをまるごと置き換えるユニット設定の上書きと変更したい箇所だけをdrop-inファイルで変更する方法を、おさらいも兼ねて比較します。

/etc/systemd/systemに同名のユニット設定ファイルを置いてまるごと上書きする方法は、パッケージで提供されるユニット設定ファイルの影響をまったく受けないという点が特徴です。 また、前述のとおり、依存関係やアクティベート順序をゼロから設定しなおしたい場合は、こちらの方法を使うしかありません。 裏を返せばパッケージで提供されるユニット設定ファイルで仮に「より良い設定[8]⁠」が施された場合などに恩恵を受けられないというデメリットがあります。

drop-inファイルを使う方法の特徴は、まるごと上書きする方法をひっくり返したものとなります。 つまり、drop-inファイルを使う方法では(多くの場合)パッケージ由来のユニット設定ファイルのうち、指定した箇所のみを変更します。そのため、その他の設定はパッケージ由来のユニット設定ファイルのまま使うことができます。 こちらも裏を返せばパッケージ由来のユニット設定ファイルの影響を受けるため、パッケージの更新に伴いユニット設定ファイルが変更された場合、drop-inファイルで変更した内容と矛盾が生じる可能性があるのはデメリットです。 また、依存関係やアクティベート順序は追加のみが可能でゼロから設定しなおすことはできません。

基本的に、どちらの方法が優れているというわけではなく、どちらがより都合が良いかという観点で考えて、使い分けるのがいいでしょう。

なにはともあれ、⁠パッケージ由来のユニット設定ファイルを直接書き換えてしまい、パッケージの更新でせっかくのカスタマイズが飛んでしまう」という例がすこしでもなくなれば、筆者としては幸いです。

おすすめ記事

記事・ニュース一覧