Docker CEからRootless Dockerへ移行してみる on EC2

# 概要
現在、EC2上でDocker CEを利用している。先日↓の記事を見かけたので、Rootless Dockerへの移行(といっても、Volumeのみ)を試してみる。
[RootlessモードでDockerをより安全にする [DockerCon発表レポート] – nttlabs – Medium](https://medium.com/nttlabs/rootless-docker-12decb900fb9)

# Rootless Docker？
> Rootlessモードは，Dockerデーモン及びコンテナを，非rootユーザで実行する技術です．Rootlessモードを用いることにより，万一Dockerに脆弱性や設定ミスがあっても，攻撃者にホストのroot権限を奪取されることを防ぐことが出来ます．

参考: [RootlessモードでDockerをより安全にする [DockerCon発表レポート] – nttlabs – Medium](https://medium.com/nttlabs/rootless-docker-12decb900fb9)

:thinking:Amazon Linuxでいうところの`ec2-user`ユーザだけで、Dockerデーモンの起動からdockerコマンドの利用までできるということ。

普通にDockerを起動すると、`root`ユーザでコンテナを起動する必要があるから、rootを乗っ取られる可能性がある。
よくある一般ユーザをdockerグループに属させて、一般ユーザでdockerコマンドを利用できるようにさせても、Docker自体は`root`ユーザで起動させているから、rootを乗っ取られる可能性がある。

Rootless Dockerは、一般ユーザだけで完結できるから、rootを取られる可能性が限りなく0に近づくってことですかね。

# 試した環境

少しOSやDocker CEが古いが...:expressionless:

```bash:OS
[ec2-user@localhost ~]$ cat /etc/os-release
NAME="Amazon Linux AMI"
VERSION="2018.03"
ID="amzn"
ID_LIKE="rhel fedora"
VERSION_ID="2018.03"
PRETTY_NAME="Amazon Linux AMI 2018.03"
ANSI_COLOR="0;33"
CPE_NAME="cpe:/o:amazon:linux:2018.03:ga"
HOME_URL="http://aws.amazon.com/amazon-linux-ami/"
```

```bash:DockerCE
[ec2-user@localhost ~]$ docker version
Client:
 Version:           18.06.1-ce
 API version:       1.38
 Go version:        go1.10.3
 Git commit:        e68fc7a215d7133c34aa18e3b72b4a21fd0c6136
 Built:             Mon Mar  4 21:25:23 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.06.1-ce
  API version:      1.38 (minimum version 1.12)
  Go version:       go1.10.3
  Git commit:       e68fc7a/18.06.1-ce
  Built:            Mon Mar  4 21:26:49 2019
  OS/Arch:          linux/amd64
  Experimental:     false
```

# 移行前のコンテナ環境
まずは、移行を試す環境を作る。
`docker volume create`でボリュームを作り、`centos`コンテナにマウントさせて起動する。
起動したコンテナ上で、1GBほどのファイルを作っておく。

```bash
[root@localhost ~]# docker volume create test
test
[root@localhost ~]# docker run -itd  -v test:/mnt centos
Unable to find image 'centos:latest' locally
latest: Pulling from library/centos
8ba884070f61: Pull complete
Digest: sha256:b5e66c4651870a1ad435cd75922fe2cb943c9e973a9673822d1414824a1d0475
Status: Downloaded newer image for centos:latest
d1256d1226bcd445616f13a0e73bbb322056c9151c7adbc7c7d84011e2afe4eb
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
d1256d1226bc        centos              "/bin/bash"         7 seconds ago       Up 6 seconds                            romantic_bell
[root@localhost ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos              latest              9f38484d220f        8 weeks ago         202MB
[root@localhost ~]# docker volume ls
DRIVER              VOLUME NAME
local               test
[root@localhost ~]# docker exec -it romantic_bell bash
[root@d1256d1226bc /]# cd /mnt
[root@d1256d1226bc mnt]# dd if=/dev/zero of=zerofile bs=1024 count=1000000
1000000+0 records in
1000000+0 records out
1024000000 bytes (1.0 GB) copied, 2.46405 s, 416 MB/s
[root@d1256d1226bc mnt]# ls -lh
total 977M
-rw-r--r-- 1 root root 977M May 12 08:49 zerofile
[root@d1256d1226bc mnt]# exit
```

# 移行前準備

Rootless Dockerをインストール(Docker CEを削除)する前に、ホスト側から[前項](#移行前のコンテナ環境)で作成したボリュームを退避させる。
退避前にコンテナも止めておく。
退避したボリュームは、Rootless Dockerを実行するユーザ、グループに予め変更しておく。

```bash
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
d1256d1226bc        centos              "/bin/bash"         7 seconds ago       Up 6 seconds                            romantic_bell
[root@localhost ~]# docker stop romantic_bell
romantic_bell
[root@localhost ~]# cp -rp /var/lib/docker/volumes /tmp/
[root@localhost ~]# chown -R ec2-user:ec2-user /tmp/volumes/
[root@localhost ~]# docker rm romantic_bell
romantic_bell
```
# Docker CEのアンインストール

Rootless Dockerを入れる前に、Docker CEをアンインストールする。
アンインストールをしないと、何故かRootless DockerがDocker CEの`/var/run/docker.sock`等を使って起動しなかった:innocent:

```bash
[root@localhost ~]# yum -y remove docker
Loaded plugins: priorities, update-motd, upgrade-helper
Resolving Dependencies
--> Running transaction check
---> Package docker.x86_64 0:18.06.1ce-8.28.amzn1 will be erased
--> Finished Dependency Resolution

Dependencies Resolved

==============================================================================================================================================
 Package                     Arch                        Version                                     Repository                          Size
==============================================================================================================================================
Removing:
 docker                      x86_64                      18.06.1ce-8.28.amzn1                        @amzn-updates                      150 M

Transaction Summary
==============================================================================================================================================
Remove  1 Package

Installed size: 150 M
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Erasing    : docker-18.06.1ce-8.28.amzn1.x86_64                                                                                         1/1
  Verifying  : docker-18.06.1ce-8.28.amzn1.x86_64                                                                                         1/1

Removed:
  docker.x86_64 0:18.06.1ce-8.28.amzn1

Complete!
[root@localhost ~]# 
```
# Rootless Dockerのインストール&実行

インストールといっても、コマンド1つで終わるらしい。:thinking:

```bash
[ec2-user@localhost ~]$ curl -fsSL https://get.docker.com/rootless | sh
# 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
curl -o /etc/yum.repos.d/vbatts-shadow-utils-newxidmap-epel-7.repo https://copr.fedorainfracloud.org/coprs/vbatts/shadow-utils-newxidmap/repo/epel-7/vbatts-shadow-utils-newxidmap-epel-7.repo
yum install -y shadow-utils46-newxidmap
EOF
```
パッケージが足りない。:frowning2:

```bash
[ec2-user@localhost ~]$ cat <<EOF | sudo sh -x
> curl -o /etc/yum.repos.d/vbatts-shadow-utils-newxidmap-epel-7.repo https://copr.fedorainfracloud.org/coprs/vbatts/shadow-utils-newxidmap/repo/epel-7/vbatts-shadow-utils-newxidmap-epel-7.repo
> yum install -y shadow-utils46-newxidmap
> EOF
～省略～
[ec2-user@localhost ~]$ curl -fsSL https://get.docker.com/rootless | sh
Could not find records for the current user ec2-user from /etc/subuid . Please make sure valid subuid range is set there.
For example:
echo "ec2-user:100000:65536" >> /etc/subuid
```

`/etc/subuid`,`/etc/subgid`がない。
そもそも見た記憶がない。作る。:rolling_eyes:

```bash
[root@localhost ~]$ sudo su -
[root@localhost ~]# echo "ec2-user:1000:65536" >> /etc/subuid
[root@localhost ~]# echo "ec2-user:1000:65536" >> /etc/subgid
[root@localhost ~]# exit
[ec2-user@localhost ~]$ curl -fsSL https://get.docker.com/rootless | sh
# systemd not detected, dockerd daemon needs to be started manually

/home/ec2-user/bin/dockerd-rootless.sh --experimental --storage-driver vfs

# Docker binaries are installed in /home/ec2-user/bin
# WARN: dockerd is not in your current PATH or pointing to /home/ec2-user/bin/dockerd
# Make sure the following environment variables are set (or add them to ~/.bashrc):\n
export XDG_RUNTIME_DIR=/tmp/docker-500
export DOCKER_HOST=unix:///tmp/docker-500/docker.sock
```
言われた通りに、`.bashrc`に追加する。
また、`bin`ディレクトリもできていたので、合わせて追加する。
`/tmp/docker-500`配下に`docker.sock`ができるので、嫌な場合はこれらの環境変数を変えておけばよさそう。

```bash
[ec2-user@localhost ~]$ echo "export XDG_RUNTIME_DIR=/tmp/docker-500" >> ~/.bashrc
[ec2-user@localhost ~]$ echo "export DOCKER_HOST=unix:///tmp/docker-500/docker.sock" >> ~/.bashrc
[ec2-user@localhost ~]$ echo 'PATH=$PATH:$HOME/bin' >> .bashrc
[ec2-user@localhost ~]$ source .bashrc
```

インストールが終わったので、言われたとおりにサーバを起動する。
起動し続けておく必要があるので、`screen`で起動する。デタッチは、デフォルトは`Ctrl-a`押して`d`

```bash
[ec2-user@localhost ~]$ screen
[ec2-user@localhost ~]$ /home/ec2-user/bin/dockerd-rootless.sh --experimental --storage-driver vfs
INFO[2019-05-12T08:08:51.179358654Z] Default bridge (docker0) is assigned with an IP address 172.17.0.0/16. Daemon option --bip can be used to set a preferred IP address
INFO[2019-05-12T08:08:51.330646070Z] Loading containers: done.
INFO[2019-05-12T08:08:51.344736419Z] Docker daemon                                 commit=3998dff graphdriver(s)=vfs version=master-dockerproject-2019-05-11
INFO[2019-05-12T08:08:51.344855472Z] Daemon has completed initialization
INFO[2019-05-12T08:08:51.362135829Z] API listen on /tmp/docker-500/docker.sock
[detached]
[ec2-user@localhost ~]$
[ec2-user@localhost ~]$ docker version
Client:
 Version:           master-dockerproject-2019-05-11
 API version:       1.40
 Go version:        go1.12.5
 Git commit:        53fc2572
 Built:             Sat May 11 23:39:34 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          master-dockerproject-2019-05-11
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.5
  Git commit:       3998dff
  Built:            Sat May 11 23:46:26 2019
  OS/Arch:          linux/amd64
  Experimental:     true
 containerd:
  Version:          v1.2.6
  GitCommit:        894b81a4b802e4eb2a91d1ce216b8817763c29fb
 runc:
  Version:          1.0.0-rc8
  GitCommit:        425e105d5a03fabd737a126ad93d62a9eeede87f
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683
```

## 適当なコンテナを起動してみる

`docker`コマンドはパスを通したので今までどおり使える。

```bash
[ec2-user@localhost ~]$ docker run -d -p 8080:80 nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
743f2d6c1f65: Pull complete
6bfc4ec4420a: Pull complete
688a776db95f: Pull complete
Digest: sha256:23b4dcdf0d34d4a129755fc6f52e1c6e23bb34ea011b315d87e193033bcd1b68
Status: Downloaded newer image for nginx:latest
a26c026eddf0f0d92db01e6cd6984f83904ffc5b4d69dd245a3a88081cdc6db5
[ec2-user@localhost ~]$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
a26c026eddf0        nginx               "nginx -g 'daemon of…"   4 seconds ago       Up 3 seconds        0.0.0.0:8080->80/tcp   xenodochial_khayyam
[ec2-user@localhost ~]$ curl http://localhost:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[ec2-user@localhost ~]$
```

Rootless Docker動いた:relaxed:

# ボリュームの移行

そもそも`volumes`ディレクトリはどこにあるのか。:thinking:

```bash
[ec2-user@ip-172-31-47-41 ~]$ ll /tmp/docker-500/
total 12
drwx-----T 7 ec2-user ec2-user 4096 May 12 08:58 docker
-rw-r--r-T 1 ec2-user ec2-user    5 May 12 08:58 docker.pid
srw-rw---T 1 ec2-user     1496    0 May 12 08:58 docker.sock
drwx-----T 2 ec2-user ec2-user 4096 May 12 08:08 runc
[ec2-user@ip-172-31-47-41 ~]$ find . -name 'docker'
./.vim/plugged/ultisnips/docker
./.local/share/docker
～省略～
[ec2-user@ip-172-31-47-41 ~]$ ll .local/share/docker/
total 56
drwx------ 2 ec2-user ec2-user 4096 May 12 08:08 builder
drwx------ 4 ec2-user ec2-user 4096 May 12 08:08 buildkit
drwx------ 3 ec2-user ec2-user 4096 May 12 08:08 containerd
drwx------ 4 ec2-user ec2-user 4096 May 12 09:11 containers
-rw------- 1 ec2-user ec2-user   36 May 12 08:08 engine_uuid
drwx------ 3 ec2-user ec2-user 4096 May 12 08:08 image
drwxr-x--- 3 ec2-user ec2-user 4096 May 12 08:08 network
drwx------ 4 ec2-user ec2-user 4096 May 12 08:08 plugins
drwx------ 2 ec2-user ec2-user 4096 May 12 08:58 runtimes
drwx------ 2 ec2-user ec2-user 4096 May 12 08:08 swarm
drwx------ 2 ec2-user ec2-user 4096 May 12 09:11 tmp
drwx------ 2 ec2-user ec2-user 4096 May 12 08:08 trust
drwx------ 3 ec2-user ec2-user 4096 May 12 08:15 vfs
drwx------ 3 ec2-user ec2-user 4096 May 12 09:08 volumes
[ec2-user@ip-172-31-47-41 ~]$
```
ホームディレクトリの`.local/share/docker`配下にあった

```bash
[ec2-user@ip-172-31-47-41 ~]$ ll .local/share/docker/volumes
total 24
-rw------- 1 ec2-user ec2-user 32768 May 12 09:08 metadata.db
```
メタデータがあるので、ディレクトリだけ移動
でも移動だけだと認識されないので、同名で`docker volume create`

```bash
[ec2-user@localhost ~]$ mv /tmp/volumes/test ~/.local/share/docker/volume/
[ec2-user@localhost ~]$ docker volume ls
DRIVER              VOLUME NAME
[ec2-user@localhost ~]$
[ec2-user@localhost ~]$ docker volume create test
test
[ec2-user@localhost ~]$ docker volume ls
DRIVER              VOLUME NAME
local               test
```

あとは、`Docker CE`のときと同じようにコンテナを作成する。

```bash
[ec2-user@localhost ~]$ docker run -itd  -v test:/mnt centos
Unable to find image 'centos:latest' locally
latest: Pulling from library/centos
8ba884070f61: Pull complete
Digest: sha256:b5e66c4651870a1ad435cd75922fe2cb943c9e973a9673822d1414824a1d0475
Status: Downloaded newer image for centos:latest
cfbadb0e2e67047bf25e23a2ce73835dfb9557e8341e4aead1cf658d69eacf9a
[ec2-user@localhost ~]$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
cfbadb0e2e67        centos              "/bin/bash"         About a minute ago   Up About a minute                       jolly_fermi
[ec2-user@localhost ~]$
[ec2-user@localhost ~]$
[ec2-user@localhost ~]$ docker inspect jolly_fermi | grep volume
                "Type": "volume",
                "Source": "/home/ec2-user/.local/share/docker/volumes/test/_data",
[ec2-user@localhost ~]$ docker exec jolly_fermi /bin/ls /mnt -l
total 1000004
-rw-r--r-- 1 root root 1024000000 May 12 08:49 zerofile
[ec2-user@ip-172-31-47-41 ~]$ docker exec jolly_fermi bash -c "echo 'hello' >> /mnt/hello.txt"
[ec2-user@ip-172-31-47-41 ~]$ cat .local/share/docker/volumes/test/_data/hello.txt
hello
[ec2-user@ip-172-31-47-41 ~]$
```
どうやらボリュームの移行はちゃんとできたようだ:clap:

[参考]
[moby/rootless.md at master · moby/moby](https://github.com/moby/moby/blob/master/docs/rootless.md#usage)
[RootlessモードでDockerをより安全にする [DockerCon発表レポート] – nttlabs – Medium](https://medium.com/nttlabs/rootless-docker-12decb900fb9)

# 最後に

気が向いたら`docker-compose`で作成したものも試しておきたい。