これは、なにをしたくて書いたもの?
systemdのユニット定義ファイルを編集する際に、ふつうにエディタコマンドで直接開いて設定したりしていたのですが、そのあたりの
考え方が間違ってそうなのでメモしておくことにしました。
systemctl edit
コマンドで編集するのが良さそうです。
使用するコマンド
systemctlのmanページはこちら。
Ubuntu Manpage: systemctl - Control the systemd system and service manager
今回扱う用途とコマンドの対応表を、以下に記載します。
用途 | 対応するコマンド | 備考 |
---|---|---|
ユニット定義ファイルの内容を確認したい | systemctl cat [パターン(ユニット名)] | フラグメントやドロップインも含めて表示する |
ユニット定義ファイルを編集したい(ドロップイン) | systemctrl edit [ユニット名] | ドロップインファイルを作成、編集する |
ユニット定義ファイルを編集したい(本体) | systemctrl edit --full [ユニット名] | |
ユニット定義ファイルを新規作成したい | systemctrl edit --force --full [ユニット名] | |
ユニット定義ファイルをベンダー定義のバージョンに戻したい | systemctl revert [ユニット名] | ドロップインファイルは削除される |
気にした方がよさそうなポイントもあるのですが、それはこれから見ていきます。
環境
今回の環境は、こちら。
$ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.4 LTS Release: 22.04 Codename: jammy $ uname -smvrpio Linux 5.15.0-101-generic #111-Ubuntu SMP Tue Mar 5 20:16:58 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
Ubuntu Linux 22.04 LTSです。
また、お題の都合上Dockerを使用します。
$ docker version Client: Docker Engine - Community Version: 26.0.0 API version: 1.45 Go version: go1.21.8 Git commit: 2ae903e Built: Wed Mar 20 15:17:48 2024 OS/Arch: linux/amd64 Context: default Server: Docker Engine - Community Engine: Version: 26.0.0 API version: 1.45 (minimum version 1.24) Go version: go1.21.8 Git commit: 8b79278 Built: Wed Mar 20 15:17:48 2024 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.6.28 GitCommit: ae07eda36dd25f8a1b98dfbf587313b99c0190bb runc: Version: 1.1.12 GitCommit: v1.1.12-0-g51d5e94 docker-init: Version: 0.19.0 GitCommit: de40ad0
お題
Ubuntu Linux 22.04 LTSにインストールしたDockerに対して、環境変数でプロキシを設定する、というお題でやってみたいと思います。
なお、プロキシサーバーについては省略しますが、http://localhost:8080
でアクセスできるものとします。
systemdのユニット定義ファイルを確認する(本体のファイルのみ)
systemdのユニット定義ファイルは、systemctl cat [ユニット名]
コマンドで確認できます。管理者権限は不要です。
$ systemctl cat docker # /lib/systemd/system/docker.service [Unit] Description=Docker Application Container Engine Documentation=https://docs.docker.com After=network-online.target docker.socket firewalld.service containerd.service time-set.target Wants=network-online.target containerd.service Requires=docker.socket [Service] Type=notify # the default is not to use systemd for cgroups because the delegate issues still # exists and systemd currently does not support the cgroup feature set required # for containers run by docker ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock ExecReload=/bin/kill -s HUP $MAINPID TimeoutStartSec=0 RestartSec=2 Restart=always # Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229. # Both the old, and new location are accepted by systemd 229 and up, so using the old location # to make them work for either version of systemd. StartLimitBurst=3 # Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230. # Both the old, and new name are accepted by systemd 230 and up, so using the old name to make # this option work for either version of systemd. StartLimitInterval=60s # Having non-zero Limit*s causes performance problems due to accounting overhead # in the kernel. We recommend using cgroups to do container-local accounting. LimitNPROC=infinity LimitCORE=infinity # Comment TasksMax if your systemd version does not support it. # Only systemd 226 and above support this option. TasksMax=infinity # set delegate yes so that systemd does not reset the cgroups of docker containers Delegate=yes # kill only the docker process, not all processes in the cgroup KillMode=process OOMScoreAdjust=-500 [Install] WantedBy=multi-user.target
コメントで、ユニット定義ファイルのパスが書かれています。
# /lib/systemd/system/docker.service
diffをとってみると、このコメント以外は内容は同じです。
$ diff <(systemctl cat docker) /lib/systemd/system/docker.service 1d0 < # /lib/systemd/system/docker.service
systemdのユニット定義ファイルを編集する(ドロップインファイル)
次に、systemdのユニット定義ファイルを編集してみます。
この時、ソフトウェアの提供元のユニット定義ファイルを直接編集するのではなく、ドロップインファイルでオーバーライドするのが良いと
されています。
ドロップインファイルというのは、ユニット定義がfoo.service
だった場合にfoo.service.d
ディレクトリ配下に配置したファイルです。
これは、systemctl edit [ユニット名]
で行います。
$ sudo systemctl edit docker
ちなみに、この時Ubuntu Linux 22.04 LTSだとnanoが起動して困ったので、気になる人は以下のコマンドで好みのエディターを指定するように
してください。
$ sudo update-alternatives --config editor
systemctl edit
を実行すると、以下のようにコメントアウトされた元の内容が表示されるので、こちらを参考にドロップインファイルを
作成しましょう。
### Editing /etc/systemd/system/docker.service.d/override.conf ### Anything between here and the comment below will become the new contents of the file ### Lines below this comment will be discarded ### /lib/systemd/system/docker.service # [Unit] # Description=Docker Application Container Engine # Documentation=https://docs.docker.com # After=network-online.target docker.socket firewalld.service containerd.service time-set.target # Wants=network-online.target containerd.service # Requires=docker.socket # # [Service] 〜省略〜
今回は、こんな感じのファイルにしました。
[Service] Environment="http_proxy=http://localhost:8080" Environment="https_proxy=http://localhost:8080"
ファイル名は、デフォルトでoverride.conf
になります。今回は/etc/systemd/system/docker.service.d/override.conf
になりました。
あとは再起動すれば変更が反映されます。
$ sudo systemctl restart docker
ここで、systemctl edit
の後にsystemctl daemon-reload
は要りません。
この意味でも、systemctl edit
を使うべきな気がしますね…。
systemdのユニット定義ファイルを確認する(本体のファイル+ドロップインファイル)
この状態で、systemctl cat
で確認してみます。
$ systemctl cat docker
ドロップインファイル含めて表示されています。
# /lib/systemd/system/docker.service [Unit] Description=Docker Application Container Engine Documentation=https://docs.docker.com After=network-online.target docker.socket firewalld.service containerd.service time-set.target Wants=network-online.target containerd.service Requires=docker.socket [Service] Type=notify # the default is not to use systemd for cgroups because the delegate issues still # exists and systemd currently does not support the cgroup feature set required # for containers run by docker ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock ExecReload=/bin/kill -s HUP $MAINPID TimeoutStartSec=0 RestartSec=2 Restart=always # Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229. # Both the old, and new location are accepted by systemd 229 and up, so using the old location # to make them work for either version of systemd. StartLimitBurst=3 # Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230. # Both the old, and new name are accepted by systemd 230 and up, so using the old name to make # this option work for either version of systemd. StartLimitInterval=60s # Having non-zero Limit*s causes performance problems due to accounting overhead # in the kernel. We recommend using cgroups to do container-local accounting. LimitNPROC=infinity LimitCORE=infinity # Comment TasksMax if your systemd version does not support it. # Only systemd 226 and above support this option. TasksMax=infinity # set delegate yes so that systemd does not reset the cgroups of docker containers Delegate=yes # kill only the docker process, not all processes in the cgroup KillMode=process OOMScoreAdjust=-500 [Install] WantedBy=multi-user.target # /etc/systemd/system/docker.service.d/override.conf [Service] Environment="http_proxy=http://localhost:8080" Environment="https_proxy=http://localhost:8080"
本体のユニット定義ファイルを編集する
次は、本体のユニット定義ファイルを編集してみます。
まずsystemctl edit
でドロップインファイルを以下のように変更。
/etc/systemd/system/docker.service.d/override.conf
[Service] Environment="http_proxy=http://localhost:8080" #Environment="https_proxy=http://localhost:8080"
コメントアウトした方は、本体のユニット定義ファイルに追加することにしましょう。
この場合に使うコマンドは、systemctl edit --full
です。
$ sudo systemctl edit --full docker
--full
オプションを付けると、本体のユニット定義ファイルを編集できます。今回は、以下のように変更。
〜省略〜 [Service] Type=notify # the default is not to use systemd for cgroups because the delegate issues still # exists and systemd currently does not support the cgroup feature set required # for containers run by docker ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock ExecReload=/bin/kill -s HUP $MAINPID TimeoutStartSec=0 RestartSec=2 Restart=always Environment="https_proxy=http://localhost:8080" 〜省略〜
あとは再起動すれば変更が反映されます。
$ sudo systemctl restart docker
変更内容を元に戻す
ここまでで、インストール時点のユニット定義ファイルとは、このような差になりました。
$ diff <(systemctl cat docker) /lib/systemd/system/docker.service 1d0 < # /etc/systemd/system/docker.service 18a18 > Environment="http_proxy=http://localhost:8080" 49,53d48 < < # /etc/systemd/system/docker.service.d/override.conf < [Service] < Environment="http_proxy=http://localhost:8080" < #Environment="https_proxy=http://localhost:8080"
これを元に戻すには、systemctl revert
を実行します。
$ sudo systemctl revert docker
実行ログ。
Removed /etc/systemd/system/docker.service.d/override.conf. Removed /etc/systemd/system/docker.service.d. Removed /etc/systemd/system/docker.service.
差分がなくなりました。
$ diff <(systemctl cat docker) /lib/systemd/system/docker.service 1d0 < # /lib/systemd/system/docker.service
新しくユニット定義ファイルを作成する
systemctl
コマンドで新しくユニット定義ファイルを作成する場合は、systemctl edit --force --full
コマンドを使います。
$ sudo systemctl edit --force --full my-service
この場合、/etc/systemd/system
配下にファイルを作成しようとします。
自分で用意したユニット定義ファイルをrevertすると?
ところで、自分で用意したユニット定義ファイルをsystemctl revert
するとどうなるのでしょう?
作成してみます。
$ sudo systemctl edit --force --full my-httpd
こんな内容にしてみました。
$ systemctl cat my-httpd # /etc/systemd/system/my-httpd.service [Unit] Description=My Simple Http Server After=networ-online.target Wants=network-online.target [Service] Type=simple ExecStart=python3 -m http.server --directory /tmp [Install] WantedBy=multi-user.target
起動することを確認。
$ sudo systemctl start my-httpd
systemctl revert
してみます。
$ sudo systemctl revert my-httpd
特になにも表示されません。systemctl cat
でも、そのまま中身が残っています。
$ systemctl cat my-httpd # /etc/systemd/system/my-httpd.service [Unit] Description=My Simple Http Server After=networ-online.target Wants=network-online.target [Service] Type=simple ExecStart=python3 -m http.server --directory /tmp [Install] WantedBy=multi-user.target
それもそのはずで、manページを見ると「削除されない」と書かれています。
Note that if a unit file has no vendor-supplied version (i.e. is only defined below /etc/systemd/system or /run/systemd/system, but not in a unit file stored below /usr/), then it is not removed. Also, if a unit is masked, it is unmasked.
Ubuntu Manpage: systemctl - Control the systemd system and service manager
ちなみに、自分で用意したユニット定義ファイルにもsystemctl edit
でドロップインファイルを作成することができます。
このパターンはあまり使わない気もしますが。
おわりに
systemdのユニット定義ファイルを確認、編集、そしてインストールした時点のものに戻す方法を調べてみました。
今までふつうにエディターで編集していたので、こうやってコマンドで操作できることを知りませんでした…。
コマンドのmanページとか見ないとダメですね…。