32
28

More than 3 years have passed since last update.

Docker の Rootlessモードを試してみた

Posted at

前書き

ユーザが、Dockerを使用する際に、/var/run/docker.sock へのアクセス権限が問題になることがありました。

$ sudo ls -l /var/run/docker.sock
srw-rw---- 1 root docker 0 12月 15 19:07 /var/run/docker.sock

対処方法として、sudoを使う方法やユーザをdocker グループに入れる方法がありました。しかし、いずれもひと手間が面倒であったり、セキュリティ面に問題ありで、良い方法ではありませんでした。

1つの解決策として、Docker 19.03から下記のRootlessモードが行えるようになりました。

Docker 19.03新機能 (root権限不要化、GPU対応強化、CLIプラグイン…)

簡単に説明すると、各ユーザ用にDockerの環境を作成します。そのためDockerを使用するユーザ毎に、RootlessモードのDockerのインストールが必要です。

RootlessモードのDockerを実際にインストールした時に気が付いたことを書いています。
以下では、「Rootless Docker」と記述しています。

試した環境

  • CentOS Linux release 8.0.1905 (Core)

※CentOSは、「最小限のインストール」でインストールした直後の状態です。

この記事の中でインストールするRootless Dockerのバージョン

  • Client: Docker Engine - Community master-dockerproject-2019-12-11
  • Server: Docker Engine - Community Engine master-dockerproject-2019-12-11

前準備

テスト用にアカウントを2つ作成しています。

$ sudo useradd user01
$ sudo useradd user02
$ sudo passwd user01
$ sudo passwd user02

Rootless Dockerのインストール手順

インストールは、下記のコマンドで完了します。
ユーザ権限で実行できます。

$ curl -fsSL https://get.docker.com/rootless | sh
$ echo 'export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock' >> ~/.bash_profile
$ source ~/.bash_profile
$ docker container run hello-world
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.
    (amd64)
 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/

「Hello from Docker!」が表示されたら成功です。
次に、OSを再起動したとき自動起動するようにします。

$ vi .config/systemd/user/docker.service

docker.serviceファイルの最後の行を変更します。
multi-user.target のままだと、自動起動しなかったです。

[Install]
WantedBy=multi-user.target

    ↓

[Install]
WantedBy=default.target

自動起動の設定を続けます。

$ systemctl --user daemon-reload
$ systemctl --user enable docker
Created symlink /home/user01/.config/systemd/user/multi-user.target.wants/docker.service → /home/user01/.config/systemd/user/docker.service.
$ sudo loginctl enable-linger user01

これで、OS再起動時にRootless Dockerが起動するようになります。

インストール後の確認

ディレクトリ・ファイルを確認

インストールを完了すると、以下のディレクトリやファイルが作成されています。

~/.config
~/.local
~/bin
/var/run/user/1000/docker
/var/run/user/1000/docker.pid
/var/run/user/1000/docker.sock
/var/run/user/1000/runc

※1000の部分は、UIDです。環境によって変わります。
※/var/run/user/1000/に追加されたディレクトリやファイルは、OS再起動時に消えますが、rootless dockerd が起動すると作成されます。

パスの確認

homeディレクトリ下にインストールされています。

$ which docker
~/bin/docker

バージョンの確認

Versionの表記が少し気になりますが、Engine Versionも表示されています。
通常のDockerだと、Engine Versionは「dial unix /var/run/docker.sock: connect: permission denied」となって表示されません。

$ docker version
Client: Docker Engine - Community
 Version:           master-dockerproject-2019-12-11
 API version:       1.41
 Go version:        go1.12.12
 Git commit:        08eaead2
 Built:             Wed Dec 11 23:52:32 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          master-dockerproject-2019-12-11
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.13.4
  Git commit:       1347481
  Built:            Wed Dec 11 23:58:15 2019
  OS/Arch:          linux/amd64
  Experimental:     true
 containerd:
  Version:          v1.3.2
  GitCommit:        ff48f57fc83a8c44cf4ad5d672424a98ba37ded6
 runc:
  Version:          1.0.0-rc9
  GitCommit:        d736ef14f0288d6993a1845745d6756cfc9ddd5a
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

プロセスを確認

4つのプロセスが動作しています。
全てのプロセスがユーザ権限で動作しています。

$ ps xo user,cmd | grep docker
user01   rootlesskit --net=vpnkit --mtu=1500 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run /home/user01/bin/dockerd-rootless.sh --experimental --storage-driver=vfs
user01   /proc/self/exe --net=vpnkit --mtu=1500 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run /home/user01/bin/dockerd-rootless.sh --experimental --storage-driver=vfs
user01   dockerd --experimental --storage-driver=vfs
user01   containerd --config /run/user/1000/docker/containerd/containerd.toml --log-level info

ユーザ毎の違いを比べてみる

user02でRootless Dockerをインストールする前にバージョン確認してみました。
当然、見つかりません。

[user02@localhost ~]$ docker version
-bash: docker: コマンドが見つかりません

user02でも、同様にRootless Dockerをインストールして、確認を続けます。

パスの確認

各ユーザのhomeの下を参照しているので、別ファイルです。

[user01@localhost ~]$ which docker
~/bin/docker

[user02@localhost ~]$ which docker
~/bin/docker

i-node番号を確認すると、別ファイルだとわかります。

[user01@localhost ~]$ ls -i ~/bin/docker
33554563 /home/user01/bin/docker

[user02@localhost ~]$ ls -i ~/bin/docker
33554616 /home/user02/bin/docker

バージョンの確認

実行ファイルは別々でも、同じバージョンなので違いがわからないです。

$ docker version
Client: Docker Engine - Community
 Version:           master-dockerproject-2019-12-11
 API version:       1.41
 Go version:        go1.12.12
 Git commit:        08eaead2
 Built:             Wed Dec 11 23:52:32 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          master-dockerproject-2019-12-11
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.13.4
  Git commit:       1347481
  Built:            Wed Dec 11 23:58:15 2019
  OS/Arch:          linux/amd64
  Experimental:     true
 containerd:
  Version:          v1.3.2
  GitCommit:        ff48f57fc83a8c44cf4ad5d672424a98ba37ded6
 runc:
  Version:          1.0.0-rc9
  GitCommit:        d736ef14f0288d6993a1845745d6756cfc9ddd5a
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

[user02@localhost ~]$ docker version
Client: Docker Engine - Community
 Version:           master-dockerproject-2019-12-11
 API version:       1.41
 Go version:        go1.12.12
 Git commit:        08eaead2
 Built:             Wed Dec 11 23:52:32 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          master-dockerproject-2019-12-11
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.13.4
  Git commit:       1347481
  Built:            Wed Dec 11 23:58:15 2019
  OS/Arch:          linux/amd64
  Experimental:     true
 containerd:
  Version:          v1.3.2
  GitCommit:        ff48f57fc83a8c44cf4ad5d672424a98ba37ded6
 runc:
  Version:          1.0.0-rc9
  GitCommit:        d736ef14f0288d6993a1845745d6756cfc9ddd5a
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

プロセスを確認

4つのプロセスで、PIDが違っています。

[user01@localhost ~]$ ps xo pid,user,cmd | grep docker
 1225 user01   rootlesskit --net=vpnkit --mtu=1500 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run /home/user01/bin/dockerd-rootless.sh --experimental --storage-driver=vfs
 1233 user01   /proc/self/exe --net=vpnkit --mtu=1500 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run /home/user01/bin/dockerd-rootless.sh --experimental --storage-driver=vfs
 1272 user01   dockerd --experimental --storage-driver=vfs
 2866 user01   containerd --config /run/user/1000/docker/containerd/containerd.toml --log-level info

[user02@localhost ~]$ ps xo pid,user,cmd | grep docker
 8013 user02   rootlesskit --net=vpnkit --mtu=1500 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run /home/user02/bin/dockerd-rootless.sh --experimental --storage-driver=vfs
 8022 user02   /proc/self/exe --net=vpnkit --mtu=1500 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run /home/user02/bin/dockerd-rootless.sh --experimental --storage-driver=vfs
 8074 user02   dockerd --experimental --storage-driver=vfs
 8091 user02   containerd --config /run/user/1001/docker/containerd/containerd.toml --log-level info

/ver/run の下のファイルの確認

そもそもパスが違うので別物です。

[user01@localhost ~]$ ls -l /var/run/user/1000
合計 4
srw-rw-rw-. 1 user01 user01   0 12月 22 21:54 bus
drwx-----T. 7 user01 user01 180 12月 22 21:58 docker
-rw-r--r-T. 1 user01 user01   4 12月 22 21:58 docker.pid
srw-rw---T. 1 user01 user01   0 12月 22 21:58 docker.sock
drwx-----T. 2 user01 user01  40 12月 22 21:58 runc
drwxr-xr-x. 2 user01 user01  80 12月 22 22:00 systemd

[user02@localhost ~]$ ls -l /var/run/user/1001
合計 4
srw-rw-rw-. 1 user02 user02   0 12月 22 22:01 bus
drwx-----T. 5 user02 user02 140 12月 22 22:05 docker
-rw-r--r-T. 1 user02 user02   4 12月 22 22:05 docker.pid
srw-rw---T. 1 user02 user02   0 12月 22 22:05 docker.sock
drwx-----T. 2 user02 user02  40 12月 22 22:05 runc
drwxr-xr-x. 2 user02 user02  80 12月 22 22:05 systemd

Dockerコマンドでの違い

コンテナの確認

hello-worldコンテナを起動したので、停止状態のコンテナが残っています。
CONTAINER ID が違っており別々のコンテナだとわかります。

[user01@localhost ~]$ docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
a9fa819c358e        hello-world         "/hello"            9 minutes ago       Exited (0) 9 minutes ago                       crazy_lederberg

[user02@localhost ~]$ docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
236dbc03fa53        hello-world         "/hello"            13 seconds ago      Exited (0) 12 seconds ago                       heuristic_hypatia

イメージの確認

IMAGE ID が違がって・・・ないです。同じです。
※先に結論だけ書いておきますが、IMAGE IDは同じですが、実体は別物です。

[user01@localhost ~]$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              fce289e99eb9        11 months ago       1.84kB

[user02@localhost ~]$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              fce289e99eb9        11 months ago       1.84kB

user01で、nginx イメージをpullします。

[user01@localhost ~]$ docker image pull nginx
Using default tag: latest
latest: Pulling from library/nginx
000eee12ec04: Pull complete
eb22865337de: Pull complete
bee5d581ef8b: Pull complete
Digest: sha256:50cf965a6e08ec5784009d0fccb380fc479826b6e0e65684d9879170a9df8566
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

ダウンロードが終わるとイメージ一覧に追加されています。

[user01@localhost ~]$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              231d40e811cd        4 weeks ago         126MB
hello-world         latest              fce289e99eb9        11 months ago       1.84kB

user02は、ダウンロードしていないので、nginxイメージを確認できません。

[user02@localhost ~]$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              fce289e99eb9        11 months ago       1.84kB

user02でnginxコンテナを起動すると、「Unable to find image」と表示されダウンロードが開始しました。

[user02@localhost ~]$ docker container run nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
000eee12ec04: Pull complete
eb22865337de: Pull complete
bee5d581ef8b: Pull complete
Digest: sha256:50cf965a6e08ec5784009d0fccb380fc479826b6e0e65684d9879170a9df8566
Status: Downloaded newer image for nginx:latest
^C                        <-- nginxコンテナを停止
[user02@localhost ~]$

nginxイメージのIMAGE IDも、user01、user02ともに同じになっています。

[user01@localhost ~]$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              231d40e811cd        4 weeks ago         126MB
hello-world         latest              fce289e99eb9        11 months ago       1.84kB

[user02@localhost ~]$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              231d40e811cd        4 weeks ago         126MB
hello-world         latest              fce289e99eb9        11 months ago       1.84kB

イメージは、各ユーザでダウンロードしないとダメなようです。
一見、IMAGE IDが同じなので、同じイメージを見ているように勘違いしそうです。

イメージの実体を確認

hello-worldイメージを少し追ってみました。
jsonファイルの処理のために、pythonをインストールしています。

$ sudo dnf install python3

管理しているファイルを確認しました。

[user01@localhost ~]$ cat /home/user01/.local/share/docker/image/vfs/repositories.json | python3 -m json.tool
{
    "Repositories": {
        "hello-world": {
            "hello-world:latest": "sha256:fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e",
            "hello-world@sha256:4fe721ccc2e8dc7362278a29dc660d833570ec2682f4e4194f4ee23e415e1064": "sha256:fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e"
        },
        "nginx": {
            "nginx:latest": "sha256:231d40e811cd970168fb0c4770f2161aa30b9ba6fe8e68527504df69643aa145",
            "nginx@sha256:50cf965a6e08ec5784009d0fccb380fc479826b6e0e65684d9879170a9df8566": "sha256:231d40e811cd970168fb0c4770f2161aa30b9ba6fe8e68527504df69643aa145"
        }
    }
}

このファイルは各ユーザのhomeディレクトリ下にあります。
パスが違うので当然、別物です。
また下記のように、i-node番号も違っています。(桁が違いすぎる)

[user01@localhost ~]$ ls -li /home/user01/.local/share/docker/image/vfs/repositories.json
152 -rw-------. 1 user01 user01 542 12月 22 22:12 /home/user01/.local/share/docker/image/vfs/repositories.json

[user02@localhost ~]$ ls -li /home/user02/.local/share/docker/image/vfs/repositories.json
100663444 -rw-------. 1 user02 user02 542 12月 22 22:21 /home/user02/.local/share/docker/image/vfs/repositories.json

UUID(で合ってる?)をたどっていくと最終的に、helloコマンドにたどり着きます。

[user01@localhost ~]$ ls -li /home/user01/.local/share/docker/vfs/dir/e1b5ab5b419c6229106017654150711e2717ae81f3c8002bedb936f0f2786b4b/hello
33554585 -rwxrwxr-x. 1 user01 user01 1840  1月  1  2019 /home/user01/.local/share/docker/vfs/dir/e1b5ab5b419c6229106017654150711e2717ae81f3c8002bedb936f0f2786b4b/hello

同じように、user02でも確認します。
「dir」の下のディレクトリ名がuser01と違っています。

[user02@localhost ~]$ ls -li /home/user02/.local/share/docker/vfs/dir/f56bbc69cac68b78ef386f01643acbdaa89929e4f8f57bd2e8c8039e5dfa17c6/hello
67215817 -rwxrwxr-x. 1 user02 user02 1840  1月  1  2019 /home/user02/.local/share/docker/vfs/dir/f56bbc69cac68b78ef386f01643acbdaa89929e4f8f57bd2e8c8039e5dfa17c6/hello

helloコマンドのi-node番号が違っています。
dockerコマンド上は、同じIDに見えますが、イメージは別物だと言えます。

イメージの削除

user01、user02ともに、停止コンテナを削除した後、user02でイメージの削除を行います。

[user02@localhost ~]$ docker image rm hello-world
Untagged: hello-world:latest
Untagged: hello-world@sha256:4fe721ccc2e8dc7362278a29dc660d833570ec2682f4e4194f4ee23e415e1064
Deleted: sha256:fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e
Deleted: sha256:af0b15c8625bb1938f1d7b17081031f649fd14e6b233688eea3c5483994a66a3
[user02@localhost ~]$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              231d40e811cd        3 weeks ago         126MB

user02では、hello-worldイメージが消えています。
user01では、残っています。

[user01@localhost ~]$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              231d40e811cd        3 weeks ago         126MB
hello-world         latest              fce289e99eb9        11 months ago       1.84kB

docker-compose の場合

docker-commposeを実行したときの動作を確認してみました。

$ sudo pip3 install docker-compose
$ docker-compose version
docker-compose version 1.25.0, build b42d419
docker-py version: 4.1.0
CPython version: 3.6.8
OpenSSL version: OpenSSL 1.1.1 FIPS  11 Sep 2018

簡単なdocker-compose.ymlを作成します。

$ vi docker-compose.yml
version: '3'
services:

  wordpress:
    image: wordpress
    container_name: wordpress
    restart: always
    ports:
      - 80:80
    environment:
      WORDPRESS_DB_PASSWORD: wp-password

  mysql:
    image: mysql:5.7
    container_name: mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: mysql-password

実行します。
wordpressとmysqlのコンテナのダウンロードが始まるため、時間がかかります。

$ docker-compose up -d
Starting wordpress ... done
Starting mysql     ... done
$ docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                 NAMES
32a9bd917995        mysql:5.7           "docker-entrypoint.s…"   2 minutes ago       Up 33 seconds       3306/tcp, 33060/tcp   mysql
cfdd93b5f5ff        wordpress           "docker-entrypoint.s…"   2 minutes ago       Up 33 seconds       0.0.0.0:80->80/tcp    wordpress

docker-composeからの起動もできました。
確認できたので、終了させておきます。

$ docker-compose down
Stopping mysql     ... done
Stopping wordpress ... done
Removing mysql     ... done
Removing wordpress ... done
Removing network user01_default

作業中に解決したエラー等

バージョン確認時のメッセージ

バージョン確認時等に、下記のようなメッセージが表示される。

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

環境変数の「DOCKER_HOST」が正しく設定されているか確認してください。

systemctlのメッセージ

systemctl --user status docker コマンドを実行した時に下記のようなエラーが出る。

level=warning msg="Running modprobe bridge br_netfilter failed with message: modprobe: ERROR: could not insert 'br_netfilter': Operation not permitted\ninsmod /lib/modules/4.18.0-80.el8.x86_64/kernel/net/bridge/br_netfilter.ko.xz \n, error: exit status 1"

原因は、br_netfilterモジュールがロードされていないこと。
なので、OS起動時にロードするようにします。

$ lsmod | grep br_netfilter
br_netfilter           24576  0
bridge                188416  1 br_netfilter

$ echo "br_netfilter" > /etc/modules-load.d/br_netfilter.conf

最後に

ユーザごとに別の環境でDockerを使えるようになります。
当然、本来のDocker(/usr/bin/docker)と、別なものになります。
イメージが別になるなど注意が必要そうです。
気になるところはありますが、root権限が不要なるメリットがあるのでしばらく使ってみようと思います。

32
28
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
28