2024-05-27

Docker Root Dir の場所をデフォルトから変えてみる(大失敗)

Docker Root Dir は docker pull などでダウンロードしたコンテナイメージが保管される場所です。デフォルトでは /var/lib/docker と設定されているため、人によってはディスクの空き容量があっという間に足りなくなってしまう可能性があります。

変え方はいろいろある

Linux 界隈のあるあるですが、何かをしたい場合の手段が必ずと言っていいほど複数存在しています。これが一般人に難解さを感じさせる原因なのではないかと思います。

 

それはさておき、まずは dockerd の起動オプションで場所を指定する方式です。

$ cat /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

ExecStart= の部分が dockerd の起動オプションの指定です。ここに -g /home/〜 みたいな感じで起動オプションを追加してあげれば Docker Root Dir を変更できます。

同じ方式の派生版ですが /etc/systemd/system/docker.service.d/docker.conf というファイルを作成し、ここに ExecStart= を記載しても変更できます。


もう一つは daemon.json を用意するパターンです。

/etc/docker/daemon.json

{
    "graph": "/home/xxxxxxxx/docker-image"
}

結論としてはこちらの daemon.json で変更する方式を採用しました。

最初の docker.service を編集した場合、Docker CE のアップデートで内容が更新されてしまい、再編集しないといけなくなりそうだったからです。

その次の docker.conf を用意する方式も似たような理由です。アップデートで docker.service が変更された時に docker.conf を追い上げないといけないからです。

daemon.json を使うとアップデートによる変更の影響を受けず、起動オプションの中でも自分が変更したい部分をピンポイントで変更できそうです。


いざ変更

daemon.json の用意ができたので、dockerd に反映してみます。まずは停止からです。

$ systemctl stop docker.service 
Warning: Stopping docker.service, but it can still be activated by:
  docker.socket

おっと、docker.socket も停止しないといけないようですね。

$ systemctl stop docker.socket

docker.socket も停止しました。

$ systemctl daemon-reload
$ systemctl start docker.service docker.socket
Job for docker.service failed because the control process exited with error code.
See "systemctl status docker.service" and "journalctl -xeu docker.service" for details.

なんと!docker の起動エラーになってしまいました。systemctl status で確認しろとのことです。はい、確認してみます。

$ systemctl status docker.service
× docker.service - Docker Application Container Engine
     Loaded: loaded (/lib/systemd/system/docker.service; enabled; preset: enabled)
     Active: failed (Result: exit-code) since Sun 2024-05-26 11:08:24 JST; 20s ago
   Duration: 1d 16min 55.917s
TriggeredBy: × docker.socket
       Docs: https://docs.docker.com
    Process: 72220 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock (code=exited, statu>
   Main PID: 72220 (code=exited, status=1/FAILURE)
        CPU: 52ms

 5月 26 11:08:24 xxxxx systemd[1]: docker.service: Scheduled restart job, restart counter is at 3.
 5月 26 11:08:24 xxxxx systemd[1]: Stopped docker.service - Docker Application Container Engine.
 5月 26 11:08:24 xxxxx systemd[1]: docker.service: Start request repeated too quickly.
 5月 26 11:08:24 xxxxx systemd[1]: docker.service: Failed with result 'exit-code'.
 5月 26 11:08:24 xxxxx systemd[1]: Failed to start docker.service - Docker Application Container Engine.

「Start request repeated too quickly.」とあります。 docker.service と docker.socket を同時に start したのがいけなかったんでしょうか?

docker.socket の方も確認してみます。

$ systemctl status docker.socket
× docker.socket - Docker Socket for the API
     Loaded: loaded (/lib/systemd/system/docker.socket; enabled; preset: enabled)
     Active: failed (Result: service-start-limit-hit) since Sun 2024-05-26 11:08:24 JST; 1min 15s ago
   Duration: 6.544s
   Triggers: ● docker.service
     Listen: /run/docker.sock (Stream)
        CPU: 818us

 5月 26 11:08:17 xxxxx systemd[1]: Starting docker.socket - Docker Socket for the API...
 5月 26 11:08:17 xxxxx systemd[1]: Listening on docker.socket - Docker Socket for the API.
 5月 26 11:08:24 xxxxx systemd[1]: docker.socket: Failed with result 'service-start-limit-hit'.

「service-start-limit-hit」とあります。もしや一度でもこの状態になると何かしらリセットしないと二度と起動できなくなってしまうのでしょうか?

という訳で、ステータスのリセットコマンドを発見したので投入してみます。

$ systemctl reset-failed docker.service
$ systemctl reset-failed docker.socket

うん、ステータスはリセットされました。

この状態でもう一度 docker.socket と docker.service を順番に起動してみたのですが、状況は変わらずでエラーになってしまいます。

 

ちょっと作戦を変更

なんかこれは起動のタイミングの問題ではなさそうだ、という勘が働きました。試しに追加で作成した daemon.json をリネームして無効化してみました。 

そして docker を起動させてみると、キレイに起動されます。

なるほど、追加した daemon.json に問題があるようです。

docker image保存先を外部ストレージに変更する

先ほど用意していた daemon.json の見た感じは問題なさそうだったのですが、調べてみると原因が見つかりました。Docker のバージョンによって指定するパラメーター名が違うそうです!!!

Docker 23 未満は graph で、Docker 23 以降は data-root で指定するという違いがあるそうです。

ここまで来れば勝ったも同然です。daemon.json を再編集して docker を再起動させます。

$ sudo docker info
Client: Docker Engine - Community
 Version:    26.1.3
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.14.0
    Path:     /usr/libexec/docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v2.27.0
    Path:     /usr/libexec/docker/cli-plugins/docker-compose

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 26.1.3
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Using metacopy: false
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: systemd
 Cgroup Version: 2
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
 Swarm: inactive
 Runtimes: runc io.containerd.runc.v2
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 8b3b7ca2e5ce38e8f31a34f35b2b68ceb8470d89
 runc version: v1.1.12-0-g51d5e94
 init version: de40ad0
 Security Options:
  apparmor
  seccomp
   Profile: builtin
  cgroupns
 Kernel Version: 6.7.12-zen3
 Operating System: LMDE 6 (faye)
 OSType: linux
 Architecture: x86_64
 CPUs: 12
 Total Memory: 23.35GiB
 Name: 
 ID: 
 Docker Root Dir: /home/xxxxxxxx/docker-image
 Debug Mode: false
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false

いやぁ、長い戦いでした。