LoginSignup
16
13

More than 3 years have passed since last update.

DockerのUID/GIDあれこれ: Linux版通常モード & Docker Desktop for Mac編

Posted at

1. はじめに

 Dockerコンテナからボリュームマウントを通じてファイルを書き出す場合、ユーザID/グループID(以下、UID/GID)を指定しないとファイルのオーナがroot(UID0)になってしまい、困ることがあります。
docker container runコマンドの--userオプションでUID/GIDを指定することができますが、Linux版DockerとDocker Desktop for Macでは挙動に差があります。
これらの挙動について自分なりに整理するために、いろいろ実験しました。
なお、DockerfileUSER命令を使用してUID/GIDを指定する方法もありますが、今回はそちらについては触れていませんのでご了承ください。

 余裕があれば、Rootlessモード編、userns-remapモード編も書きたいと思います。というか、そちらが本命なのですが。

2. Linux版 通常モード

 まずは、Linux版Dockerの通常モード(Rootlessモードでも、userns-remapモードでもない、一般的なモード)での挙動を調査しました。

2.1. 環境

 調査した環境は以下の通りです。

  • ハードウェア: Raspberry Pi 4 2GB版
  • OS: Ubuntu Server 20.04 LTS ARM64(64ビット)版
  • Docker Engine: 19.03.8
ubuntu$ cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

ubuntu$ uname -a
Linux ubuntu 5.4.0-1008-raspi #8-Ubuntu SMP Wed Apr 8 11:13:06 UTC 2020 aarch64 aarch64 aarch64 GNU/Linux

ubuntu$ sudo docker version
Client:
 Version:           19.03.8
 API version:       1.40
 Go version:        go1.13.8
 Git commit:        afacb8b7f0
 Built:             Wed Mar 11 23:43:15 2020
 OS/Arch:           linux/arm64
 Experimental:      false

Server:
 Engine:
  Version:          19.03.8
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.13.8
  Git commit:       afacb8b7f0
  Built:            Wed Mar 11 22:48:33 2020
  OS/Arch:          linux/arm64
  Experimental:     false
 containerd:
  Version:          1.3.3-0ubuntu2
  GitCommit:
 runc:
  Version:          spec: 1.0.1-dev
  GitCommit:
 docker-init:
  Version:          0.18.0
  GitCommit:

ubuntu$ sudo docker info
...
 Security Options:
  apparmor
  seccomp
   Profile: default
...

 なお、以下のコマンドは標準のubuntuユーザ(UID1000、GID1000)で実行しています。
ubuntuユーザはdockerグループには意図的に入れていないため、dockerコマンドの実行にはsudoを利用しています。
Rootlessモード、userns-remapモードは使用していませんが、念のため/etc/subuid/etc/subgidの内容も示します。

ubuntu$ id
uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),115(netdev),118(lxd)

ubuntu$ cat /etc/subuid
ubuntu:100000:65536

ubuntu$ cat /etc/subgid
ubuntu:100000:65536

2.2. 実験

 実験は以下の通りです。インラインで説明を記載しています。
なお、ファイルの読み込み権限を分かりやすくするためにumaskでパーミッションのマスクを設定しています。
また、今回の実験ではUIDとGIDに同一の値を設定していますが、もちろん別々の値でも構いません。

# 実験用のディレクトリを作成します。(他ユーザでも書き込める必要があります)
ubuntu$ mkdir -p -m 777 /tmp/docker/normal

# UID/GIDを指定せず、idコマンドを実行してUID/GIDを確認します。
# →UID/GIDは0:0です。
ubuntu$ sudo docker container run --tty --rm ubuntu:20.04 id
uid=0(root) gid=0(root) groups=0(root)

# UID/GIDを指定せず、touchコマンドで空ファイルを生成して、ファイルのUID/GIDを確認します。
# →ファイルのUID/GIDは0:0です。
ubuntu$ sudo docker container run --tty --rm --volume /tmp/docker/normal:/out ubuntu:20.04 /bin/bash -c "umask 0077 && touch /out/without_user && ls -ln /out/without_user"
-rw------- 1 0 0 0 May 18 15:53 /out/without_user

# UID/GIDとして1000:1000を指定し、idコマンドを実行してUID/GIDを確認します。
# →UID/GIDは1000:1000です。
ubuntu$ sudo docker container run --tty --user 1000:1000 ubuntu:20.04 id
uid=1000 gid=1000 groups=1000

# UID/GIDとして1000:1000を指定し、touchコマンドで空ファイルを生成して、ファイルのUID/GIDを確認します。
# →ファイルのUID/GIDは1000:1000です。
ubuntu$ sudo docker container run --tty --user 1000:1000 --volume /tmp/docker/normal:/out ubuntu:20.04 /bin/bash -c "umask 0077 && touch /out/with_user_1000 && ls -ln /out/with_user_1000"
-rw------- 1 1000 1000 0 May 18 15:54 /out/with_user_1000

# UID/GIDとして2000:2000を指定し、idコマンドを実行してUID/GIDを確認します。
# →UIG/GIDは2000:2000です。
ubuntu$ sudo docker container run --tty --user 2000:2000 ubuntu:20.04 id
uid=2000 gid=2000 groups=2000

# UID/GIDとして2000:2000を指定し、touchコマンドで空ファイルを生成して、ファイルのUID/GIDを確認します。
# →ファイルのUID/GIDは2000:2000です。
ubuntu$ sudo docker container run --tty --user 2000:2000 --volume /tmp/docker/normal:/out ubuntu:20.04 /bin/bash -c "umask 0077 && touch /out/with_user_2000 && ls -ln /out/with_user_2000"
-rw------- 1 2000 2000 0 May 18 15:54 /out/with_user_2000

# Dockerホスト側のファイルのUID/GIDを確認します。
# →UID/GIDはDockerコンテナ内と同一です。
ubuntu$ ls -ln /tmp/docker/normal/
total 0
-rw------- 1    0    0 0 May 18 15:53 without_user
-rw------- 1 1000 1000 0 May 18 15:54 with_user_1000
-rw------- 1 2000 2000 0 May 18 15:54 with_user_2000

# Dockerホスト側でファイルを読めるかどうか確認します。
# →ubuntuユーザでは0:0のファイルを読むことができません。
ubuntu$ cat /tmp/docker/normal/without_user
cat: /tmp/docker/normal/without_user: Permission denied

# →ubuntuユーザでは1000:1000のファイルを読むことができます。
ubuntu$ cat /tmp/docker/normal/with_user_1000

# →ubuntuユーザでは2000:2000のファイルを読むことができません。
ubuntu$ cat /tmp/docker/normal/with_user_2000
cat: /tmp/docker/normal/with_user_2000: Permission denied

 Linux版Dockerの通常モードでは、割と素直な結果になりました。整理すると以下の通りです。

  • --userオプションを指定しない場合:
    • Dockerコンテナ内での実行UID/GIDは0:0となり、ファイルのUID/GIDも同一となる。
    • また、Dockerホスト側から見てもファイルのUID/GIDはDockerコンテナ内と同一となる。
  • --userオプションを指定した場合:
    • Dockerコンテナ内での実行UID/GIDは--userオプションで指定した値となり、ファイルのUID/GIDも同一となる。
    • また、Dockerホスト側から見てもファイルのUID/GIDはDockerコンテナ内と同一となる。

3. Docker Desktop for Mac

 続いてmacOS上で動作する「Docker Desktop for Mac」での挙動を調査しました。

3.1. 環境

 調査した環境は以下の通りです。

  • ハードウェア: MacBook Pro 2018
  • OS: macOS 10.14.6(Mojave)
  • Docker Desktop for Mac: 2.3.0.2
  • Docker Engine: 19.03.8
mac$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.6
BuildVersion:   18G103

mac$ docker version
Client: Docker Engine - Community
 Version:           19.03.8
 API version:       1.40
 Go version:        go1.12.17
 Git commit:        afacb8b
 Built:             Wed Mar 11 01:21:11 2020
 OS/Arch:           darwin/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.8
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.17
  Git commit:       afacb8b
  Built:            Wed Mar 11 01:29:16 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.2.13
  GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

mac$ docker info
...
 Security Options:
  seccomp
   Profile: default
...

 なお、以下のコマンドは作業用のユーザ(UID501、GID20)で実行しています。

mac$ id -u
501

mac$ id -g
20

3.2. 実験

 実験は以下の通りです。インラインで説明を記載しています。

# 実験用のディレクトリを作成します。(他ユーザでも書き込める必要があります)
mac$ mkdir -p -m 777 /tmp/docker/mac

# UID/GIDを指定せず、idコマンドを実行してUID/GIDを確認します。
# →UID/GIDは0:0です。
mac$ docker container run --tty --rm ubuntu:20.04 id
uid=0(root) gid=0(root) groups=0(root)

# UID/GIDを指定せず、touchコマンドで空ファイルを生成して、ファイルのUID/GIDを確認します。
# →ファイルのUID/GIDは0:0です。
mac$ docker container run --tty --rm --volume /tmp/docker/mac:/out ubuntu:20.04 /bin/bash -c "umask 0077 && touch /out/without_user && ls -ln /out/without_user"
-rw------- 1 0 0 0 May 18 15:23 /out/without_user

# UID/GIDとして1000:1000を指定し、idコマンドを実行してUID/GIDを確認します。
# →UID/GIDは1000:1000です。
mac$ docker container run --tty --user 1000:1000 ubuntu:20.04 id
uid=1000 gid=1000 groups=1000

# UID/GIDとして1000:1000を指定し、touchコマンドで空ファイルを生成して、ファイルのUID/GIDを確認します。
# →ファイルのUID/GIDは1000:1000です。
mac$ docker container run --tty --user 1000:1000 --volume /tmp/docker/mac:/out ubuntu:20.04 /bin/bash -c "umask 0077 && touch /out/with_user_1000 && ls -ln /out/with_user_1000"
-rw------- 1 1000 1000 0 May 18 15:24 /out/with_user_1000

# UID/GIDとして2000:2000を指定し、idコマンドを実行してUID/GIDを確認します。
# →UIG/GIDは2000:2000です。
mac$ docker container run --tty --user 2000:2000 ubuntu:20.04 id
uid=2000 gid=2000 groups=2000

# UID/GIDとして2000:2000を指定し、touchコマンドで空ファイルを生成して、ファイルのUID/GIDを確認します。
# →ファイルのUID/GIDは2000:2000です。
mac$ docker container run --tty --user 2000:2000 --volume /tmp/docker/mac:/out ubuntu:20.04 /bin/bash -c "umask 0077 && touch /out/with_user_2000 && ls -ln /out/with_user_2000"
-rw------- 1 2000 2000 0 May 18 15:24 /out/with_user_2000

# Dockerホスト側のファイルのUID/GIDを確認します。
# →UID/GIDはDockerコンテナ内と異なり、UIDはすべてmacOS側の実行ユーザ、GIDはすべて0です。
mac$ ls -ln /tmp/docker/mac/
total 0
-rw-------  1 501  0  0 May 19 00:24 with_user_1000
-rw-------  1 501  0  0 May 19 00:24 with_user_2000
-rw-------  1 501  0  0 May 19 00:23 without_user

# Dockerホスト側でファイルを読めるかどうか確認します。
# →UIDが同一のため、すべてのファイルはエラーなく読むことができます。
mac$ cat /tmp/docker/mac/without_user
mac$ cat /tmp/docker/mac/with_user_1000
mac$ cat /tmp/docker/mac/with_user_2000

 Docker Desktop for Macでは、Linux版Dockerの通常モードとは異なる結果になりました。整理すると以下の通りです。

  • --userオプションを指定しない場合:
    • Dockerコンテナ内での実行UID/GIDは0:0となり、ファイルのUID/GIDも同一となる。(Linux版通常モードと同一の挙動)
    • ただし、Dockerホスト側から見たファイルのUID/GIDはmacOS側のUID:0となる。(Linux版通常モードと異なる挙動)
  • --userオプションを指定した場合:
    • Dockerコンテナ内での実行UID/GIDは指定した値となり、ファイルのUID/GIDも同一となる。(Linux版通常モードと同一の挙動)
    • ただし、Dockerホスト側から見たファイルのUID/GIDはmacOS側のUID:0となる。(Linux版通常モードと異なる挙動)

4. 最後に

 本命はRootlessモード、userns-remapモードの挙動の調査なので、頑張って続きを書きたいと思います。

参考

16
13
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
16
13