[Docker] Rootless Docker を試してみた

# Rootless Docker とは

> Rootless モード（Rootless mode）は Docker デーモンとコンテナを root 以外のユーザが実行できるようにするもので、デーモンやコンテナ・ランタイムにおける潜在的な脆弱性を回避します。
> [Docker 公式ドキュメント](https://docs.docker.jp/engine/security/rootless.html)

# 今回の環境

- Ubuntu Server 20.04 on VMware ESXi

# いざ挑戦

## まずは事前準備

### uidmap 導入

> ホスト上に newuidmap と newgidmap のインストールが必要です。

とのことなので、インストールしておきます。

```sh
$ sudo apt install -y uidmap
```

これをインストールしていないと Docker をインストールする際に

```sh
# Installing stable version 19.03.12
# Missing system requirements. Please run following commands to
# install the requirements and run this installer again.
# Alternatively iptables checks can be disabled with SKIP_IPTABLES=1

cat <<EOF | sudo sh -x
apt-get install -y uidmap
EOF
```

と言われるので入れ忘れないようにしましょう。（体験談）

### UID/GID 確認

> /etc/subuid と /etc/subgid はユーザに対して、少なくともサブオーディネイト UID/GID を 65,536 含むべきです。

とのことなので確認しておきましょう。

```sh
$ grep ^$(whoami): /etc/subuid
dev:100000:65536
$ grep ^$(whoami): /etc/subgid
dev:100000:65536
```

`65536` が両方に含まれていれば OK です。

## インストール

ワンライナーで導入できるのは通常の Docker と同じです。

```sh
$ curl -fsSL get.docker.com/rootless | sh
# Installing stable version 19.03.12
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 57.9M  100 57.9M    0     0  18.0M      0  0:00:03  0:00:03 --:--:-- 18.0M
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 18.3M  100 18.3M    0     0  6245k      0  0:00:03  0:00:03 --:--:-- 6245k
# starting systemd service
● docker.service - Docker Application Container Engine (Rootless)
     Loaded: loaded (/home/dev/.config/systemd/user/docker.service; disabled; vendor preset: enabled)
     Active: active (running) since Sat 2020-07-25 08:07:23 UTC; 21ms ago
       Docs: https://docs.docker.com
   Main PID: 45635 (rootlesskit)
     CGroup: /user.slice/user-1000.slice/user@1000.service/docker.service
             tq45635 rootlesskit --net=vpnkit --mtu=1500 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run /home/dev/bin/dockerd-rootless.sh --experimental --storage-driver=overlay2
             tq45647 /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/dev/bin/dockerd-rootless.sh --experimental --storage-driver=overlay2
             mq45656 newgidmap 45647 0 1000 1 1 100000 65536

Jul 25 08:07:23 docker dockerd-rootless.sh[45635]: + which slirp4netns
Jul 25 08:07:23 docker dockerd-rootless.sh[45635]: + [ -z ]
Jul 25 08:07:23 docker dockerd-rootless.sh[45635]: + which vpnkit
Jul 25 08:07:23 docker dockerd-rootless.sh[45635]: + net=vpnkit
Jul 25 08:07:23 docker dockerd-rootless.sh[45635]: + [ -z ]
Jul 25 08:07:23 docker dockerd-rootless.sh[45635]: + mtu=1500
Jul 25 08:07:23 docker dockerd-rootless.sh[45635]: + [ -z ]
Jul 25 08:07:23 docker dockerd-rootless.sh[45635]: + _DOCKERD_ROOTLESS_CHILD=1
Jul 25 08:07:23 docker dockerd-rootless.sh[45635]: + export _DOCKERD_ROOTLESS_CHILD
Jul 25 08:07:23 docker dockerd-rootless.sh[45635]: + exec rootlesskit --net=vpnkit --mtu=1500 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run /home/dev/bin/dockerd-rootless.sh --experimental --storage-driver=overlay2
Client: Docker Engine - Community
 Version:           19.03.12
 API version:       1.40
 Go version:        go1.13.10
 Git commit:        48a66213fe
 Built:             Mon Jun 22 15:42:53 2020
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.12
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.13.10
  Git commit:       48a66213fe
  Built:            Mon Jun 22 15:49:35 2020
  OS/Arch:          linux/amd64
  Experimental:     true
 containerd:
  Version:          v1.2.13
  GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683
# Docker binaries are installed in /home/dev/bin
# WARN: dockerd is not in your current PATH or pointing to /home/dev/bin/dockerd
# Make sure the following environment variables are set (or add them to ~/.bashrc):

export PATH=/home/dev/bin:$PATH
export DOCKER_HOST=unix:///run/user/1000/docker.sock

#
# To control docker service run:
# systemctl --user (start|stop|restart) docker
#
```

これでインストールが完了しました。
ですがこのままでは `docker` コマンドは使えません。
※パスが通っている場所にインストールしたわけではないため
`docker` コマンドを使えるようにするために環境変数に追加します。

```sh
$ export PATH=/home/dev/bin:$PATH
$ export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock
```

実際に確認してみましょう。

```sh
$ docker info
Client:
 Debug Mode: false

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 1
 Server Version: 19.03.12
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Native Overlay Diff: false
 Logging Driver: json-file
 Cgroup Driver: none
 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: runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc version: dc9208a3303feef5b3839f4323d9beb36df0a9dd
 init version: fec3683
 Security Options:
  seccomp
   Profile: default
  rootless
 Kernel Version: 5.4.0-42-generic
 Operating System: Ubuntu 20.04.1 LTS
 OSType: linux
 Architecture: x86_64
 CPUs: 8
 Total Memory: 7.774GiB
 Name: docker
 ID: NURI:7LP5:IHUJ:VSSV:6E5W:VMLS:4D52:X5EJ:CB24:CDJ2:OMAO:LMWB
 Docker Root Dir: /home/dev/.local/share/docker
 Debug Mode: false
 Registry: https://index.docker.io/v1/
 Labels:
 Experimental: true
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false
 Product License: Community Engine
```

`docker` コマンドが使えていることと、 `Security Options` に `rootless` が含まれている点が確認できました。

## 使ってみる

とりあえず `Nginx` を動かしてみましょう。

```sh
$ docker run -dP --name nginx nginx
11cd14bb3bf8d4b99aa46be825bfd7f51143bc578e68ef265f3add1baa0b19ed
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                   NAMES
11cd14bb3bf8        nginx               "/docker-entrypoint.…"   19 seconds ago      Up 18 seconds       0.0.0.0:32768->80/tcp   nginx
$ curl -s localhost:32768 | head -n 5
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
```

ポートフォワードもしっかり動いていることが確認できました。

```sh
$ ps -aux | grep docker
dev         1519  0.0  0.0 112232  6856 ?        Ssl  10:18   0:00 rootlesskit --net=vpnkit --mtu=1500 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run /home/dev/bin/dockerd-rootless.sh --experimental --storage-driver=overlay2
dev         1528  7.4  0.1 112872 12060 ?        Sl   10:18   0:05 /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/dev/bin/dockerd-rootless.sh --experimental --storage-driver=overlay2
dev         1562 20.5  0.8 1638352 67892 ?       Sl   10:18   0:14 dockerd --experimental --storage-driver=overlay2
dev         1583  1.1  0.2 1241920 23784 ?       Ssl  10:18   0:00 containerd --config /run/user/1000/docker/containerd/containerd.toml --log-level info
dev         1875  0.0  0.0 106976  4780 ?        Sl   10:19   0:00 /home/dev/bin/rootlesskit-docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 32768 -container-ip 172.17.0.2 -container-port 80
dev         1880  0.0  0.0 103372  2364 ?        Sl   10:19   0:00 docker-proxy -container-ip 172.17.0.2 -container-port 80 -host-ip 127.0.0.1 -host-port 32768 -proto tcp
dev         1891  0.0  0.0 108872  4604 ?        Sl   10:19   0:00 containerd-shim -namespace moby -workdir /home/dev/.local/share/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/2f657a2a65b754ff9bd59254f1cd36b745c3f2679aa795c474e6ba29ead4e560 -address /run/user/1000/docker/containerd/containerd.sock -containerd-binary /home/dev/bin/containerd -runtime-root /run/user/1000/docker/runtime-runc
dev         1976  0.0  0.0   5192   740 pts/0    S+   10:20   0:00 grep --color=auto docker
```

また、 `root` ユーザーではなく `dev` ユーザーで実行していることも確認できました。