Ubuntu Serverを起動した際に、特定のdocker compose
コマンドを自動で実行したい。ホームディレクトリにある docker-compose.yaml のDockerサービスは自動で起動できている。
ぱっと思いついたのが、systemd
サービスを作成すること。この記事では、ユーザーサービスとしてsystemd
サービスを登録し、Rootless
モードでDocker Composeを自動起動する手順をまとめておく。
背景
やりたいことはシンプルで、
Seafileを起動するためのdocker compose --env-file seafile/.env -f seafile/seafile_compose.yaml start
コマンドをサーバー起動時に自動実行する。
すでに、ユーザーサービスの定義ファイルを置くためのディレクトリを作成されていた。
$ ls -l ~/.config/systemd/user/
合計 12
drwxr-xr-x 2 arimasou16 arimasou16 4096 8月 22 09:05 default.target.wants
-rw-rw-r-- 1 arimasou16 arimasou16 603 2月 10 2024 docker.service
-rw-rw-r-- 1 arimasou16 arimasou16 463 8月 22 09:03 seafile.service
ちなみにdocker.service
の中身はこうなっている。
~/.config/systemd/user/docker.service
[Unit]
Description=Docker Application Container Engine (Rootless)
Documentation=https://docs.docker.com/go/rootless/
[Service]
Environment=PATH=/usr/bin:/sbin:/usr/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/opt/nvim-linux64/bin
ExecStart=/usr/bin/dockerd-rootless.sh
・・・以下、後略・・・
次に、ユーザーサービスの定義ディレクトリ内にseafile.service
という名前でサービスファイルを作成する。
~/.config/systemd/user/seafile.service
[Unit]
Description=Seafile Docker Compose User Service
After=docker.service
Requires=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
Environment="DOCKER_HOST=unix:///run/user/1000/docker.sock"
WorkingDirectory=/home/arimasou16
ExecStart=/usr/bin/docker compose --env-file seafile/.env -f seafile/seafile_compose.yaml start
ExecStop=/usr/bin/docker compose --env-file seafile/.env -f seafile/seafile_compose.yaml stop
[Install]
WantedBy=default.target
- [Unit]セクション:
docker.service
の起動後にこのサービスが起動するように依存関係を設定する。 - [Service]セクション:
Type=oneshot
: 単発のタスクとして実行する。RemainAfterExit=yes
:ExecStart
のプロセスが終了してもサービスを有効状態に保ち、ExecStop
が実行できるようにする。WorkingDirectory
: コマンドを実行するディレクトリを絶対パスで指定する。
- [Install]セクション:
WantedBy=default.target
は、ユーザーがログインしたときにサービスが自動的に起動するようにするための標準的な設定をする。
2. サービスを有効化して起動
ファイルを作成したら、設定をリロードしてサービスを有効化する。ユーザーサービスなので--user
フラグを付け、sudo
は不要。
# 設定を再読み込み
systemctl --user daemon-reload
# ユーザーログイン時の自動起動を有効化
systemctl --user enable seafile.service
# サービスを手動で起動してみる
systemctl --user start seafile.service
3. トラブルシューティング
上記の手順で進めたところ、いくつかのエラーに遭遇した。
エラー1: Unit network-online.target not found.
当初、ネットワークが有効になってからサービスを起動しようとAfter=network-online.target
を追加していたが、このエラーが発生した。
これは、network-online.target
がユーザーセッションでは必ずしも有効ではないために起こった。
解決策:
docker.service
自体がネットワークの準備ができてから起動するため、seafile.service
がdocker.service
の後に起動するように設定されば、間接的にネットワークの問題は解決される。そのため、サービスファイルからnetwork-online.target
の記述を削除した(上記の設定ファイルは修正済みのもの)。
エラー2: DockerソケットへのPermission denied
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
これは、DockerをRootlessモードで運用していることが原因だった。
RootlessモードのDockerソケットは、システム用の/var/run/docker.sock
ではなく、ユーザーディレクトリ内の/run/user/1000/docker.sock
(1000はユーザーID)にある。systemdのユーザーサービスが、デフォルトのシステム用ソケットに接続しようとしてエラーになっていた。
解決策:
サービスファイルに環境変数DOCKER_HOST
を追加し、正しいソケットのパスを明示的に指定する。
最終的なseafile.service
ファイルは上記のようになった。
この修正後に再度systemctl --user daemon-reload
とsystemctl --user start seafile.service
を実行すると、無事にサービスが起動できた。
まとめ
以上の設定で、ユーザーログイン時に自動でDocker Composeのコンテナが起動するようになった。