差分
このページの2つのバージョン間の差分を表示します。
両方とも前のリビジョン 前のリビジョン 次のリビジョン | 前のリビジョン | ||
linux:kernel:namespace:pid_namespaces [2013/08/06 07:25] – tenforward | linux:kernel:namespace:pid_namespaces [2013/08/07 12:06] (現在) – [/proc/PID と PID 名前空間] tenforward | ||
---|---|---|---|
行 51: | 行 51: | ||
pidns_init_sleep の出力の最後の行の説明のため,childFunc() 関数の実装の議論の時にスキップした部分のコードに戻る必要がある. | pidns_init_sleep の出力の最後の行の説明のため,childFunc() 関数の実装の議論の時にスキップした部分のコードに戻る必要がある. | ||
+ | ===== /proc/PID と PID 名前空間 ===== | ||
+ | |||
+ | Linux システムのプロセスはそれぞれ /proc/PID ディレクトリを持っている.ここにはプロセスに関係する様々な情報を含む擬似ファイルを含む.この配置は直接 PID 名前空間のモデルに置き換えることができる.PID 名前空間の中では,/ | ||
+ | |||
+ | しかし,目に見える PID 名前空間に一致する /proc/PID ディレクトリを作成するために,proc ファイルシステム (短縮して " | ||
+ | |||
+ | < | ||
+ | # mount -t proc proc / | ||
+ | </ | ||
+ | |||
+ | もうひとつの方法として,procfs は mount() システムコールを使ってマウントすることも可能である.プログラムの childFunc() 関数内から以下のようにして. | ||
+ | |||
+ | <code c> | ||
+ | mkdir(mount_point, | ||
+ | mount(" | ||
+ | printf(" | ||
+ | </ | ||
+ | |||
+ | mount_point 変数は pidns_init_sleep 起動時のコマンドライン引数で与えられる文字列で初期化される. | ||
+ | |||
+ | 前の pidns_init_sleep を実行したサンプルのシェルセッションでは,新しい procfs として /proc2 をマウントした.現実の利用では,説明したどちらかのテクニックを使って,procfs は (必要であれば) 通常は普通の場所にマウントされるだろう.しかし,我々のデモの間 /proc2 に procfs をマウントすることは,システムの他のプロセスに問題が生じるのを防ぐ簡単な方法を提供してくれる.つまり,これらのプログラムは我々のテストプログラムと同じ名前空間にあるので,/ | ||
+ | |||
+ | それゆえ,我々のシェルセッション内で /proc にマウントされた procfs は,親の PID 名前空間から見えるプロセスに対する PID サブディレクトリを示し,一方で /proc にマウントされた procfs は,子供の PID 名前空間に存在するプロセスに対する PID サブディレクトリを示す.ちなみに,子供の PID 名前空間内のプロセスが /proc マウントポイントで見える PID ディレクトリで見えるにも関わらず,これらの PID は子供の PID 名前空間内のプロセスに対しては意味がないという事は重要な事である.これらの子プロセスから呼ばれたシステムコールは,それらが属する PID 名前空間のコンテキスト内の PID として解釈されるからである. | ||
+ | |||
+ | もし ps のような様々なツールが,子供の PID 名前空間内でも正しく動くことを期待するのであれば,伝統的な /proc マウントポイントにマウントされた procfs を持つことは必要なことである.なぜならこれらのツールは /proc で見つかる情報に依存しているからである.親の PID 名前空間が使う /proc マウントポイントに影響を与えずにこれを達成する方法は 2 つある.1 つ目は,もし子プロセスが CLONE_NEWNS フラグを使って作られているのであれば,子供はシステムの他とは異なるマウント名前空間にいる事になる.この場合,新しい procfs を /proc にマウントしても,問題を引き起こすことはない.他の方法として,CLONE_NEWNS フラグを使う代わりに,子供は chroot() を使って root ディレクトリを変更し,/ | ||
+ | |||
+ | pidns_init_sleep を実行しているシェルセッションに戻ろう.プログラムを停止させ,親の名前空間のコンテキスト内で親子のプロセスの詳細をいくつか観察するために ps コマンドを使おう. | ||
+ | |||
+ | < | ||
+ | ^Z Stop the program, placing in background | ||
+ | [1]+ Stopped | ||
+ | # ps -C sleep -C pidns_init_sleep -o "pid ppid stat cmd" | ||
+ | PID PPID STAT CMD | ||
+ | 27655 27090 T ./ | ||
+ | 27656 27655 S sleep 600 | ||
+ | </ | ||
+ | |||
+ | 最後の行の " | ||
+ | |||
+ | readlink コマンドを使って,/ | ||
+ | |||
+ | < | ||
+ | # readlink / | ||
+ | pid: | ||
+ | # readlink / | ||
+ | pid: | ||
+ | </ | ||
+ | |||
+ | この時点で,新しい PID 名前空間内のプロセスに関する情報を得るのに,新しくマウントした procfs を使うこともできる.まず,以下のようなコマンドで名前空間内の PID のリストを取得できる. | ||
+ | |||
+ | < | ||
+ | # ls -d / | ||
+ | /proc2/1 | ||
+ | </ | ||
+ | |||
+ | 以上のように,PID 名前空間はひとつのプロセスだけを含んでおり,その名前空間での PID は 1 である.また,/ | ||
+ | |||
+ | < | ||
+ | # cat / | ||
+ | Name: sleep | ||
+ | Pid: 1 | ||
+ | PPid: 0 | ||
+ | </ | ||
+ | |||
+ | ファイルの PPid フィールドは 0 であり,子供に対する親プロセスの ID が 0 であると報告した getppid() の結果と一致する. | ||
+ | |||
+ | ===== ネストした PID 名前空間 ===== | ||
+ | |||
+ | 先に述べたように,PID 名前空間は親子関係で階層構造的にネストする.PID 名前空間内では,同じ名前空間内の他の全てのプロセスを見ることができるだけでなく,子孫の名前空間のメンバーの全てのプロセスも見る (" | ||
+ | |||
+ | プロセスは,属している PID 名前空間から始まり,root PID 名前空間までに属する PID 名前空間の階層構造のぞれぞれのレイヤーごとに 1 つ PID を持つだろう.getpid() を呼ぶと,プロセスが属する名前空間に紐付いた PID が常に返ってくる. | ||
+ | |||
+ | プロセスが,そのプロセスが見える名前空間内のそれぞれで異なる PID を持っていることを示すために [[http:// | ||
+ | |||
+ | プログラムはネストされた PID 名前空間内で一連の子プロセスを再帰的に作成する.プログラムを起動する際に,何個の子供と PID 名前空間を作るのかをコマンドライン引数で指定する. | ||
+ | |||
+ | < | ||
+ | # ./ | ||
+ | </ | ||
+ | |||
+ | 新しい子プロセスを作るのに加えて,それぞれの再帰ステップはユニークに名前が付けられたマウントポイントに procfs をマウントする.再帰の最後に,最後の子供が sleep を実行する.先のコマンドラインは以下のような出力が出る. | ||
+ | |||
+ | < | ||
+ | ^Z Stop the program, placing in background | ||
+ | [1]+ Stopped | ||
+ | # ls -d / | ||
+ | / | ||
+ | # ls -d / | ||
+ | / | ||
+ | # ls -d / | ||
+ | / | ||
+ | # ls -d / | ||
+ | / | ||
+ | # ls -d / | ||
+ | /proc0/1 | ||
+ | </ | ||
+ | |||
+ | 全てを見ることができる名前空間内で,再帰の末尾 (例えば最も深くネストした名前空間内で sleep を実行しているプロセス) でプロセスの PID を見るには grep コマンドが適切だろう. | ||
+ | |||
+ | < | ||
+ | # grep -H ' | ||
+ | / | ||
+ | / | ||
+ | / | ||
+ | / | ||
+ | / | ||
+ | </ | ||
+ | |||
+ | 言い換えると,最も深くネストした PID 名前空間 (/proc0) 内では,sleep を実行しているプロセスは PID 1 を持つ.そして,最も浅い PID 名前空間で作られた名前空間 ((/proc4) では,プロセスは PID 5 を持つ. | ||
+ | |||
+ | もしこの記事で紹介したプログラムを実行した場合,プログラムはマウントポイントとマウントディレクトリをそのままにしていることに注意すること.プログラムが終了した後,以下のようなシェルコマンドが片付けをするのに十分である. | ||
+ | |||
+ | < | ||
+ | # umount /proc? | ||
+ | # rmdir /proc? | ||
+ | </ | ||
+ | |||
+ | ===== 最後に ===== | ||
+ | |||
+ | この記事では,PID 名前空間についてかなり詳しく見た.次の記事では,PID 名前空間での init プロセスについての議論と説明を記載すると共に,PID 名前空間 API の他の詳細についても少し触れる. |