shiftfs (s_user_ns version) 試してみた
Open Source Summit Japan 2017 で聞いた話に shiftfs の話があって、興味を持ったので試してみました。この機能の前提機能なんかに関する前提知識に欠けているため、以下には間違いが含まれている可能性が大きいです。是非指摘を頂きたいと思います。試してみただけで内部の処理とかは書いてませんよw
下に関連情報を挙げておきます (こちらを直接見たほうがいいかも)。
- Container Interfaces for Storage - Are We There Yet? (Open Source Summit の James Bottomley 氏のスライド)
- shiftfs: uid/gid shifting filesystem (s_user_ns version) (lwn.net)
- Unprivileged Build Containers (James Bottomley’s random Pages)
- 【和訳】コンテナとストレージの問題:コンテナ普及の要因分析 (CREATIONLINEのブログ) (ちょっと訳がわかりづらい部分があるのでオリジナルの記事を見たほうがよいかも?)
直接関係ないけど s_user_ns
のパッチも紹介しておきます。
- s_user_ns の kernel patch (lkml.org)
User Namespace に関しては私の連載記事をどうぞ。
- 第16回 Linuxカーネルのコンテナ機能 [6] ─ユーザ名前空間 (LXCで学ぶコンテナ入門)
一般ユーザ権限のコンテナとイメージ
User Namespace を利用する場合、LXC では shadow に実装されている subuid, subgid を使い、そのユーザに対して使用を許可された uid/gid を使ってコンテナを作成し、起動します。
例えば $HOME/.config/lxc/default.conf
で
lxc.id_map = u 0 100000 65536 lxc.id_map = g 0 100000 65536
のように設定していれば、lxc-create
を実行した時、コンテナ内の uid:0 がホスト上では uid:100000 にマッピングされ、コンテナイメージ上の root 所有のファイルについては、ホスト上で見ると uid/gid が 100000 のユーザ・グループ所有で作成されます。
例えば次のような感じです。
$ ls -l ~/.local/share/lxc/xenial01/rootfs/ 合計 77,824 drwxr-xr-x 2 100000 100000 4,096 4月 22日 2016年 bin/ drwxr-xr-x 2 100000 100000 4,096 4月 13日 2016年 boot/ drwxr-xr-x 3 100000 100000 4,096 4月 22日 2016年 dev/ :(snip)
普段はこれで問題はないのですが、例えば public に流通している root 権限で起動するコンテナで利用する前提のイメージとか、単なる tar.gz のアーカイブとかを一般ユーザで使ったり、逆に一般ユーザ権限用のイメージを root で起動したりする際には、あらかじめ chown などで権限を変更しておく必要があります。一度きりの処理なら良いのですが、起動するたびに入れ代わり立ち代わりユーザを変えて起動したいとかだと不便です。
逆に一般ユーザ権限でコンテナイメージを作成すると、作成環境の ID のマッピング状況に依存してしましますね。
shiftfs
そこでどうやら 4.8 カーネルで struct super_block
に s_user_ns
という変数が導入され、ファイルシステム上のファイルやディレクトリの処理を行う際には、Namespace 上の ID を使うことができるようになったようです (ここはちゃんと調べてないので間違ってる可能性大)。
ただし、これは単なるディレクトリを bind mount して、コンテナイメージとして使う場合には使えません。なぜなら bind mount は独自の super block は持たないからです (たぶん)。
そこで、s_user_ns
を使って User Namespace 内での ID を使うように、super block を使いつつ bind mount をできる shiftfs という機能が James Bottomley 氏が提案しています。現時点では色々な理由であまり受け入れられる感じではなさそうですが…
このパッチは s_user_ns
より前のバージョンもあり、その際はマウントオプションで uidmap=0:1000:1
みたいにマッピングを設定していました。(以前のバージョン)
shiftfs のパッチ
どういう経緯かわからないですが、linuxkit に 4.11 用のパッチがありました。これを 4.12 に当ててみました。私の手元は aufs のパッチも当ててるので Makefile だけ適用エラーになりましたが、多分 4.12 にはそのまま当たります。
shiftfs 使わない場合
root 権限で lxc-create
で作った Alpine Linux のイメージで試してみました (あらかじめコンテナディレクトリやrootfsディレクトリは一般ユーザでアクセスできるようにしてあります)。
ホスト上で確認すると、root で作成しているので、当たり前ですが root 所有のディレクトリが並びます。
# ls -ld /var/lib/lxc/alpine01/rootfs drwxr-xr-x 1 root root 108 7月 5日 20:32 /var/lib/lxc/alpine01/rootfs/ # ls -l /var/lib/lxc/alpine01/rootfs 合計 0 drwxr-xr-x 1 root root 868 5月 4日 03:12 bin/ drwxr-xr-x 1 root root 130 5月 4日 03:12 dev/ drwxr-xr-x 1 root root 584 6月 22日 22:32 etc/ drwxr-xr-x 1 root root 0 5月 4日 03:12 home/ drwxr-xr-x 1 root root 354 5月 4日 03:12 lib/ drwxr-xr-x 1 root root 28 5月 4日 03:12 media/ drwxr-xr-x 1 root root 0 5月 4日 03:12 mnt/ drwxr-xr-x 1 root root 0 5月 4日 03:12 proc/ drwx------ 1 root root 24 6月 22日 20:54 root/ drwxr-xr-x 1 root root 0 5月 4日 03:12 run/ drwxr-xr-x 1 root root 1,610 5月 4日 03:12 sbin/ drwxr-xr-x 1 root root 0 5月 4日 03:12 srv/ drwxr-xr-x 1 root root 0 5月 4日 03:12 sys/ drwxrwxrwt 1 root root 36 6月 22日 22:02 tmp/ drwxr-xr-x 1 root root 40 5月 4日 03:12 usr/ drwxr-xr-x 1 root root 78 6月 22日 20:17 var/
このコンテナイメージを、普通に User Namespace を作成して、Namespace 内から見てみましょう。
$ unshare --pid --user --map-root-user --mount --mount-proc --fork -- /bin/bash # cat /proc/self/{u,g}id_map 0 1000 1 0 100 1 # ls -ld /var/lib/lxc/alpine01/rootfs drwxrwxrwx 1 nobody nogroup 108 6月 22日 22:02 /var/lib/lxc/alpine01/rootfs/ # ls -l /var/lib/lxc/alpine01/rootfs 合計 0 drwxr-xr-x 1 nobody nogroup 868 5月 4日 03:12 bin/ drwxr-xr-x 1 nobody nogroup 130 5月 4日 03:12 dev/ drwxr-xr-x 1 nobody nogroup 584 6月 22日 22:32 etc/ drwxr-xr-x 1 nobody nogroup 0 5月 4日 03:12 home/ drwxr-xr-x 1 nobody nogroup 354 5月 4日 03:12 lib/ drwxr-xr-x 1 nobody nogroup 28 5月 4日 03:12 media/ drwxr-xr-x 1 nobody nogroup 0 5月 4日 03:12 mnt/ drwxr-xr-x 1 nobody nogroup 0 5月 4日 03:12 proc/ drwx------ 1 nobody nogroup 24 6月 22日 20:54 root/ drwxr-xr-x 1 nobody nogroup 0 5月 4日 03:12 run/ drwxr-xr-x 1 nobody nogroup 1,610 5月 4日 03:12 sbin/ drwxr-xr-x 1 nobody nogroup 0 5月 4日 03:12 srv/ drwxr-xr-x 1 nobody nogroup 0 5月 4日 03:12 sys/ drwxrwxrwt 1 nobody nogroup 36 6月 22日 22:02 tmp/ drwxr-xr-x 1 nobody nogroup 40 5月 4日 03:12 usr/ drwxr-xr-x 1 nobody nogroup 78 6月 22日 20:17 var/ root@enterprise:~#
マッピングされていないので nobody:nogroup に。このままではこのイメージ以下に書き込みできません。(なぜnobody:nogroupになるのかは私の連載に書いてます)
shiftfs の利用
s_user_ns
バージョンの shiftfs は、まずマウントしたいディレクトリに印を付ける必要があるようです。まずは root で以下を実行。-o mark
と mark オプションでマウントします。
# mount -t shiftfs -o mark /var/lib/lxc/alpine01/rootfs/ /var/lib/lxc/alpine01/rootfs/ # grep alpine01 /proc/self/mounts /var/lib/lxc/alpine01/rootfs /var/lib/lxc/alpine01/rootfs shiftfs rw,relatime,mark 0 0
この後、また一般ユーザで userns 作成して、別ディレクトリに shiftfs マウントしてみます。この時は特にマウントオプションは不要です。
$ id -u ; id -g 1000 100 $ unshare --pid --user --map-root-user --mount --mount-proc --fork -- /bin/bash # cat /proc/self/{u,g}id_map 0 1000 1 0 100 1 # mount -t shiftfs /var/lib/lxc/alpine01/rootfs/ /home/karma/mnt # grep shiftfs /proc/self/mounts /var/lib/lxc/alpine01/rootfs /var/lib/lxc/alpine01/rootfs shiftfs rw,relatime,mark 0 0 /var/lib/lxc/alpine01/rootfs /home/karma/mnt shiftfs rw,relatime 0 0
ここでマウントしたディレクトリ以下を見てみると、
# ls -l /home/karma/mnt 合計 0 drwxr-xr-x 1 root root 868 5月 4日 03:12 bin/ drwxr-xr-x 1 root root 130 5月 4日 03:12 dev/ drwxr-xr-x 1 root root 584 6月 22日 22:32 etc/ drwxr-xr-x 1 root root 0 5月 4日 03:12 home/ drwxr-xr-x 1 root root 354 5月 4日 03:12 lib/ drwxr-xr-x 1 root root 28 5月 4日 03:12 media/ drwxr-xr-x 1 root root 0 5月 4日 03:12 mnt/ drwxr-xr-x 1 root root 0 5月 4日 03:12 proc/ drwx------ 1 root root 24 6月 22日 20:54 root/ drwxr-xr-x 1 root root 0 5月 4日 03:12 run/ drwxr-xr-x 1 root root 1,610 5月 4日 03:12 sbin/ drwxr-xr-x 1 root root 0 5月 4日 03:12 srv/ drwxr-xr-x 1 root root 0 5月 4日 03:12 sys/ drwxrwxrwt 1 root root 36 6月 22日 22:02 tmp/ drwxr-xr-x 1 root root 40 5月 4日 03:12 usr/ drwxr-xr-x 1 root root 78 6月 22日 20:17 var/
ちゃんと User Namespace 内から見ても root 所有に表示されています。