TOC
Podmanでいち早く実装していたrootlessでのコンテナ実行にDockerが追いつく
2019年7月にリリースされたDocker 19.03でexperimentalとして追加されたrootlessモードが2020年12月にリリースされたDocker 20.10で正式機能としてリリースされたので、特に大儀なくroot権限で動かしていたコンテナを一般ユーザーで動かすように変えました。手順が結構多くて大変でした。
手元でちゃんと使っているDockerがRaspberry Pi 4(RAM8GB)なので、この上で動かしているUbuntu 21.10(aarch64)での動作確認です。
余談としては、以前Podmanで一般ユーザーでのコンテナも使っていましたが、docker-composeを使いたかったので最近はPodmanは触っていません…
今、改めてUbuntuでPodmanを使う(2020年11月)
試したDockerのバージョンはDocker Inc.配布のDocker-CE
最近使っていたDockerはこれといって最新機能を使っているわけではなかったのでUbuntuが配布しているもの(パッケージ名はdocker.io)を使っていましたが、こっちだとrootless版として簡単に使えるようになっているように見えなかったので、削除してDocker-CEのrootless版をインストールする手順になります。
Docker デーモンをルート以外のユーザで実行(Rootless モード) — Docker-docs-ja 19.03 ドキュメント
Dockerイメージ・Dockerコンテナは一旦諦め(ボリュームマウントを除く)
Dockerを使う際にビルドするイメージとコンテナについて、rootで動かすDockerで使っていたイメージとコンテナについては一旦諦めることにしました。
パーミッションが変わることで変な影響が出るのが嫌だったためで、普段からイメージをリポジトリ管理していたり、バックアップからのリストア手順を確立していれば問題ないのかなと思います。
ただ、ボリュームマウントはランタイムとは関係なくファイルシステムをループバックマウントしてるに等しいので、ownerの変更だけで使い続けます。
これまで使っていたroot版dockerの停止・削除
動作中コンテナの停止
# docker container ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b8cd5ce26c84 ghcr.io/linuxserver/calibre-web "/init" 3 weeks ago Up 5 days 0.0.0.0:8083->8083/tcp, :::8083->8083/tcp calibre-web
43feb8312fa5 nextcloud "/entrypoint.sh apac…" 9 months ago Up 5 days 0.0.0.0:8080->80/tcp, :::8080->80/tcp nextcloud_app_1
13781e2cf50e mariadb "docker-entrypoint.s…" 9 months ago Up 5 days 3306/tcp nextcloud_db_1
こんな感じで動作中のコンテナが表示されるので、docker-composeやdockerで片っ端から止めて、動作中コンテナをなくします。
# docker container ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dockerの停止
# systemctl disable --now docker.service
Synchronizing state of docker.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install disable docker
Removed /etc/systemd/system/multi-user.target.wants/docker.service.
Warning: Stopping docker.service, but it can still be activated by:
docker.socket
# systemctl disable --now docker.socket
Removed /etc/systemd/system/sockets.target.wants/docker.socket.
dockerの削除
# apt-get remove docker docker.io containerd runc --purge
rootless版のDocker-CEをインストール
aptでインストール
# curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] http://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
# apt-get install uidmap
# apt-get install docker-ce
# apt-get install docker-ce-rootless-extras
【追記】Raspberry PiでUbuntu 21.10以降の場合は linux-modules-extra-raspi パッケージをインストールする
この記事は元々Ubuntu 21.04用に記載していましたが、Ubuntu 21.10の場合vethで始まるNICがなくなっており、Ubuntu 21.10で追加されたlinux-modules-extra-raspi
パッケージをインストールする必要がありました。
# apt-get install linux-modules-extra-raspi
Raspberry Pi4をUbuntu 21.10に上げてからdockerコンテナが上がらなくなってたことに気付いてエラー見たらvethなんちゃらがなくなってて linux-modules-extra-raspi を入れないといけなくなってた #ubuntu #docker #rpi
— 雅楽斎/garakusai (@garakusai1) October 19, 2021
Build package for raspberry pi 4 aarch64 - snapcraft https://t.co/oOMjYXr7iJ
パッケージインストール以外のセットアップ
rootless版に移行した後が面倒なので、インストールしたdockerを停止します。
# systemctl disable --now docker.service
# systemctl disable --now docker.socket
rootless版dockerを動かす一般ユーザーで以下のコマンドを実行します。
$ dockerd-rootless-setuptool.sh install
[INFO] Creating /home/hogehoge/.config/systemd/user/docker.service
[INFO] starting systemd service docker.service
+ systemctl --user start docker.service
+ sleep 3
+ systemctl --user --no-pager --full status docker.service
● docker.service - Docker Application Container Engine (Rootless)
Loaded: loaded (/home/hogehoge/.config/systemd/user/docker.service; disabled; vendor preset: enabled)
Active: active (running) since Sun 2021-11-14 11:18:26 JST; 3s ago
Docs: https://docs.docker.com/go/rootless/
Main PID: 379478 (rootlesskit)
Tasks: 41
Memory: 51.4M
CPU: 1.163s
CGroup: /user.slice/user-1001.slice/user@1001.service/app.slice/docker.service
├─379478 rootlesskit --net=slirp4netns --mtu=65520 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run --propagation=rslave /usr/bin/dockerd-rootless.sh
├─379489 /proc/self/exe --net=slirp4netns --mtu=65520 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run --propagation=rslave /usr/bin/dockerd-rootless.sh
├─379508 slirp4netns --mtu 65520 -r 3 --disable-host-loopback --enable-sandbox --enable-seccomp 379489 tap0
├─379515 dockerd
├─379536 containerd --config /run/user/1001/docker/containerd/containerd.toml --log-level info
└─379571 [iptables]
11月 14 11:18:29 rpi4 dockerd-rootless.sh[379515]: time="2021-11-14T11:18:29.245684816+09:00" level=info msg="ccResolverWrapper: sending update to cc: {[{unix:///run/user/1001/docker/containerd/containerd.sock <nil> 0 <nil>}] <nil> <nil>}" module=grpc
11月 14 11:18:29 rpi4 dockerd-rootless.sh[379515]: time="2021-11-14T11:18:29.245778762+09:00" level=info msg="ClientConn switching balancer to \"pick_first\"" module=grpc
11月 14 11:18:29 rpi4 dockerd-rootless.sh[379515]: time="2021-11-14T11:18:29.248753408+09:00" level=info msg="parsed scheme: \"unix\"" module=grpc
11月 14 11:18:29 rpi4 dockerd-rootless.sh[379515]: time="2021-11-14T11:18:29.248845522+09:00" level=info msg="scheme \"unix\" not registered, fallback to default scheme" module=grpc
11月 14 11:18:29 rpi4 dockerd-rootless.sh[379515]: time="2021-11-14T11:18:29.248918931+09:00" level=info msg="ccResolverWrapper: sending update to cc: {[{unix:///run/user/1001/docker/containerd/containerd.sock <nil> 0 <nil>}] <nil> <nil>}" module=grpc
11月 14 11:18:29 rpi4 dockerd-rootless.sh[379515]: time="2021-11-14T11:18:29.248970302+09:00" level=info msg="ClientConn switching balancer to \"pick_first\"" module=grpc
11月 14 11:18:29 rpi4 dockerd-rootless.sh[379515]: time="2021-11-14T11:18:29.670007593+09:00" level=warning msg="Unable to find cpu controller"
11月 14 11:18:29 rpi4 dockerd-rootless.sh[379515]: time="2021-11-14T11:18:29.670146523+09:00" level=warning msg="Unable to find io controller"
11月 14 11:18:29 rpi4 dockerd-rootless.sh[379515]: time="2021-11-14T11:18:29.670214524+09:00" level=warning msg="Unable to find cpuset controller"
11月 14 11:18:29 rpi4 dockerd-rootless.sh[379515]: time="2021-11-14T11:18:29.671131046+09:00" level=info msg="Loading containers: start."
+ DOCKER_HOST=unix:///run/user/1001/docker.sock /usr/bin/docker version
Client: Docker Engine - Community
Version: 20.10.10
API version: 1.41
Go version: go1.16.9
Git commit: b485636
Built: Mon Oct 25 07:42:23 2021
OS/Arch: linux/arm64
Context: default
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 20.10.10
API version: 1.41 (minimum version 1.12)
Go version: go1.16.9
Git commit: e2f740d
Built: Mon Oct 25 07:40:56 2021
OS/Arch: linux/arm64
Experimental: false
containerd:
Version: 1.4.11
GitCommit: 5b46e404f6b9f661a205e28d59c982d3634148f8
runc:
Version: 1.0.2
GitCommit: v1.0.2-0-g52b36a2
docker-init:
Version: 0.19.0
GitCommit: de40ad0
+ systemctl --user enable docker.service
Created symlink /home/hogehoge/.config/systemd/user/default.target.wants/docker.service → /home/hogehoge/.config/systemd/user/docker.service.
[INFO] Installed docker.service successfully.
[INFO] To control docker.service, run: `systemctl --user (start|stop|restart) docker.service`
[INFO] To run docker.service on system startup, run: `sudo loginctl enable-linger hogehoge`
[INFO] Creating CLI context "rootless"
Successfully created context "rootless"
[INFO] Make sure the following environment variables are set (or add them to ~/.bashrc):
export PATH=/usr/bin:$PATH
export DOCKER_HOST=unix:///run/user/1001/docker.sock
で、後々最後の行の環境変数DOCKER_HOST
を手動で設定する必要があります。そういう設定をするのがインストールコマンドの役割だと思うんですが。
起動してみる
$ docker info
Client:
Context: default
Debug Mode: false
Plugins:
app: Docker App (Docker Inc., v0.9.1-beta3)
buildx: Build with BuildKit (Docker Inc., v0.6.3-docker)
Server:
ERROR: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
errors pretty printing info
実行できるはずの一般ユーザーで動作しているDocker daemonに接続できないというエラーが出ます。
環境変数DOCKER_HOSTは”unix://$XDG_RUNTIME_DIR/docker.sock”らしいので、dockerコマンドを実行する一般ユーザーでdockerコマンド実行前に設定する必要がありますが、dockerコマンドとdocker-composeコマンド専用の環境変数を設定するのも癪なので、エイリアスを作るのに~/.bash_aliases
に以下の内容を記載します(ない場合はファイルを作成します)
alias docker='DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock docker'
alias docker-compose='DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock docker-compose'
また、OS起動時にdocker-composeのrestart: always
によるコンテナの自動起動でも実現するため、ディレクトリの作成と環境変数定義をします。
$ mkdir ~/.config/environment.d
$ vi ~/.config/environment.d/rootless-docker.conf
~/.config/environment.d/rootless-docker.conf
は以下の内容で作成します。こうすることで、systemdのユーザーのユニットファイルの実行時に定義した環境変数が適用されます。
DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock
$HOME ディレクトリが存在するユーザーの場合、~/.config/environment.d/ ディレクトリに NAME=VAL という形式で環境変数を記述した .conf ファイルを作成する。ユーザーのユニットファイルにのみ影響します。詳しくは environment.d(5) を見てください。
bashでログインし直してもう一度実行します。
$ docker info
Client:
Context: default
Debug Mode: false
Plugins:
app: Docker App (Docker Inc., v0.9.1-beta3)
buildx: Build with BuildKit (Docker Inc., v0.6.3-docker)
Server:
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 20.10.10
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Native Overlay Diff: false
userxattr: true
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 logentries splunk syslog
Swarm: inactive
Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 5b46e404f6b9f661a205e28d59c982d3634148f8
runc version: v1.0.2-0-g52b36a2
init version: de40ad0
Security Options:
seccomp
Profile: default
rootless
cgroupns
Kernel Version: 5.13.0-1009-raspi
Operating System: Ubuntu 21.10
OSType: linux
Architecture: aarch64
CPUs: 4
Total Memory: 7.626GiB
Name: rpi4
ID: EZR5:44EP:CKMV:GEMI:NYWH:SG6Y:7CSF:BHUS:NCOW:SJWV:TCQY:YPJZ
Docker Root Dir: /home/hogehoge/.local/share/docker
Debug Mode: false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false
WARNING: No cpu cfs quota support
WARNING: No cpu cfs period support
WARNING: No cpu shares support
WARNING: No cpuset support
WARNING: No io.weight support
WARNING: No io.weight (per device) support
WARNING: No io.max (rbps) support
WARNING: No io.max (wbps) support
WARNING: No io.max (riops) support
WARNING: No io.max (wiops) support
WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled
hello-worldコンテナを実行
$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
93288797bd35: Pull complete
Digest: sha256:cc15c5b292d8525effc0f89cb299f1804f3a725c8d05e158653a563f15e4f685
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(arm64v8)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
一般ユーザーでdockerコンテナを実行できることが確認できました。
【追記】ユーザーがログインしていない状態でもdockerコンテナを実行できるようにloginctlで実行ユーザーをlinger指定する
systemdを--user
で実行する場合、誰かがそのユーザーでsshなりGUIでログインしないと実行されません。1
今回はrootless docker実行ユーザーであるhogehogeユーザーをlinger指定します。
# loginctl enable-linger hogehoge
イメージ・コンテナの格納場所をUSB接続のHDDに変更する
Raspberry Pi 4で運用しているDockerはそのまま使うとMicroSDの容量を食う上に寿命も物凄い速さで縮むので、Dockerイメージのような大容量データはUSB接続のHDDに格納していましたので、同じ様にrootless接続のDockerでもUSB接続のHDDを使用するようにします。
NextcloudをRaspberry Pi 4にセットアップ(docker-composeで運用)、WebDAVでの動作確認も。
具体的な変更箇所は、OS起動時にHDDのマウントを待ってからユーザー権限のdocker daemonが起動するようにすることと、格納場所としてHDDを指定することの2つです。
まず、格納場所のディレクトリを作成してownerとgroupを変更します。
# mkdir /mnt/usbhdd1/var/docker-image-rootless
# chown hogehoge:hogehoge docker-image-rootless/
ユーザーデーモンのsystemdの設定ファイルは~/.config/systemd/user/docker.service
なので、以下のように変更します。
【追記】Docker23にて-g
オプションが廃止されたため、下記変更内容を--data-root
オプションに変更しています。
Dockerを23にアップグレードしたら-g(–graph)オプションが廃止されてdockerdが起動できなくなっていた
--- /home/hogehoge/.config/systemd/user/docker.service.org 2021-11-14 13:31:04.376227308 +0900
+++ /home/hogehoge/.config/systemd/user/docker.service 2021-11-14 13:35:47.598313568 +0900
@@ -1,10 +1,11 @@
[Unit]
Description=Docker Application Container Engine (Rootless)
Documentation=https://docs.docker.com/go/rootless/
+After=mnt-usbhdd1.automount
[Service]
Environment=PATH=/usr/bin:/sbin:/usr/sbin:/home/hogehoge/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
-ExecStart=/usr/bin/dockerd-rootless.sh
+ExecStart=/usr/bin/dockerd-rootless.sh --data-root /mnt/usbhdd1/var/docker-image-rootless
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
設定ファイルの変更を反映します。
$ systemctl --user daemon-reload
$ systemctl --user restart docker
変更が反映された事を確認します。
$ systemctl cat --user docker
もう一回hello-worldコンテナを実行すると、格納場所にはさっきダウンロードしたイメージがないので、再度イメージをダウンロードします。
$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
93288797bd35: Pull complete
Digest: sha256:cc15c5b292d8525effc0f89cb299f1804f3a725c8d05e158653a563f15e4f685
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(arm64v8)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
ボリュームマウントをしていたDockerコンテナを移行してみる
旧来のroot版Dockerで動かしていたコンテナ(ボリュームマウントを使っていたもの)にCalibre Webがあるので、これを試しに移行することにします。
電子書籍ライブラリとしてCalibre WebをRaspberry Pi 4でDockerで運用する
docker-compose.yaml
の上げ下げだけで起動・停止ができているので、2箇所のボリュームマウント
- /mnt/usbhdd1/var/docker-calibre-web-config:/config
- /mnt/usbhdd1/var/docker-calibre-web-library:/books
について、動作を比較してみます。
一旦、docker-calibre-web-configとdocker-calibre-web-libraryに相当するディレクトリdocker-calibre-web-config-rootlessとdocker-calibre-web-library-rootlessを作成して、docker-compose.yaml
の記述をこの2つに変更した状態でdocker-compoose up -d
、docker-compose down
してみた結果、configの方はファイルが生成されたので見てみると…
# ls -l docker-calibre-web-config docker-calibre-web-config-rootless
docker-calibre-web-config:
合計 220
-rw-r--r-- 1 ubuntu ubuntu 143360 10月 19 20:20 app.db
-rw-r--r-- 1 ubuntu ubuntu 43196 11月 14 10:29 calibre-web.log
-rw-r--r-- 1 ubuntu ubuntu 3 6月 18 22:51 client_secrets.json
-rw-r--r-- 1 ubuntu ubuntu 32768 6月 18 22:52 gdrive.db
docker-calibre-web-config-rootless:
合計 156
-rw-r--r-- 1 166535 166535 118784 11月 14 17:25 app.db
-rw-r--r-- 1 166535 166535 1188 11月 14 17:25 calibre-web.log
-rw-r--r-- 1 166535 166535 3 11月 14 17:22 client_secrets.json
drwxr-xr-x 1 hogehoge hogehoge 0 11月 14 17:22 custom-cont-init.d
drwxr-xr-x 1 hogehoge hogehoge 0 11月 14 17:22 custom-services.d
-rw-r--r-- 1 166535 166535 32768 11月 14 17:24 gdrive.db
rootlessの方のowner/groupは166535を使うようです。custom-cont-init.d
とcustom-services.d
という中身が空でownerが作業ユーザーになっているディレクトリが気になりますが、そこは無視して以前使っていた方のowner/groupを166535に変更します。
# chown -R 166535:166535 docker-calibre-web-config docker-calibre-web-library
# ls -l docker-calibre-web-config
合計 220
-rw-r--r-- 1 166535 166535 143360 10月 19 20:20 app.db
-rw-r--r-- 1 166535 166535 43196 11月 14 10:29 calibre-web.log
-rw-r--r-- 1 166535 166535 3 6月 18 22:51 client_secrets.json
-rw-r--r-- 1 166535 166535 32768 6月 18 22:52 gdrive.db
docker-compose.yaml
ファイルの内容を元に戻してdocker-compose up -d
で起動します。問題なく起動することを確認したらdocker-compose down
で終了します。ボリュームマウントがどうなっているか確認すると…
# ls -l docker-calibre-web-config
合計 232
-rw-r--r-- 1 166535 166535 155648 11月 14 17:47 app.db
-rw-r--r-- 1 166535 166535 44062 11月 14 17:53 calibre-web.log
-rw-r--r-- 1 166535 166535 3 6月 18 22:51 client_secrets.json
drwxr-xr-x 1 hogehoge hogehoge 0 11月 14 17:46 custom-cont-init.d
drwxr-xr-x 1 hogehoge hogehoge 0 11月 14 17:46 custom-services.d
-rw-r--r-- 1 166535 166535 32768 6月 18 22:52 gdrive.db
custom-cont-init.d
とcustom-services.d
がやっぱり作られているのが気になりますが、動作は問題ないのでこのままrootless版で使います。
スポンサーリンク
- これrootless dockerのバグなんじゃないかと思いこんでました…恥ずかしい [return]
comments powered by Disqus