Provided by: manpages-ja_0.5.0.0.20210215+dfsg-1_all
名前
pid_namespaces - Linux PID 名前空間の概要
説明
名前空間の概要については namespaces(7) を参照。 PID 名前空間はプロセス ID 番号空間を分離する。 これは、異なる PID 名前空間のプロセスは同じ PID を持つことができることを意味する。 PID 名前空間を使うことで、コンテナー内のプロセス群 を中断、再開したり、 コンテナー内のプロセスの PID を保持したままコンテナーを新しいホストに 移行したりするといった機能をコンテナーが提供することが可能になる。 新しい PID 名前空間の PID は、 独立したシステムであるかのように、 1 から始まる。 fork(2), vfork(2), clone(2) を呼び出すと、 その名前空間内で一意な PID でプロセスが生成される。 PID 名前空間を使用するには、設定 CONFIG_PID_NS が有効になったカーネルが必要である。 名前空間の init プロセス 新しい名前空間で作成される最初のプロセス (すなわち、CLONE_NEWPID フラグで clone(2) を使っ て作成されたプロセスや、 CLONE_NEWPID フラグで unshare(2) を呼び出した後のプロセスによって 作成された最初のプロセス) は PID 1 を持ち、 そのプロセスはその名前空間の "init" プロセスと なる (init(1) 参照)。 名前空間内でみなしごになった (親プロセスがいなくなった) 子プロセス は、 init(1) ではなくこのプロセスが親プロセスになる (ただし、 同じ PID 名前空間内のその子 プロセスの先祖が、 prctl(2) の PR_SET_CHILD_SUBREAPER コマンドを使って、 自分自身をみなし ごとなった子孫のプロセスの引き取り手になっている場合はこの限りではなく)。 PID 名前空間の "init" プロセスが終了すると、 カーネルはその名前空間の全プロセスを SIGKILL シグナルで終了する。 この動作は、 PID 名前空間の正しい操作のためには "init" プロセスは不可 欠であるという事実を反映したものである。 この場合、 その PID 名前空間へのそれ以降の fork(2) はエラー ENOMEM で失敗する。 "init" プロセスが終了している PID 名前空間に新しいプ ロセスを作成することはできない。 このような状況は、 例えば、 名前空間にいたプロセスに対応 する /proc/[pid]/ns/pid ファイルに対してオープンしたファイルディスクリプターを使って、 "init" プロセスが終了した後にその名前空間に setns(2) を行った場合に起こり得る。 unshare(2) を呼び出した後にも、この状況は起こり得る。 それ以降に fork(2) で作成された最初の子プロセス が終了すると、 それ以降の fork(2) の呼び出しは NOMEM で失敗する。 PID 名前空間の他のメンバーは、 "init" プロセスがシグナルハンドラーを設定したシグナルだけ を、 "init" プロセスに送信することができる。 この制限は特権プロセスに対しても適用される。 この制限により、 PID 名前空間の他のメンバーがうっかり "init" プロセスを殺してしまうのを防 ぐことができる。 同様に、 先祖の名前空間のプロセスは、 "init" プロセスがそのシグナルに対するハンドラーを設 定している場合にのみ、 kill(2) で説明されている通常のアクセス許可のチェックを経た上で、 子 供の PID 名前空間の "init" プロセスにシグナルを送信できる。 (ハンドラー内では、 sigaction(2) に説明がある siginfo_t の si_pid フィールドは 0 になる。) SIGKILL と SIGSTOP は例外として扱われ、 これらのシグナルが先祖の PID 名前空間から送信された場合には強制的に配 送される。 これらのシグナルはどちらも "init" プロセルが捕捉することはできない。 そのた め、これらのシグナルに関連付けられた通常のアクション (それぞれ、プロセスの終了とプロセスの 強制停止) が実行される。 Linux 3.4 以降では、 reboot(2) システムコールを呼び出すと、 シグナルがその名前空間の "init" プロセスに送信される。 詳細は reboot(2) を参照。 ネストされた PID 名前空間 PID 名前空間は入れ子にすることができる。 最初の ("root") PID 名前空間以外の各 PID 名前空間 は親を持つ。 PID 名前空間の親は clone(2) や unshare(2) を使ってその名前空間を作成したプロ セスの PID 名前空間である。 したがって、 PID 名前空間は木構造を構成し、 すべての名前空間は 親を辿って行くと、最終的には root 名前空間に辿り着く。 プロセスは、所属する PID 名前空間の他のプロセスから見える。また、 root PID 名前空間に向か う直径の先祖の各 PID 名前空間のプロセスからも見える。 この場合、「見える」とは、 あるプロ セスが、 他のプロセスがプロセス ID を指定するシステムコールを使う際に操作の対象にできるこ とを意味する。 逆に、子供 PID 名前空間のプロセスから親や先祖の名前空間のプロセスは見えな い。 あるプロセスは自分自身の PID 名前空間とその子孫の名前空間のプロセスだけが見える (例え ば、kill(2) でシグナルを送信したり、 setpriority(2) で nice 値を設定したり、など)。 プロセスは、そのプロセスが見える PID 名前空間の階層の各層においてプロセス ID を一つ持ち、 直接の先祖の名前空間を辿ることで通って root PID 名前空間に至ることができる。 プロセス ID に対して操作を行うシステムコールは、常に、呼び出し元プロセスの PID 名前空間で見えるプロセ ス ID を使って操作を行う。 getpid(2) の呼び出しでは、 常に、 プロセスが作成された名前空間 に関連付けられた PID を返す。 PID 名前空間内のプロセスは名前空間の外部に親プロセスを持つことができる。 例えば、その名前 空間の初期プロセス (すなわち PID 1 を持つ init(1) プロセス) の親プロセスは必然的に別の名前 空間に属すことになる。 同様に、 あるプロセスが setns(2) を使って子プロセスを PID 名前空間 に参加させた場合、 子プロセスは setns(2) の呼び出し元とは異なる PID 名前空間に属す。 子プ ロセスで getppid(2) を呼び出すと 0 が返される。 プロセスは (setns(2) を CLONE_NEWPID で使うなどで) 子供の PID 名前空間に自由に入ることがで きるが、 逆の方向には移動できない。 つまり、 プロセスは先祖の名前空間 (親、親の親など) に 入ることはできない。 PID 名前空間の変更は一方向の操作である。 setns(2) と unshare(2) の動作 PID 名前空間のファイルディスクリプターを指定して setns(2) を呼び出したり、 CLONE_NEWPID フ ラグ付きで unshare(2) を呼び出したりすると、 その結果作成された子プロセスは呼び出し元とは 異なる PID 名前空間に置かれる。 しかし、これらの呼び出しでは呼び出し元プロセスの PID 名前 空間は変更されない。 なぜなら、PID 名前空間を変更してしまうと、 呼び出し元が認識する (getpid() が返す) 自分の PID が変わってしまい、 多くのアプリケーションやライブラリが正しく 動作しなくなるからである。 別の言い方をすると、 あるプロセスがどの PID 名前空間に所属するかは、 そのプロセスが作成さ れたときに決定され、 それ以降は変更されることはない。 いろいろあるが、プロセス間の親子関係 には、PID 名前空間の親子関係がそのまま反映されるということだ。 プロセスの親プロセスは、同 じ名前空間にいるか、もしくは直接の親 PID 名前空間にいるかのいずれかである。 CLONE_NEWPID の他の CLONE_* フラグとの互換性 CLONE_NEWPID はいくつかの他の CLONE_* フラグと組み合わせることができない。 * CLONE_THREAD は、 プロセス内のスレッド間で互いにシグナルを送信できるようにするため、 同 じ PID 名前空間に属している必要がある。 同様に、 プロセス内の全スレッドが proc(5) ファ イルシステムで見える必要がある。 * CLONE_SIGHAND は、同じ PID 名前空間である必要がある。 さもなければ、 シグナルが送信され た際に、シグナルを送信したプロセスのプロセス ID を意味のある形でエンコードすることがで きない (sigaction(2) の siginfo_t 型の説明を参照)。 複数の PID 名前空間に属するプロセス 間で一つのシグナルキューを共有すると、うまく動かなくなる。 * CLONE_VM は、全スレッドが同じ PID 名前空間に属している必要がある。 なぜなら、 コアダン プの観点から見ると、 2 つのプロセスが同じアドレス空間を共有していれば、 これらはスレッ ドであり、コアダンプが一緒に行われるからである。 コアダンプが書き込まれる際に、 各ス レッドの PID がコアダンプに書き込まれる。 もしプロセス ID のいくつかが親 PID 名前空間に 属していたとすると、 プロセス ID の書き込みは意味を持たなくなってしまう。 まとめると、 CLONE_THREAD, CLONE_SIGHAND, CLONE_VM では技術的な要件として PID 名前空間が共 有されている点がある。 (さらに clone(2) では CLONE_THREAD か CLONE_SIGHAND が指定された際 には CLONE_VM が指定されている必要がある点にも注意。) したがって、以下のような順序で呼び出 しを行うと (エラー EINVAL で) 失敗する。 unshare(CLONE_NEWPID); clone(..., CLONE_VM, ...); /* Fails */ setns(fd, CLONE_NEWPID); clone(..., CLONE_VM, ...); /* Fails */ clone(..., CLONE_VM, ...); setns(fd, CLONE_NEWPID); /* Fails */ clone(..., CLONE_VM, ...); unshare(CLONE_NEWPID); /* Fails */ /proc と PID 名前空間 /proc ファイルシステムは、/proc のマウントを行ったプロセスの PID 名前空間で見えるプロセス だけを表示する。 たとえ、 その /proc ファイルシステムが他の名前空間のプロセスから参照され たとしても、そうである。 新しい PID 名前空間を作成した後、 子プロセスが、自身の root ディレクトリを変更し、新しい procfs インスタンスを /proc にマウントするのは ps(1) などのツールが正しく動作するためにも 有用である。 clone(2) の flags 引き数に CLONE_NEWNS も指定されて新しいマウント名前空間が同 時に作成された場合は、 root ディレクトリを変更する必要はない。 新しい procfs インスタンス を /proc にそのままマウントすることができる。 シェルから、コマンドで /proc のマウントを行うには次のようにする。 $ mount -t proc proc /proc パス /proc/self に対して readlink(2) を呼び出すと、 procfs のマウントを行ったプロセスの PID 名前空間におけるプロセス ID が得られる。 これは調査目的でプロセスが他の名前空間で自身 の PID を知りたい場合などに役立つ。 その他 プロセス ID が UNIX ドメインソケット経由で別の PID 名前空間のプロセスに渡される場合 (unix(7) の SCM_CREDENTIALS の説明を参照)、 プロセス ID は受信プロセスの PID 名前空間での 対応する PID 値に翻訳される。
準拠
名前空間は Linux 独自の機能である。
例
user_namespaces(7) 参照。
関連項目
clone(2), setns(2), unshare(2), proc(5), credentials(7), capabilities(7), user_namespaces(7), switch_root(8)
この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.79 の一部 である。プロジェクト の説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。