LXC 3.0 新機能の予習
ここ最近、新バージョンリリース時と、ドキュメント(man pages)に更新があったときに翻訳する以外、新しい機能について全く調査していませんでした。
なんとなく見てると LXC 3.0 が近いようですので、どう変わるのかをまとめてみます。
cgroup ドライバの整理
これまで LXC には cgroup 関連のドライバが 3 つ含まれていました。
- cgfs
- cgmanager
- cgfsng
cgfs ドライバはもっとも古くからあるドライバです。今や cgroup は /sys/fs/cgroup
にマウントされますが、昔は特にマウントする場所は決まっておらず、/dev/cgroup
にマウントしたり、/cgroup
にマウントしたりしていました。どこにマウントされるかわからないファイルシステムを検出するロジックなど、今や不要になったロジックが多く含まれています。
cgfs ドライバの機能は cgfsng でカバーされていますので、cgfs ドライバは削除されるようです。
cgmanager ドライバは Ubuntu 14.04 のあたりに導入された cgmanager を使って cgroup を管理するためのドライバでした。カーネルに cgroup namespace が導入された今となっては、cgmanager は不要で、すでに廃止予定のプロジェクトになっていますので、cgmanager ドライバも廃止されます。
テンプレートの整理
LXC 2.x までは、様々なディストリビューション用のコンテナイメージを作成するために、シェルスクリプトで書かれたテンプレートが各ディストリビューションごとに用意されていました。
LXC 3.0 では、ディストリビューション依存のテンプレートが削除されるようです。ただ、バサッと切り捨てるのではなく、lxc-templatesというプロジェクトに分離されました。
LXC プロジェクト配下には、新たに distrobuilder という、イメージを作成するための Go 言語によるツールの開発が始まっています。
distrobuilder
distrobuilder は、
- 最近は、ディストリビューションがクラウド用にイメージを準備していることが多いので、それを取得して LXC/LXD 用のイメージを作成する
- 各ディストリビューションが採用しているパッケージ管理コマンドを使って、従来のように LXC/LXD 用のイメージを作成する
という機能を持っているようです。
現時点では、各ディストリビューションが準備している
- alpine イメージ(alpine-minirootfs-*.tar.gz)
- arch イメージ(archlinux-bootstrap-*-x86_64.tar.gz)
- CentOS イメージ(iso イメージ?)
- Ubuntu イメージ(ubuntu-base--base-.tar.gz)
を使用してイメージを作成する機能と、
- debootstrap
を使用してイメージを作成する機能があるようです。
各種言語バインディングの分離
LXC のソースアーカイブに含まれていた、
は独立したリポジトリに分離されるようです。
pam_cgfs の LXC への移動
ユーザログイン時に、ユーザ用の cgroup を作成するための pam モジュールとして pam_cgfs
が LXCFS で開発されていましたが、LXC 3.0 からは LXC ツリー配下で開発されるようです。
cgroup v2 サポート
cgroup v2 がサポートされたようです。
他にもあるでしょうけど、とりあえずこのあたりで。
参考
- LXC Lands Unified cgroup Hierarchy Support
- On The Way To LXC 3.0: Removal of cgmanager And cgfs cgroup Drivers
- On The Way To LXC 3.0: Splitting Out Templates And Language Bindings
- On The Way To LXC 3.0: Moving The Cgroup Pam Module Into The LXC Tree (Including A Detour About Fully Unprivileged Containers)
GnuPGで鍵取得しようとするとdirmngrに繋がらないと怒られる
単なるメモ。Plamo-7.0 開発中環境でのお話。
gnupg 2.1.19 までは大丈夫なんだけど、gnupg 2.1.23、2.2.0、2.2.1 にすると、dirmngr がうまく動かない… (2.1.20 〜 22 は作ってないので知らない)。
$ gpg --recv-keys (鍵) gpg: connecting dirmngr at '/home/karma/.gnupg/S.dirmngr' failed: IPC connect呼び出しに失敗しました gpg: 鍵サーバからの受信に失敗しました: dirmngrがありません
となる。この時、dirmngr は起動しているけど、
tcp 0 1 10.200.200.232:45602 127.0.0.1:9050 SYN_SENT 27056/dirmngr
のように、どうやら Tor に接続に行っている模様。これコンパイル時に無効化できんの? もしくはデフォルト使わないってできんの?
もちろん dirmngr.conf で使わないように設定すれば使わない。でも Plamo では、システムワイドで dirmngr 起動するわけではなく、ユーザごとに起動することになるので、ユーザの dirmngr.conf にいちいち書かなければならない。
$ cat ~/.gnupg/dirmngr.conf no-use-tor
いや、GnuPG 詳しくないから知らんけど
マニュアルには The default is to use Tor if it is available on startup or after reloading dirmngr.
と書いてある。でも Tor なんて入ってないと思うんだけど…
GnuPGのdirmngrのコード見ると、dirmngr/server.c
で
/* This function returns true if a Tor server is running. The status * is cached for the current connection. */ static int is_tor_running (ctrl_t ctrl) { /* Check whether we can connect to the proxy. */ if (!ctrl || !ctrl->server_local) return 0; /* Ooops. */ if (!ctrl->server_local->tor_state) { assuan_fd_t sock; sock = assuan_sock_connect_byname (NULL, 0, 0, NULL, ASSUAN_SOCK_TOR); if (sock == ASSUAN_INVALID_FD) ctrl->server_local->tor_state = -1; /* Not running. */ else { assuan_sock_close (sock); ctrl->server_local->tor_state = 1; /* Running. */ } } return (ctrl->server_local->tor_state > 0); }
こんな関数がある。ここで tor_state
が 1 になってる?
libassuan を見ると、src/assuan-socket.c
内に
_assuan_sock_connect_byname (assuan_context_t ctx, const char *host, unsigned short port, int reserved, const char *credentials, unsigned int flags) { assuan_fd_t fd; unsigned short socksport; if ((flags & ASSUAN_SOCK_TOR)) socksport = TOR_PORT; else if ((flags & ASSUAN_SOCK_SOCKS)) socksport = SOCKS_PORT; else { gpg_err_set_errno (ENOTSUP); return ASSUAN_INVALID_FD; } if (host && !*host) { /* Error out early on an empty host name. See below. */ gpg_err_set_errno (EINVAL); return ASSUAN_INVALID_FD; } fd = _assuan_sock_new (ctx, AF_INET, SOCK_STREAM, 0); if (fd == ASSUAN_INVALID_FD) return fd; /* For HOST being NULL we pass an empty string which indicates to socks5_connect to stop midway during the proxy negotiation. Note that we can't pass NULL directly as this indicates IP address mode to the called function. */ if (socks5_connect (ctx, fd, socksport, credentials, host? host:"", port, NULL, 0)) { int save_errno = errno; assuan_sock_close (fd); gpg_err_set_errno (save_errno); return ASSUAN_INVALID_FD; } return fd; }
なんて関数がある。よくわからんw
いや、違うな。dirmngr に Tor のオプションを指定すると、オプションが --use-tor
か --no-use-tor
かに関わらず dirmngr はすぐに起動するけど、何も指定しないと起動後 127.0.0.1:9050 へのアクセスをして、だいぶタイムアウトを待った後に、使わない設定で起動するな。dirmngr.conf を準備して、ちゃんと設定しろ、ということかな。なんて不便なソフトウェアだ。
$ strace dirmngr --server --homedir /home/karma/.gnupg -vvv --debug-all :(snip) write(2, "dirmngr[27628]: enabled debug fl"..., 108dirmngr[27628]: enabled debug flags: x509 crypto memory cache memstat hashing ipc dns network lookup extprog) = 108 write(2, "\n", 1 ) = 1 socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3 connect(3, {sa_family=AF_INET, sin_port=htons(9050), sin_addr=inet_addr("127.0.0.1")}, 16 :(↑でだんまり) :(snip)
うん、接続を延々待ってるわ。これで失敗したあとにちゃんと dirmngr は起動して、クライアントからのリクエストに応える。不便すぎて涙出るな。
Linux 4.10 で入った Overlayfs の redirect_dir 機能の動きを軽く追ってみた
ちょっと前にリリースされたカーネルですが、4.10 で overlayfs に変更が入っていましたのでちょっと調べてみました。
Overlayfs についてはこちらをどうぞ (ちょっと古い記事なのでカーネルにマージされる前の仕様も説明しています)。
それとコンテナ勉強会のこの発表資料
- ちょっとOverlayfsの実装、読んでみました (@akachochinさん)
カーネルの変更と準備
4.10の関連するコミットは以下。
- ovl: redirect on rename-dir
- ovl: allow redirect_dir to default to “on”
- ovl: allow setting max size of redirect
- ovl: show redirect_dir mount option
lowerdir側に存在するディレクトリを移動した場合の改良ってところでしょうか。相変わらずパッチも短くて見やすくて変更が追いやすそうですね (あまりちゃんと見てませんが)。
以下は 4.13-rc5 カーネルで試しています。
カーネルの config で Overlayfs: turn on redirect dir feature by default
を “Y” にするとデフォルトで有効になるようです (CONFIG_OVERLAY_FS_REDIRECT_DIR
)。
従来の動き
まずは従来の動きにするように redirect_dir=off
というオプションを与えます。
$ 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,redirect_dir=off > overlayfs overlay/ # マウント
重ね合わされた overlay
ディレクトリの中身はこんな風になります。普通の動きですね。
$ find overlay/
overlay/
overlay/lowerdir
overlay/lowerdir/lowfile
overlay/upperdir
overlay/upperdir/upfile
lowerdir
を移動しましょう。
$ cd overlay $ mv lowerdir lowerdir2 $ ls -F lowerdir2/ upperdir/
ここで下層の lowerdir
と上層の upperdir
の中を覗いてみます。
$ find lower/
lower/
lower/lowerdir
lower/lowerdir/lowfile
Overlayfs は下層側は変化しませんので、これは当たり前。
$ ls -l upper/ 合計 8,192 c--------- 1 root root 0, 0 8月 16日 17:32 lowerdir drwxr-xr-x 2 karma users 4,096 8月 16日 17:29 lowerdir2/ drwxr-xr-x 2 karma users 4,096 8月 16日 17:29 upperdir/
Overlayfs では、削除されたファイルやディレクトリは特別なデバイスファイルになるのでした。lowerdir
は削除された状態になっており、新たに移動先の lowerdir2
が上層に作成されていますね。lowerdir2
内には、元々下層の lowerdir
内に存在していたファイルがコピーされています。
$ ls -l upper/lowerdir2/ 合計 0 -rw-r--r-- 1 karma users 0 8月 16日 17:29 lowfile
ディレクトリ内に多数のファイルやディレクトリがある場合は時間がかかりそうです。
改良後の動き
4.10 で導入された “redirect on rename-dir” という機能を使ってみましょう。
$ sudo mount -t overlay \ > -o lowerdir=lower,upperdir=upper,workdir=work,redirect_dir=on \ > overlayfs overlay
ここでは明示的に redirect_dir=on
としていますが、カーネルの config でこの機能を “Y” にしてあれば、自動的にオンになりますので、これは不要です。
$ find overlay/
overlay/
overlay/lowerdir
overlay/lowerdir/lowfile
overlay/upperdir
overlay/upperdir/upfile
先ほどと同じように下層と上層が重ね合わされた状態になっています。この状態で先ほどと同じようにディレクトリを移動してみましょう。
$ cd overlay/ $ ls lowerdir/ upperdir/ $ mv lowerdir lowerdir2 $ ls lowerdir2/ upperdir/
はい、移動されました。それでは下層と上層のディレクトリ内を覗いてみましょう。
$ ls -l upper/ 合計 12,288 c--------- 1 root root 0, 0 8月 16日 17:35 lowerdir drwxr-xr-x 2 karma users 4,096 8月 16日 17:34 lowerdir2/ drwxr-xr-x 2 karma users 4,096 8月 16日 17:34 upperdir/
これは先ほどと同じですね。移動前の lowerdir
が削除された状態になっており、新たに lowerdir2
が作成されています。この lowerdir2
内を覗いてみましょう。
$ ls -l upper/lowerdir2/ 合計 0 $ ls overlay/lowerdir2/ lowfile
おや? 先ほどは内部のファイルもコピーされていましたが、今回はファイルが存在しません。にもかかわらず、重ね合わせたディレクトリにはちゃんとファイルが存在しますね。下層側を見てみると、
$ ls -l lower/lowerdir/ 合計 0 -rw-r--r-- 1 karma users 0 8月 16日 17:34 lowfile
ファイルが存在しますが、これは従来と変わりありません。
ディレクトリを移動した場合は、中身のファイルは元の下層側のファイルを参照しているようですね。参照先はどうやって調べているのでしょう?
先に紹介したコミットにも、Documentation/filesystems/overlayfs.txt にも書かれてあります。
2. If the "redirect_dir" feature is enabled, then the directory will be copied up (but not the contents). Then the "trusted.overlay.redirect" extended attribute is set to the path of the original location from the root of the overlay. Finally the directory is moved to the new location.
調べてみましょう。
$ sudo getfattr -n trusted.overlay.redirect upper/lowerdir2 # file: upper/lowerdir2 trusted.overlay.redirect="lowerdir"
ここに参照先が保存されていますね。
階層が深くなった時は “he path of the original location from the root of the overlay” ってことだから、マウントポイントからのパスが保存されているのかと思ったら、単なるディレクトリ名でした。まあ追えるからかな。
$ sudo getfattr -n trusted.overlay.redirect upper/lowerdir2/hogehoge2 # file: upper/lowerdir2/hogehoge2 trusted.overlay.redirect="hogehoge"
ちなみに redirect_dir 機能を使って操作された overlayfs (の upperdir) を、redirect_dir 機能をサポートしていないカーネルではマウントできませんので注意しましょう (あまりないか…)。
おまけ
4.10 では、redirect 機能の他に、ディレクトリの移動時の変更がもうひとつ加えられています。xfs の時に効果を発揮するのでしょうか。
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 所有に表示されています。
4.12 で nsfs の見た目がちょっと変わった
4.12 で nsfs に変更が加わってますね。
nsfs ってのは /proc/$PID/ns 以下の、そのプロセスがどの Namespace に所属しているのかを表している特殊なリンクがあるディレクトリです。
4.11 まではこんな感じ。
# ls -l /proc/self/ns total 0 lrwxrwxrwx 1 root root 0 Jul 4 17:14 cgroup -> cgroup:[4026531835] lrwxrwxrwx 1 root root 0 Jul 4 17:14 ipc -> ipc:[4026531839] lrwxrwxrwx 1 root root 0 Jul 4 17:14 mnt -> mnt:[4026531840] lrwxrwxrwx 1 root root 0 Jul 4 17:14 net -> net:[4026531957] lrwxrwxrwx 1 root root 0 Jul 4 17:14 pid -> pid:[4026531836] lrwxrwxrwx 1 root root 0 Jul 4 17:14 user -> user:[4026531837] lrwxrwxrwx 1 root root 0 Jul 4 17:14 uts -> uts:[4026531838]
サポートしている Namespace それぞれの Namespace を表しています。
4.12 は
# ls -l /proc/self/ns total 0 lrwxrwxrwx 1 root root 0 Jul 4 17:00 cgroup -> cgroup:[4026531835] lrwxrwxrwx 1 root root 0 Jul 4 17:00 ipc -> ipc:[4026531839] lrwxrwxrwx 1 root root 0 Jul 4 17:00 mnt -> mnt:[4026532397] lrwxrwxrwx 1 root root 0 Jul 4 17:00 net -> net:[4026531961] lrwxrwxrwx 1 root root 0 Jul 4 17:00 pid -> pid:[4026532399] lrwxrwxrwx 1 root root 0 Jul 4 17:00 pid_for_children -> pid:[4026532399] lrwxrwxrwx 1 root root 0 Jul 4 17:00 user -> user:[4026531837] lrwxrwxrwx 1 root root 0 Jul 4 17:00 uts -> uts:[4026531838]
こんな感じ。pid_for_children
というファイルが加わっています。CRIU 方面で必要だからということのようです (よく知りません)。kernel のコミットでいうと、
- ns: allow ns_entries to have custom symlink content
- pidns: expose task pid_ns_for_children to userspace
これは、PID Namespace だけちょっと特殊な部分があるからでしょうね。この辺りは Masami Ichikawa さんの、
の 28 ページ辺りをご覧になるのがよろしいかと。(nsfs についても 35 ページ辺りに言及があります)
つまり新しいプロセスを生成しない限りは、新しい PID Namespace に所属できません。unshare(2)
とか setns(2)
でも CLONE_NEWPID
は指定できますが、指定した新しい PID Namespace に所属するのはその子プロセスからです。
お気軽コンテナコマンド unshare
コマンドも --pid
だけ指定してもエラーになります。--fork
を同時に指定する必要があります。
ということは、プロセスの状態として、子供用に PID Namespace を持っていながら、自身は元の Namespace に所属しているという状態があるということですね。そういうプロセスの「子供用 PID Namespace を知る」ための機能ということでしょうか。
カーネルの Namespace を実現するための構造体、nsproxy
も
30 struct nsproxy { 31 atomic_t count; 32 struct uts_namespace *uts_ns; 33 struct ipc_namespace *ipc_ns; 34 struct mnt_namespace *mnt_ns; 35 struct pid_namespace *pid_ns_for_children; 36 struct net » *net_ns; 37 struct cgroup_namespace *cgroup_ns; 38 };
という風に pid_namespace *pid_ns_for_children
となってますね。これを表示しているのかな (たぶん)。
試してみました。
# unshare --mount --pid --mount-proc --fork # ls -l /proc/self/ns | grep pid lrwxrwxrwx 1 root root 0 Jul 4 17:27 pid -> pid:[4026532399] lrwxrwxrwx 1 root root 0 Jul 4 17:27 pid_for_children -> pid:[4026532399]
↑は新しい PID Namespace 内で調べてるのでまあこんな感じ。元の PID Namespace から見てみましょう。
# pgrep unshare 5354 # pstree -p 5354 unshare(5354)───bash(5355)
unshare
コマンド (pid: 5354) の子プロセスとして bash
が pid: 5355 で起動していますね。
# ls -l /proc/5354/ns | grep pid lrwxrwxrwx 1 root root 0 7月 4日 17:00 pid -> pid:[4026531836] lrwxrwxrwx 1 root root 0 7月 4日 17:00 pid_for_children -> pid:[4026532399] # ls -l /proc/5355/ns | grep pid lrwxrwxrwx 1 root root 0 7月 4日 17:00 pid -> pid:[4026532399] lrwxrwxrwx 1 root root 0 7月 4日 17:04 pid_for_children -> pid:[4026532399]
というわけで、unshare
コマンド自身の pid_for_children
は、子プロセスの bash
の pid
(PID Namespace) と一致していますね。でも unshare
コマンド自身の pid
(PID Namespace) はそれとは異なります。
というわけで、4.12 でちょっと nsfs に変わったのを調べてみました。(間違いの指摘歓迎!!)
nsproxy まわりについても同じく Ichikawa さんのブログが参考になります
- nsproxyとfork()周りのめも (φ(・・*)ゞ ウーン カーネルとか弄ったりのメモ)