LinuxでDocker使うと、Docker側で生成したファイルがrootになる問題

公開:2020/12/09
更新:2021/01/03
6 min読了の目安(約5500字TECH技術記事

英語読んで書いてあることやっただけ。

状況

  • ホストマシンがLinuxでDockerを使う場合、rootで実行する必要がある
    → いちいち sudo docker-compose とrootで実行する必要あり
    → コレについてはzshでalias張れば解決なのでまぁ、手間ではない

  • コンテナ内で自動生成する場合 (Laravelとかでファイルを生成させる場合とか)
    → 生成されるファイルが root:root になる
    → Read onlyになってローカルから触れないので、いちいち sudo chown する必要が

  • そもそもrootでDockerを実行する = dockerに変なの仕込まれたら終わり
    → セキュリティ面でも非常に良くない

これらを解決したい

Rootlessモード

この問題には userns-remap という解決方法があったが、
Docker v19.03からは rootlessモード というものが用意されたようで、こちらを使ってみようと思う。

この違いとしては、 userns-remap デーモン自体はrootで動いていたのに対し、
Rootlessモードではすべてがroot権限なしで動くようになっている様子。
(一部機能はまだ動かないものもあるらしい)

環境

  • ArchLinux
  • yay (AUR)

インストール

一応、Dockerの公式には乗ってるらしいが、ArchLinuxのユーザリポジトリ(AUR)に方法が載っていたので、
AURで楽しようと思う。

20/12/09 ぐらいの話なので、AURのページから下記の情報がまだ使えるか確認しながらどうぞ。
https://aur.archlinux.org/packages/docker-rootless/

21/01/03 上記見れなくなってた。以下で入りそう。なんか最近このあたりゴタゴタしてるので公式とか見たほうがいいかも

docker-rootlessをAURからインストール

追記 21/01/03
公式を確認すると以下のインストールが推奨されていたので追記

$ sudo pacman -S fuse-overlayfs

上記AURに従ってまず AUR から docker-rootless をいれてやる

$ yay -S docker-rootless

終わったらこの表示が出る。これは先程のAURのコメントの通りなので、これに従ってやっていく

=== Post installation message from docker-rootless ===
This is based on https://docs.docker.com/engine/security/rootless/
To Run the Docker daemon as a non-root user (Rootless mode) for ArchLinux, you need t
o do the following things:

1. configure kernel settings

create '/etc/sysctl.d/99-docker-rootless.conf': 'kernel.unprivileged_userns_clone=1'

and then run: 'sudo sysctl --system'

> see https://docs.docker.com/engine/security/rootless/#distribution-specific-hint for detailed information

2. configure subuid and subgid

and create '/etc/subuid' and '/etc/subgid' with: 'testuser:231072:65536' (for example
, 'testuser' is username)

> see https://docs.docker.com/engine/security/userns-remap/#prerequisites for detailed information

3. start and enable user service: 'systemctl --user status|start|stop docker'

4. finally set docker socket environment variable: 'export DOCKER_HOST=unix://$XDG_RU
NTIME_DIR/docker.sock', you can also add it to '~/.bashrc' or somewhere alike
=========

カーネルの設定

以下を作る

/etc/sysctl.d/99-docker-rootless.conf

kernel.unprivileged_userns_clone=1

subuid, subgid の設定

それぞれ下記内容で生成
ユーザ名には自分のユーザ名を入れる

※注意: subgidの方はgroupのidなのかとおもったら、こちらもuserのidで良い模様。
これでドツボにはまって時間浪費した。ちくしょう。

/etc/subuidと/etc/subgid

ユーザ名:231072:65536

※231072については適当に絶対に被らなさそうな開始idを指定すれば良いので、114514とか適当に
subuid、subgidともに100000から65536個確保、とかでも良さそうだった

ユーザのDocker起動,自動起動有効

# まず状態の確認
$ systemctl --user status docker
# State が running でなければ start
$ systemctl --user start docker
# 自動起動を有効に
$ systemctl --user enable docker

enableした場合、設定が最後まで終わったあと再起動してdockerが起動されているか確認すると良さそう
最後にもっかいstatusして起動できてるか確認しておくとなおよし

systemctlでの起動の際は、root側と --user 側でそれぞれstartしてenableしておく必要あり
rootのdockerが起動していないと、userのdockerだけでは起動がfailedする
あと、起動しない理由としてユーザがdockerグループから抜けていたというのもあったが
そもそもそれをしたくないのでrootless dockerにしたはずなんだが、みたいな話になってきてなんかアレ
https://stackoverflow.com/questions/60490529/docker-rootless-on-ubuntu-overlay2-failed-driver-not-supported
とりあえずコレやってもfailedしてそう

追記: 20/12/09
rootlessモードなdockerをstartするだけでいけた。なんでや。

Docker Host

お使いのshellでPATHを通す
小生は zsh なので .zshrc

export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock

再起動

あとはユーザ権限で docker info ができるかどうか。
できたらおめでとう :tada:

注意

rootless な Docker は、sudo で起動するものとは別にコンテナなどを持つ
つまり同じプロジェクトでもdocker-compose up -dすると新しくbuildが走っちゃうよ、ということである
新幹線でテザリングしてたときにやらかしてコンテナビルド走って慌てて消した
即日通信制限がかかり、その月はひもじい思いをしたので気をつけよう!

追記

dockerのファイル保存先をかえれば、root側のdockerと設定関係のファイルがかち合わないのでは?とおもった

コンテナをbuildしてる最中にこんな感じのが出てくる

Status: Downloaded newer image for php:8-fpm
 ---> edc6bf79d9ba
Step 2/2 : RUN apt update && docker-php-ext-install pdo pdo_mysql
 ---> Running in 5616e0ab9a5a
ERROR: Service 'php' failed to build : /run/containerd/s/60ceecf888f9382eafe6d7308496a508a83e2bd819ef77fb285590aaf9a7985b: mkdir /run/containerd/s: permission denied: unknown

これひょっとしてrootとrootlessのdockerの環境が分けられてないかな?という気がしたので
rootlessなdockerは別なとこを指定してみる

試しにそれぞれのstatusを確認

rootless

$ systemctl --user status docker
● docker.service - Docker Application Container Engine
     Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: >
     Active: inactive (dead)
TriggeredBy: ● docker.socket

root

$ sudo systemctl status docker
● docker.service - Docker Application Container Engine (Rootless)
     Loaded: loaded (/usr/lib/systemd/user/docker.service; disabled; vendor preset:
     Active: inactive (dead)
       Docs: https://docs.docker.com

このそれぞれのdocker.serviceに、起動時の設定などをぶちこんでおける

rootless dockerのdocker.service
こいつのExecStartを変更していく

[Unit]
Description=Docker Application Container Engine (Rootless)
Documentation=https://docs.docker.com

[Service]
Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Environment=DOCKERD_FLAGS="--experimental"
ExecStart=/usr/bin/dockerd-rootless.sh $DOCKERD_FLAGS
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
Type=simple

[Install]
WantedBy=default.target

今回はユーザ向けのdockerのディレクトリを ~/.docker にしてみた

ExecStart=/usr/bin/dockerd-rootless.sh $DOCKERD_FLAGS --data-root /home/<USERの名前>/.docker

参考: https://xvideos.hatenablog.com/entry/move_docker_location