TenForward

技術ブログ。はてなダイアリーから移転しました

docker-compose.yaml の volumes の指定でハマった話

私はDockerもDocker Composeもcontainerdも素人で、今回の問題がよく知られた問題なのか、そうでないのかもよく知りません。ちなみにDocker Composeは今日まで使ったことがなかったし、Rancher Desktopも今日はじめてインストールしました(^^)。

この辺りのコンテナランタイムの知識もないので、用語の使い方も間違ってたりするかもしれませんがご容赦を。

このエントリは単に「ちょっと時間使って調べた」ので「オレ頑張ったよ」と誰かに言わないと気がすまないし、最近技術ブログ書いてないよなと思ったので書いてみるだけです。

問題

「Sensu Goをコンテナで起動してるけど、コンテナを再起動するたびに初期化されるので、Sensuに詳しいだろうからちょっと見て」という相談を受けたのが始まりです。(ちなみにSensu Go詳しくないです。Sensu Goを使ったシステムをちょっと作ったことがありますが)結局は Sensu の知識は全く不要でした。

Rancher Desktop環境で、Sensu Goの公式ドキュメントにあるDocker Composeを使ってsensu-backend(sensuサーバー)を起動すると、再起動するたびにetcdのデータが初期化されているのか、毎回クライアント側も初期設定する必要があるということでした。

ちなみに yaml はこんな。

version: "3"
services:
  sensu-backend:
    ports:
    - 3000:3000
    - 8080:8080
    - 8081:8081
    volumes:
    - "sensu-backend-data:/var/lib/sensu/sensu-backend/etcd"
    command: "sensu-backend start --state-dir /var/lib/sensu/sensu-backend --log-level debug"
    environment:
    - SENSU_BACKEND_CLUSTER_ADMIN_USERNAME=admin
    - SENSU_BACKEND_CLUSTER_ADMIN_PASSWORD=admin
    image: sensu/sensu:latest

volumes:
  sensu-backend-data:
    driver: local

解決

問題自体はすぐに解決しました。手元に Rancher Desktop がなかったので、Linux 上の Docker 環境で docker-compose.yaml を書いて起動してみました。

しかしどのようにやっても、ちょっとコンテナを強制終了しても、特に再起動後は問題なく使えます。で、このことを相談を受けた人に伝えると、すぐに

  • Linux(のDocker)でやったらたしかに問題は起こらない
  • 試しに Rancher Desktop のコンテナランタイムを "containerd" にしていたのを "dockerd(moby)" に切り替えたら問題が起こらなくなった

というわけで、これで解決です。

問題を再燃させる

でも、気になりますよね、これ!ということであえて Rancher Desktop のコンテナランタイムを "containerd" に切り替えて調査!

ここで引き下がるのはなんか悔しいってことで色々調べてみました。調べたといってもほとんど Docker Compose の YAML の書き方とか、そもそも「ボリュームってなんやねん」とか、皆無だった基礎知識のあたりを調べてた時間がほとんどですが。

まず、最初に気づいたのは起動時に Warning が出ていること。

% nerdctl compose up -d
INFO[0000] Creating network sensu_default
WARN[0000] Ignoring: volume sensu-backend-data: [Driver] <-(コレ)
INFO[0000] Ensuring image sensu/sensu:latest
INFO[0000] Creating container sensu_sensu-backend_1

もしかして、ボリュームがうまくできてないの?とか思ったけど、これは文字通りWarningで関係ないことが後で判明します。多分ですが、

ココ

Unimplemented docker volume create flags: --driver, --opt

と書かれてるので、これが原因でしょう。

色々調べてると、どうやら再起動するたびにボリュームが新たに作られていってることに気づきます。これだったら、毎回新たに etcd のデータが作られるので、毎回初期設定が必要になるのもわかります。こんな感じ。再起動のたびに新たにボリュームが作られています。

% nerdctl volume list               
VOLUME NAME    DIRECTORY
% nerdctl compose up -d
INFO[0000] Creating network sensu_default               
WARN[0000] Ignoring: volume sensu-backend-data: [Driver] 
INFO[0000] Creating volume sensu_sensu-backend-data     
INFO[0000] Ensuring image sensu/sensu:latest            
INFO[0000] Creating container sensu_sensu-backend_1     
% nerdctl volume list  
VOLUME NAME                                                         DIRECTORY
9a3721923ba55334655208752d48846585c9072f11bce8f1e7fa9f2a4a5074a0    /var/lib/nerdctl/dbb19c5e/volumes/default/9a3721923ba55334655208752d48846585c9072f11bce8f1e7fa9f2a4a5074a0/_data
sensu_sensu-backend-data                                            /var/lib/nerdctl/dbb19c5e/volumes/default/sensu_sensu-backend-data/_data
% nerdctl compose down              
INFO[0000] Removing container sensu_sensu-backend_1     
INFO[0000] Removing network sensu_default               
karma@warbird sensu % nerdctl compose up -d
INFO[0000] Creating network sensu_default               
WARN[0000] Ignoring: volume sensu-backend-data: [Driver] 
INFO[0000] Ensuring image sensu/sensu:latest            
INFO[0000] Creating container sensu_sensu-backend_1     
% nerdctl volume list  
VOLUME NAME                                                         DIRECTORY
sensu_sensu-backend-data                                            /var/lib/nerdctl/dbb19c5e/volumes/default/sensu_sensu-backend-data/_data
0b65bbacb252e1ac8953c2b2903aa7ae94b0f213952776ce568d08bdb8b794d2    /var/lib/nerdctl/dbb19c5e/volumes/default/0b65bbacb252e1ac8953c2b2903aa7ae94b0f213952776ce568d08bdb8b794d2/_data
9a3721923ba55334655208752d48846585c9072f11bce8f1e7fa9f2a4a5074a0    /var/lib/nerdctl/dbb19c5e/volumes/default/9a3721923ba55334655208752d48846585c9072f11bce8f1e7fa9f2a4a5074a0/_data

たぶん、ここは sensu-backend-data という名前のボリュームがひとつだけ作られるのが正解っぽいけど、なぜか謎のボリュームが増殖していくという…

これは何が起こっているのかコンテナ内(コンテナのMount Namespace内)を確認しないとダメだね、ってことで、やってみました。

% nerdctl ps          
CONTAINER ID    IMAGE                           COMMAND                   CREATED          STATUS    PORTS                                                                     NAMES
0eeffa3553b5    docker.io/sensu/sensu:latest    "sensu-backend start…"    2 minutes ago    Up        0.0.0.0:3000->3000/tcp, 0.0.0.0:8080->8080/tcp, 0.0.0.0:8081->8081/tcp    sensu_sensu-backend_1    
% nerdctl exec -ti sensu_sensu-backend_1 -- /bin/sh
/ # cat /proc/self/mountinfo | grep sensu
146 125 253:1 /var/lib/nerdctl/dbb19c5e/volumes/default/sensu_sensu-backend-data/_data /var/lib/sensu/sensu-backend/etcd rw,relatime master:4 - ext4 /dev/disk/by-label/data-volume rw
147 125 253:1 /var/lib/nerdctl/dbb19c5e/volumes/default/0b65bbacb252e1ac8953c2b2903aa7ae94b0f213952776ce568d08bdb8b794d2/_data /var/lib/sensu rw,relatime master:4 - ext4 /dev/disk/by-label/data-volume rw

これでもうわかりましたね。ちゃんと指定のボリュームは作られているものの、別のマウントもされているので、おそらくはそっち側が上にマウントされてる感じかな?

ちなみに名前付きで作ってるボリュームについては、コンテナ内の別のディレクトリにマウントしてみると空でした。こっちが指定どおり sensu-backend-data という名前で作られてないのも気になりますね。("name" 属性を指定したらちゃんとその名前で作られたけど)

匿名のボリュームは /var/lib/sensu にマウントされていることから、コンテナ内に /var/lib/sensu は存在しなくても作ってくれるものの、さらにその子ディレクトリが /var/lib/sensu/sensu-backend/etcd のように指定されていると、コンテナ上にはそのようなディレクトリがないので、まずは /var/lib/sensu を作りに行って、それに新たにボリュームが作成されてマウントされてしまう感じでしょうか。名前付きのボリュームもマウントはされているので、そちらがどのような状態になっているのかが謎…

存在しないディレクトリにはマウントできないし、でも作成された後であとでマウントされたらそっちが見えるはずだし、でもどうやら匿名で作られた /var/lib/sensu にマウントされている方が上で見えているようだし…

というわけで、docker-compose.yaml には、存在しないディレクトリは /var/lib/sensu のように一段だけ指定して無事解決でした。

version: "3"
services:
  sensu-backend:
    ports:
    - 3000:3000
    - 8080:8080
    - 8081:8081
    volumes:
    - sensu-backend-data:/var/lib/sensu
    command: "sensu-backend start --state-dir /var/lib/sensu/sensu-backend --log-level debug"
    environment:
    - SENSU_BACKEND_CLUSTER_ADMIN_USERNAME=admin
    - SENSU_BACKEND_CLUSTER_ADMIN_PASSWORD=admin
    image: sensu/sensu:latest

volumes:
  sensu-backend-data:

まとめると、

  • containerd をランタイムとして使うと、volumesで指定したパスのうち、コンテナ内に存在するディレクトリ(ここでは /var/lib)の下に存在しないディレクトリ(マウントポイント)は、直下のディレクトリ(ここでは /var/lib/sensu まで)は作成してくれる
  • それ以上深いディレクトリを指定しても作ってくれなくて、とりあえず新しいボリュームを作成し、存在するディレクトリの一層下までのディレクトリまで作成し、そこにマウントしてしまう(ここでは /var/lib/sensu
  • 存在しない深いディレクトリ(ここでは /var/lib/sensu/sensu-backend/etcd)を指定すると、それもマウントはしてくれるようだが、その上にさらに上記のマウントを重ねてしまうようなので見えないので結局は使えない(マウント情報を見ての想像です)
  • Rancher Desktop でランタイムとして "dockerd" 指定すると、最初に示した YAML で問題なく動く
  • ここの volumes の指定をどのように行うのが正解なのかはよく知らない(わからない)<ドキュメントとか読んでません

という感じです。雑なまとめ。

うーん、Mac 上から VM 層が隠蔽されていると、VM 内を覗けないのでトラブルシューティングしにくいなあ…(やる方法あるのかもしれんけどしらん)

ま、これ以上は特に興味がない個別のプロダクトのお話になるのでこの辺りで終わり!

2022 年やりたいこと

技術ブログだけど、今年やりたいことといえば技術のことよりもそれ以外のことが思い浮かぶなあ。フォロワーさんが書いてるのをみて、一年の初めってのもあるし、歳もひとつとったしということで、書いてみるかなと思って書いてみました。

技術

これまで通りのことをやるくらいかな。昨年は忙しかったし、なんか仕事で色々疲れてあまり新しいことをやろうという気がおこらなかった。今年もあまりやる気が湧いてくる気もしないけど。

  • 連載記事を 2021 年よりはたくさん書きたい
  • 連載記事をまとめて技術書典に出すとか何か形にしたいな
  • linuxcontainers.org の翻訳はこれまで通り
  • コンテナの勉強会を最低 1 回はやりたい
    • けれども何もネタを思いつきません。何か面白そうなテーマが思い浮かんで、話してくれる人が見つかりますように
  • 昨年よりはもう少し新しいコンテナ関連の新技術を調べたい
  • Go とか Rust とか新しい言語やりたいな(昨年 Go はちょっと手をつけたけど結局放置…)
  • 仕事で昨年からまたセキュリティ関連やってるんだけど、まあその辺りをぼちぼちと…(あまり技術によってない感じなので(以下略))

趣味

  • 昨年よりはドラマ(韓国ドラマ)の視聴を増やしたい
  • 昨年よりはちゃんと音楽聴きたい
    • イベント復活したらいきたいですね。昨年は久々に King Crimson でコンサート行きました
  • 韓国語
    • Duolingo と NHKテレビ講座で進めて 10 分程度のヨントンに耐えられるようにしたい(それ以前にコミュニケーション能力に問題あるんだけど :-p)
    • ハングル検定 5 級くらい受けてみたいな
  • 本を読みたいな。買って放置してるやつ多い(歳と共に本を読む集中力がなくなってきた)
  • 久々にメガネを買いたいな(JFReyが好きで、これまで10本ほどヤフオクで買ってます)(2021-01-04追記)

運動

  • 昨年はワクチン接種後以外はほぼ毎日運動をしたので継続したい。内容は変わらずジムに行くか、5km ほどの決まったコースを走るか

まとめ

  • なんか「やる気に満ち溢れてる!」感がないなあ。実現しないんちゃう? :-p

『Infra Study 2nd #2「クラウドネイティブを支えるインフラ技術」』でお話してきました

6/11(金)に Infra Study 2nd #2 ってイベントで登壇しました。そのレポートを会社のテックブログで書きました。

blog.idcf.jp

まあ、参加してない方や、アーカイブ動画を見てない方は、このレポートを読むというよりは、もとのアーカイブ動画を見ましょう、って感じですね。

www.youtube.com

5.11 で追加された OverlayFS の非特権マウント(2)

前回は、OverlayFS の非特権マウントの基本的な部分について説明しました。

ところで OverlayFS はシンプルながらも、より進んだ使い方ができる機能やオプションが存在します。基本的な機能以上の機能を使う場合、OverlayFS は拡張ファイル属性を使います。

例えば連載第18回で説明した「opaque(不透明)ディレクトリ」機能や、以前のブログエントリーで説明したredirect_dir機能などです。

しかし拡張ファイル属性で、この trusted で始まる属性(trusted名前空間)を使う場合は特権が必要であり、当然 User Namespace 内の root ではこの属性を使用できません。このような場合、代わりに自由に定義して使える属性(名前空間)として user が存在します1

OverlayFS でも、この機能を使うように実装されており、trusted の代わりに user を使う場合は、マウントオプションとして userxattr を指定してマウントします。この場合、trusted.overlay.* ではなく user.overlay.* を使うようになります。

非特権の場合の拡張ファイル属性

この拡張ファイル属性の動きを連載で説明した「opaque(不透明)ディレクトリ」を使って説明しましょう。この機能を使うと lowerdir に指定した下層側のディレクトリの内容が見えなくなります。

opaqueディレクトリを使いたい場合、拡張ファイル属性 trusted.overlay.opaquey という値を入れます。非特権 OverlayFS の場合は、この代わりに user.overlay.opaque を使うわけです

この機能の動きを見るための環境を作成しましょう。

$ mkdir lower upper work overlay
$ mkdir {lower,upper}/opaquetest
$ touch lower/opaquetest/testfile_lower upper/opaquetest/testfile_upper

これまでの実行例と同様に lowerupperworkoverlay というディレクトリを作成し、lowerupper の両方のディレクトリに opaquetest というディレクトリを作成します(連載の例と同じです)。そして lowerupper 配下の opaquetest ディレクトリ内にそれぞれ testfile_lowertestfile_upper というファイルを置きます。

この環境で普通に OverlayFS マウントを行うと、次のように見えるはずです。

# tree overlay/
overlay/
└── opaquetest
    ├── testfile_lower
    └── testfile_upper

1 directory, 2 files

userxattr オプションを使わない場合

まずは userxattr オプションを指定せずに OverlayFS マウントを行い、動きを見てみましょう。当然、期待する動きはしないはずです。

# setfattr -n "user.overlay.opaque" -v "y" upper/opaquetest/ (拡張ファイル属性を設定する)
# getfattr -n "user.overlay.opaque"  upper/opaquetest/ (拡張ファイル属性が設定されたのを確認)
# file: upper/opaquetest/
user.overlay.opaque="y"

# mount -t overlay -o lowerdir=lower,upperdir=upper,workdir=work overlay overlay
# tree overlay/ (拡張ファイル属性を設定したものの、特にOverlayFSの動きに変化はない)
overlay/
└── opaquetest
    ├── testfile_lower
    └── testfile_upper

1 directory, 2 files
# umount overlay

上記の例のように user.overlay.opaque 属性を設定しても、特に先ほどの普通に OverlayFS マウントを行ったときと動きに変化はありません。

userxattr オプションを追加してマウントした場合

それでは OverlayFS マウントを行う際に userxattr オプションを追加してみましょう。

# getfattr -n "user.overlay.opaque"  upper/opaquetest/ (拡張属性が設定されているのを確認)
# file: upper/opaquetest/
user.overlay.opaque="y"

# mount -t overlay -o lowerdir=lower,upperdir=upper,workdir=work,userxattr overlay overlay (userxattrオプションを指定してマウント)
# tree lower upper (lower, upper以下のopaquetestディレクトリにはそれぞれファイルが存在する)
lower
└── opaquetest
    └── testfile_lower
upper
└── opaquetest
    └── testfile_upper

2 directories, 2 files
# tree overlay/ (overlayディレクトリを見ると上層側に置いたファイルしか見えない)
overlay/
└── opaquetest
    └── testfile_upper

1 directory, 1 file

このように上層側のファイルしか見えません。opaque ディレクトリの機能が働いていることがわかります。

非特権マウントの場合に使えない機能

以上のように、非特権マウントの場合は trusted.overlay の代わりに user.overlay を使って OverlayFS 独自の機能を実現します。

しかし非特権の場合、特権を持っているケースと同じように機能を使うと危険なケースがあります(特権の取得につながるとか)。このような機能については非特権の場合には使えないようになっています。

この機能のひとつが、以前ブログで紹介したredirect_dir機能 です。

次のように、この機能を使うためにオプションを指定してマウントしようとするとエラーになります。

$ unshare --user --map-root-user --mount
# mount -t overlay -o lowerdir=lower,upperdir=upper,workdir=work,userxattr,redirect_dir=on overlay overlay
mount: /home/karma/tmp/overlay: wrong fs type, bad option, bad superblock on overlay, missing codepage or helper program, or other error.

当然ですが、redirect_dir=off とするとマウントできます。

# mount -t overlay -o lowerdir=lower,upperdir=upper,workdir=work,userxattr,redirect_dir=off overlay overlay
# grep overlay /proc/self/mountinfo 
119 109 0:62 / /home/karma/tmp/overlay rw,relatime - overlay overlay rw,lowerdir=lower,upperdir=upper,workdir=work,redirect_dir=off,index=off,metacopy=off

他にも非特権の場合、metacopy 機能が使えないようです(こちらの機能は私はまだ調べていないので詳細はまたの機会に)。


  1. ここで使っている名前空間は拡張ファイル属性の名前空間でコンテナで使う名前空間ではありません。

5.11 で追加された OverlayFS の非特権マウント(1)

5.11 カーネルで overlayfs に大きな変更があったようで、久々にカーネルの新しい機能を試してみました。

とは言っても、結果だけ言うとすぐに終わってしまうので、すごいことをやったように見せかけるために、復習したりして順に説明していきましょう。時間のない方は最後の方だけ見れば良いです。

OverlayFS とは

Union Filesystem の実装の1つで、ディレクトリを重ね合わせて1つのディレクトリツリーを構成できます。Docker なんかではおなじみの機能ですね。おなじみの機能とはいえ、実際に直接マウントして動きを見たことがない方も多いかと思います。そこでまずは動きを簡単に見てみましょう。

重ね合わせるということで、下層側ディレクトリ、上層側ディレクトリを重ね合わせて、マウントポイント以下に見せます。他にワーク用の workdir として指定するディレクトリが必要です。

次の例では

  • 下層用ディレクトリとして lower
  • 上昇用ディレクトリとして upper
  • workdirとして work
  • マウントポイントとして overlay

というディレクトリを準備しています。lowerupper の中にはディレクトリとファイルを作成しておき、マウント後に overlay 以下にそれらのファイル・ディレクトリが見えることが確認できます。

$ mkdir lower upper work overlay # overlayfs用のディレクトリの作成
$ mkdir lower/lowerdir upper/upperdir # 下層、上層それぞれにディレクトリ作成
$ touch lower/lowerdir/lowfile upper/upperdir/upfile # ディレクトリ内にファイル作成
$ sudo mount -t overlay -o lowerdir=lower,upperdir=upper,workdir=work overlay overlay
$ find overlay/
overlay/
overlay/lowerdir
overlay/lowerdir/lowfile
overlay/upperdir
overlay/upperdir/upfile
$ grep overlay /proc/$$/mountinfo 
68 33 0:67 / /home/karma/tmp/overlay rw,relatime - overlay overlay rw,lowerdir=lower,upperdir=upper,workdir=work

詳しくは連載記事 gihyo.jp や、カーネル付属文書 www.kernel.org をご覧ください。

他に関連記事としてこんな記事も書いています。

tenforward.hatenablog.com

5.11 カーネルで行われた非特権マウントのための変更と FS_USERNS_MOUNT

User Namespace内は、Namespace内では特権ユーザー、Namespace外では一般ユーザーという UID/GIDマッピングができる機能です。Namespace 内では特権を持つユーザーであっても、実際は特権を持たないユーザーでの処理がされているため、当然ながら一般的には User Namespace 内ではマウント操作はできません。

User Namespace について詳しくは連載の次の記事をご覧ください。

gihyo.jp

しかし、一部のファイルシステムについては、従来から User Namespace 内でマウントできました。例えば、コンテナ内で /proc や tmpfs などをマウントする操作は普通に行われている操作ではないかと思います。

このような User Namespace 内でファイルシステムをマウントできる機能は、非常に簡単な定義を行うだけで使えます。このためのファイルシステムに定義する定数が include/linux/fs.h に定義されています。

struct file_system_type {
        const char *name;
        int fs_flags;
#define FS_REQUIRES_DEV         1 
#define FS_BINARY_MOUNTDATA     2
#define FS_HAS_SUBTYPE          4
#define FS_USERNS_MOUNT         8       /* Can be mounted by userns root */
#define FS_DISALLOW_NOTIFY_PERM 16      /* Disable fanotify permission events */
  : (snip)

この FS_USERNS_MOUNT というのがそれで、ファイルシステムを実装する際にこの値を fs_flags に設定すると、コメントにあるように User Namespace 内の root が、そのファイルシステムをマウントできるわけです。

実は LXC 方面で使っていたため、Ubuntuカーネルにはこれまでも User Namespace 内で overlayfs をマウントするパッチが適用されていました(筆者がメンテナをつとめる Plamo Linux でも一時期適用されていたはずです)。

今回(5.11 カーネル)の OverlayFS の非特権マウントのパッチも非常に単純で、次のようなパッチです。これまで Ubuntu カーネルに適用されていたパッチも同じものです。

--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -2096,6 +2096,7 @@ static struct dentry *ovl_mount(struct file_system_type *fs_type, int flags,
 static struct file_system_type ovl_fs_type = {
    .owner      = THIS_MODULE,
    .name       = "overlay",
+   .fs_flags   = FS_USERNS_MOUNT,
    .mount      = ovl_mount,
    .kill_sb    = kill_anon_super,
 };

ovl: unprivieged mounts

今回の OverlayFS に対するパッチは 10 個ほどのパッチとなっていますが、「非特権マウント」のために必要な変更は上記の変更だけです。他はより安全に処理を行うための修正のようで、今回だけでなく 5.8 でも変更が行われていたようです。

5.11 カーネルでの非特権 OverlayFS マウント

それでは先の例と同じディレクトリ、ファイルを使って非特権 OverlayFS を試してみましょう。使用するカーネルは 5.11.5 です。

$ uname -r
5.11.5-plamo64

「非特権」と言っても、先に説明したとおり「User Namespace 内の root がマウントできる」ということですので、unshare コマンドで User Namespace を作成して試します。(いずれにせよ mount コマンドは root でないと実行が失敗するようになってます)

ただ、ここで User Namespace だけを作ってもマウントは失敗します。

$ unshare --user --map-root-user
# mount -t overlay -o lowerdir=lower,upperdir=upper,workdir=work overlay overlay
mount: /home/karma/tmp/overlay: permission denied. (失敗した)

これは Mount Namespace も元の Namespace とも独立している必要があるためです。

そこで次の例では unshare コマンドに --mount も指定して User/Mount Namespace を作成してみましょう。--map-root-user は unshare を実行するユーザーと User Namespace 内の root をマッピングするオプションです。次の例だと元の Namespace の UID: 1000 のユーザーと作成する Namespace 内の UID:0 をマッピングするということです。

$ id -u (現在のユーザーは UID:1000)
1000
$ unshare --user --map-root-user --mount (User Namespace と Mount Namespace を作成する)
# mount -t overlay -o lowerdir=lower,upperdir=upper,workdir=work overlay overlay
# grep overlay /proc/self/mountinfo (マウント情報を確認する)
119 109 0:62 / /home/karma/tmp/overlay rw,relatime - overlay overlay rw,lowerdir=lower,upperdir=upper,workdir=work,index=off,metacopy=off
# find overlay/ (重ね合わせた状態でマウントできている)
overlay/
overlay/lowerdir
overlay/lowerdir/lowfile
overlay/upperdir
overlay/upperdir/upfile

マウントが成功しましたね。所有権も見ておきましょう。

# ls -l overlay/
合計 0
drwxr-xr-x 1 root root 14  314日  21:07 lowerdir/
drwxr-xr-x 1 root root 12  314日  21:07 upperdir/
# ls -l overlay/*
overlay/lowerdir:
合計 0
-rw-r--r-- 1 root root 0  314日  21:07 lowfile

overlay/upperdir:
合計 0
-rw-r--r-- 1 root root 0  314日  21:07 upfile

これらのファイルは元の Namespace のユーザー(UID: 1000)権限で作成しましたので、ちゃんと User Namespace 内でマウントしてもマッピング先のユーザー(UID: 0=root)の所有権になっています。

5.11 より前のカーネルでの実行例

一応、比較のために 5.11 より前のバージョンのカーネルで非特権マウントができないことも確認しておきましょう。ちょっと古いのですが、手元にあった 5.2 カーネルの環境で試してみました。

$ uname -r
5.2.1-plamo64
$ id -u
1000
$ unshare --mount --user --map-root-user
# mount -t overlay -o lowerdir=lower,upperdir=upper,workdir=work overlay overlay
mount: /home/karma/tmp/overlay: permission denied.

同様に実行してみました。失敗しましたね。

(つづく)