Linux 2.6.24以降には、PIDネームスペースを複数持てるという機能が入っています。(PID = process ID。)
詳しい説明は Process IDs in a multi-namespace world [LWN.net] などに譲りますが、おおまかには、
- cloneシステムコールでプロセスを生成する際、CLONE_NEWPIDというフラグを指定
- すると、新たな「PIDネームスペース」が作られる
- cloneされた子プロセスは新たなPIDネームスペースに所属し、その中でPID=1になる。
- 同時に、親プロセス側のPIDネームスペースでは、そのプロセスに連続したPIDが振られる。
- 結果的に、子プロセスは各空間で1つずつ、計2種類のPIDを持った状態になる。
というような機能です。
分かりにくいので、具体例を出してみます。
1. PID=1000のプロセスがcloneをCLONE_NEWPIDフラグ付きでコール
2. 親プロセスがコピーされ、子プロセスが出来る。
このとき作られるプロセスは、親プロセスの空間では PID=1001、新たな子プロセスの空間では PID=1 に見える。
3. さらに子プロセスが(普通に)forkすると、親プロセスの空間では PID=1002、新たな子プロセスの空間では PID=2 が振られる。
新しいネームスペースからclone with CLONE_NEWPIDをコールすると、さらにツリー状に新しいネームスペースが作られていきます。
実際にプログラムを書いて試してみます。
以下のプログラムでは、clone with CLONE_NEWPIDをコールして新しいPIDネームスペースの子プロセスを作り、シェルをspawnします。
このとき、新たなネームスペース内で/procファイルシステムをマウントし直すようになっています(そうしないと、元のネームスペースの/procが見えるため、psコマンド等が親のネームスペースを表示してしまうためです)。
これでpsコマンドを実行すると、次のように新しいPIDネームスペースが見えます。
% sudo ./newpid_ns child - PID: 1 parent - PID 2832 => 2833 sh-3.2# ps ax PID TTY STAT TIME COMMAND 1 pts/2 S 0:00 ./newpid_ns <= 子プロセス 2 pts/2 R 0:00 /bin/sh <= spawnされたシェル 3 pts/2 R+ 0:00 ps ax <= 実行中のpsコマンド sh-3.2#
新たなネームスペースに属さないプロセスは見えなくなります。
逆に外のネームスペースからpsをコマンドを実行すると、上記のプロセスが異なるPIDで見えることが確認できます。
% ps ax PID TTY STAT TIME COMMAND ... 2832 pts/2 S 0:00 ./newpid_ns <= 親プロセス 2833 pts/2 S 0:00 ./newpid_ns <= 子プロセス(上記の1) 2834 pts/2 S+ 0:00 /bin/sh <= spawnされたシェル(上記の2) ...
この機能に加えて、cgroups機能でメモリ使用量やCPU帯域を制限することで、VMWareやXen,KVM等の仮想化を使うよりも緩やかに、かつchroot jailよりも強力に、OSやリソースを分割して使うことが可能になります。
特に、単一のシステムイメージ(ファイルの配置)で複数の空間を作れるので、複数のユーザにサービスを提供する必要のあるレンタルサーバのような環境では、ソフトウェアのインストールやアップグレードといったメンテナンスコストを下げられるため、有用かもしれません。
以下newpid_ns.cのソースコード。
続きを読む