有馬総一郎のブログ

(彼氏の事情)

2024年02月08日 18:11:30 JST - 8 minute read - Linux

出来るだけ安全に最新のDockerをインストールして、グループにユーザを追加せずにルートレスで実行する

dockerをPop!_OSにインストールしたことはなかったので、改めて調べてインストールしてみた。別段、Pop!_OSだから、という変わったことは無かったが、今まで気付かなったところで色々知ったことがあったのでまとめておく。とっととインストールしたい方は他のサイトの記事の方が、簡潔で良いと思う。

普通にリポジトリから最新を取得してインストールの仕方

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt update
sudo apt install docker-ce
sudo usermod -aG docker ${USER}
## 再起動(ログアウト)か
docker run hello-world

これで最新1のがインストールされユーザで使えるようにはなる。しかし、Dockerのリポジトリを追加2したことでW: https://download.docker.com/linux/ubuntu/dists/jammy/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.と警告が表示されるようになったので、気になって調べてみた。

apt-keyは非推奨

警告を調べると上の二つのサイトが参考になった。技評のサイトでも2021年には掲載してくれてたのか…普段はついつい読み流しちゃうんだよね。私なりに解釈するとapt-key(系コマンド)は、 /etc/apt/trusted.gpg にどんなリポジトリ鍵も、ごちゃまぜにして追加してしまうので危険ということらしい。

じゃあ、別の鍵として保存する。この場合、シンプルにcurl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo tee /etc/apt/trusted.gpg.d/docker-keyring.ascとすればいい。警告も出なくなる。

ただ、これだとASCII Armor(テキスト)形式のまま保存されてしまうし、 /etc/apt/trusted.gpg.d 配下というのが安全でないらしい

DebianRepository/UseThirdParty - Debian Wikiにはこうある。

The certificate MUST be downloaded over a secure mechanism like HTTPS to a location only writable by root. The certificate MUST NOT be placed in /etc/apt/trusted.gpg.d or loaded by apt-key add.

正直、 /usr/share/keyrings/etc/apt/keyrings がOKで /etc/apt/trusted.gpg.d/ 配下が駄目な理由が良く分からないが3、変えろというなら変えておこう。

  1. gpg --no-default-keyring --keyring /tmp/temp-keyring.gpg --import "ダウンロードしたリポジトリ鍵ファイル名"とインポート
  2. gpg --no-default-keyring --keyring /tmp/temp-keyring.gpg --export --output "リポジトリ名".gpgとエスクポート
  3. エクスポートしたリポジトリ鍵をコピー

技評のサイトには、上記のような方法が紹介されていた4が、ASCII Armor形式のGPG鍵をバイナリ形式に変換するためのオプション--dearmorを付ければ一発だ。

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg -o /usr/share/keyrings/docker-keyring.gpg --dearmor

簡易的にバイナリになっているか確認。

$ file --mime docker.asc
docker.asc: application/pgp-keys; charset=us-ascii
$ file --mime /usr/share/keyrings/docker-keyring.gpg
/usr/share/keyrings/docker-keyring.gpg: application/octet-stream; charset=binary

このままsudo add-apt-repository "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"すればイケる!と思ったが

[Unable to install on Ubuntu. Got error Unable to handle repository shortcut 'deb [arch=amd64 signed-by=/etc/apt/keyrings/osquery.asc] https://pkg.osquery.io/deb deb main' · Issue #8105 · osquery/osquery · GitHub](https://github.com/osquery/osquery/issues/8105)

とエラーになって出来ない。 Unable to install on Ubuntu. Got error Unable to handle repository shortcut ‘deb [arch=amd64 signed-by=/etc/apt/keyrings/osquery.asc] https://pkg.osquery.io/deb deb main’ · Issue #8105 · osquery/osquery · GitHubにもあるが、signed-by付けては多分できないんだろう。

echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.listとやる。その後のsudo apt updateは成功。

リポジトリ鍵の削除

ちなみにリポジトリ鍵の削除は apt-key addで登録した鍵を削除する方法 | VPS Lifeにもあるとおり

  1. apt-key listでリストを表示
  2. 削除したい鍵の40文字の英数字の末尾8文字を確認。スペースは除く。
  3. sudo apt-key del 末尾8文字で鍵削除
$ apt-key list
Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)).
/etc/apt/trusted.gpg
--------------------
pub   rsa4096 2017-06-22 [SC]
      63C4 6DF0 140D 7389 6142  9F4E 204D D8AE C33A 7AFF
uid           [  不明  ] Pop OS (ISO Signing Key) <info@system76.com>
sub   rsa4096 2017-06-22 [E]

pub   rsa4096 2017-02-22 [SCEA]
      9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid           [  不明  ] Docker Release (CE deb) <docker@docker.com>
sub   rsa4096 2017-02-22 [S]

・・・省略・・・
$ sudo apt-key del 0EBFCD88

DockerにはRootless modeというのがある

そして、dockerを一般ユーザで実行する方法だが、 【Rootless Docker】 Dockerを安全に一般ユーザで実行する | ぺんぎんやを見ると、

Dockerの実行許可を与えるユーザにグループに追加する方法が一般的でした.ただ,セキュリティ面に問題があったため,あまり推奨される方法ではありませんでした.

ということを知る。え…そうなの。とりあえずユーザをdockerグループから削除する。

$ sudo gpasswd -d $USER docker
ユーザ arimasou16 をグループ docker から削除
$ id $USER
uid=1000(arimasou16) gid=1000(arimasou16) groups=1000(arimasou16),4(adm),27(sudo),123(lpadmin),136(vboxusers)

公式の Run the Docker daemon as a non-root user (Rootless mode) | Docker Docsに細かく書いてあるので、その通りにやっていく。

/etc/subuid/etc/subgid がない

まず前提条件をクリアするためにsudo apt install uidmapをして、次にgrep ^$(whoami): /etc/subuidする。

$ grep ^$(whoami): /etc/subuid
grep: /etc/subuid: そのようなファイルやディレクトリはありません

なぬ。

podman/docs/tutorials/rootless_tutorial.md at main · containers/podman · GitHubを見る。usermod --add-subuids --add-subgidを使っても駄目。

$ sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 arimasou16
usermod: /etc/subuid does not exist, you cannot use the flags -v or -V
$ usermod --help 
  -v, --add-subuids FIRST-LAST  add range of subordinate uids
  -V, --del-subuids FIRST-LAST  remove range of subordinate uids

-v or -Vって、何かと思ったら--add-subuids--del-subuidsの省略系か。

Podman - ArchWikiSet subuid and subgid に細かい記述がある。

Users created prior to shadow 4.11.1-3 do not have entries in /etc/subuid and /etc/subgid by default. An entry can be created for them using the usermod(8) command or by manually modifying the files.

更に useradd(8) — Arch manual pagesを見ると

-F, –add-subids-for-system Update /etc/subuid and /etc/subgid even when creating a system account with -r option. -r, –system Create a system account.

System users will be created with no aging information in /etc/shadow, and their numeric identifiers are chosen in the SYS_UID_MIN-SYS_UID_MAX range, defined in /etc/login.defs, instead of UID_MIN-UID_MAX (and their GID counterparts for the creation of groups).

Note that useradd will not create a home directory for such a user, regardless of the default setting in /etc/login.defs (CREATE_HOME). You have to specify the -m options if you want a home directory for a system account to be created.

Note that this option will not update /etc/subuid and /etc/subgid. You have to specify the -F options if you want to update the files for a system account to be created.

とあるが、Pop!_OSのuseraddコマンドだとuseradd: 無効なオプション -- 'F'として使えない。なのでsudo touch /etc/subuid /etc/subgidとファイルを作成してusermodすることにした。

$ sudo touch /etc/subuid /etc/subgid
$ sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 arimasou16
$ grep ^$(whoami): /etc/subuid /etc/subgid
/etc/subuid:arimasou16:100000:65536
/etc/subgid:arimasou16:100000:65536

これで前提条件はクリアなはず。

ルートレス化

ルートレス化の前にsudo systemctl disable --now docker.service docker.socketをしてソケット、サービスを無効化する。そして、dockerd-rootless-setuptool.sh installするも[ERROR] Aborting because rootful Docker (/var/run/docker.sock) is running and accessible. Set --force to ignore.とエラーが。グループ削除や無効化した後に、ログアウト、もしくは再起動した方がいいのかも知れないが、--forceを付けて実行。

$ dockerd-rootless-setuptool.sh --force install
[INFO] Creating /home/arimasou16/.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/arimasou16/.config/systemd/user/docker.service; disabled; vendor preset: enabled)
     Active: active (running) since Thu 2024-02-08 11:13:22 JST; 3s ago
       Docs: https://docs.docker.com/go/rootless/
   Main PID: 22117 (rootlesskit)
      Tasks: 53
     Memory: 59.2M
        CPU: 472ms
     CGroup: /user.slice/user-1000.slice/user@1000.service/app.slice/docker.service
             ├─22117 rootlesskit --state-dir=/run/user/1000/dockerd-rootless --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
             ├─22128 /proc/self/exe --state-dir=/run/user/1000/dockerd-rootless --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
             ├─22146 slirp4netns --mtu 65520 -r 3 --disable-host-loopback --enable-sandbox --enable-seccomp 22128 tap0
             ├─22153 dockerd
             └─22180 containerd --config /run/user/1000/docker/containerd/containerd.toml
・・・省略・・・
Server: Docker Engine - Community
 Engine:
  Version:          25.0.3
  API version:      1.44 (minimum version 1.24)
  Go version:       go1.21.6
  Git commit:       f417435
  Built:            Tue Feb  6 21:13:09 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
 rootlesskit:
  Version:          2.0.1
  ApiVersion:       1.1.1
  NetworkDriver:    slirp4netns
  PortDriver:       builtin
  StateDir:         /run/user/1000/dockerd-rootless
 slirp4netns:
  Version:          1.0.1
  GitCommit:        6a7b16babc95b6a3056b33fb45b74a6f62262dd4
+ systemctl --user enable docker.service
Created symlink /home/arimasou16/.config/systemd/user/default.target.wants/docker.service → /home/arimasou16/.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 arimasou16`

[INFO] Creating CLI context "rootless"
Successfully created context "rootless"
[INFO] Using CLI context "rootless"
Current context is now "rootless"

[INFO] Make sure the following environment variable(s) are set (or add them to ~/.bashrc):
export PATH=/usr/bin:$PATH

[INFO] Some applications may require the following environment variable too:
export DOCKER_HOST=unix:///run/user/1000/docker.sock

上手く行ったようだ。ユーザ権限での起動はログ見るかぎり既に設定ずみっぽいのでexport DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sockをシェル設定ファイル5に追記した。

sudo loginctl enable-linger $(whoami)しろとあるが、どういうコマンドかChatGPTに聞くと

Lingering(lingering session)とは、ユーザーがログアウトした後も、そのユーザーのセッションがシステム上に残り続ける状態を指します。この状態では、ユーザーのプロセスやジョブは停止せずに継続します。通常、ユーザーがログアウトするとそのセッションは終了しますが、linger状態を有効にすると、セッションがログアウト後も残り続けるため、特定の設定やプロセスが維持されます。

loginctl enable-lingerを使用すると、指定したユーザーのlinger状態が有効になり、そのユーザーがログアウトした後もそのセッションが残り続けるようになります。これは、システム管理者が特定のユーザーの環境設定やバックグラウンドプロセスを保持したい場合などに便利です。

とあったので、デスクトップ版での用途だったの実行しなかった。サーバーでの場合は必須だろう。

その後、docker pull ubuntu:22.04実行したが、ちゃんと成功した。

Docker Composeのインストール

後は、通常どおりのやり方で問題ないはず。

Docker Compose のインストール | Docker ドキュメントを参考に実行する。バージョンが v2.4.1 となっていたが、 Releases · docker/composeを見たとき、 v2.24.5 だったので、 v2.24.5 で実行した。

$ DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
$ echo $DOCKER_CONFIG          
/home/arimasou16/.docker
$ mkdir -p $DOCKER_CONFIG/cli-plugins
$ curl -SL https://github.com/docker/compose/releases/download/v2.24.5/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100 58.5M  100 58.5M    0     0  18.7M      0  0:00:03  0:00:03 --:--:-- 31.2M
$ chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
$ docker compose version
Docker Compose version v2.24.5

ふう、思ったより長くなってしまった。普段はコマンドの意味なんてそんな調べたりしないが、今回は警告やらエラーが出たので細かく調べてみた。それまでコピペして実行してただけのコマンドの意味が少し分かった気がする。


  1. 2024-02-08時点。Docker version 25.0.3, build 4debf41がインストールされた。 ↩︎

  2. たまに記事にubuntu jammy stableとコードが固定で書かれているが、ubuntuの後の文字は、今のディストリビューションのコードを入れるので$(lsb_release -cs)とした方がいい。 lsb_release – ディストリビューションのバージョン情報の確認 | Linuxコマンド.NET。 ↩︎

  3. どこもroot 644なのも変わらなかった。あと、リポジトリ鍵はパッケージ(リポジトリ)名にするべきとあるが、とりあえず気にしないことにした。 ↩︎

  4. この方法だと一時的に /tmp/temp-keyring.gpg が残り、何故か /tmp/temp-keyring.gpg~ というチルダ付のファイルまで出来た。そのため、作業後にこの二つを削除する必要がある。 ↩︎

  5. ~/.bashrc~/.zshrc~/.profile シェル、環境に合わせる。 ↩︎