Linux 名前空間

最終更新: 2021-11-21 04:00:04 +0800 +0800
原文は英語で書かれています。あなたはAI翻訳版を読んでいます。

名前空間は、本来グローバルである名前とリソースのビューを分割します。 各タスクは、サポートされる各タイプについて1つの名前空間インスタンスを持ち、 同じインスタンスに属するタスクは、そのインスタンス固有の同じリソースを認識します。 名前空間だけでは、CPU、メモリ、I/Oの消費量は制限されません。これらのリソース制御は cgroupが提供します。

Linuxは8種類の名前空間を公開しています。Time名前空間はLinux 5.6で追加され、 それ以外のタイプは同リリースより前から存在します。名前空間フラグのバージョン固有の 正確な定義は、 include/uapi/linux/sched.h にあります。

TypeCreation flagIsolated resource
CgroupCLONE_NEWCGROUPCgroupルートのビュー
IPCCLONE_NEWIPCSystem V IPCオブジェクトとPOSIXメッセージキュー
NetworkCLONE_NEWNETネットワークデバイス、プロトコルスタック、ルーティングテーブル、ファイアウォール状態、ポート空間
MountCLONE_NEWNSマウントテーブルとマウント伝播関係
PIDCLONE_NEWPIDプロセスID番号空間とPID 1のセマンティクス
TimeCLONE_NEWTIMEmonotonic clockとboot-time clockのオフセット
UserCLONE_NEWUSERユーザーID・グループIDのマッピング、資格情報、スコープ付きケイパビリティ
UTSCLONE_NEWUTSホスト名とNISドメイン名

初期システムは各タイプのインスタンスを1つずつ持って開始します。名前空間の識別子は、 移植可能でグローバルに意味を持つ32ビットIDではありません。代わりに、 /proc/PID/ns は net:[4026531840] のようなシンボリックリンクとして名前空間の ハンドルを公開します。この番号は、名前空間ファイルシステムにおける、そのカーネル オブジェクトのinodeを識別します。

sh
ls -l /proc/self/ns
lsns
readlink /proc/self/ns/net

名前空間の作成と参加 #

clone(2) と clone3(2) に1つ以上の CLONE_NEW* フラグを渡すと、新しい名前空間内に 子を作成します。unshare(2) は、各名前空間タイプの規則に従い、呼び出し元のタスクに 新しく作成された名前空間を使用させます。PID名前空間とTime名前空間のunshareは、その後 作成される子にだけ影響し、呼び出し元は現在のPID名前空間またはTime名前空間に残ります。 setns(2) は、オープン済みのファイルディスクリプターが参照する名前空間に参加します。 unshare(1) と nsenter(1) は、実験や管理に便利なフロントエンドです。

sh
# New user, mount, and PID namespaces; the child becomes PID 1 in its PID namespace.
unshare --user --map-root-user --mount --pid --fork --mount-proc sh

# Join the mount namespace of an existing process.
sudo nsenter --target "$PID" --mount sh

名前空間の操作は互換的に扱えるものではありません。

  • 新しいPID名前空間は、その後に作成される子に影響します。タスク自身を別のPID名前空間へ 移動させることはできません。そこへ setns() すると、以後の子がその名前空間で可視になります。
  • 新しいマウント名前空間は、最初に呼び出し元のマウントテーブルをコピーします。共有マウント 伝播によって名前空間間でマウントが転送される可能性があるため、コンテナのセットアップでは、 ファイルシステムをマウントする前に、関連するツリーをprivateまたはslaveにすることが一般的です。
  • ネットワーク名前空間は、起動する必要があるloopbackデバイスを備えた状態で開始します。 これに接続する一般的な方法は、vethエンドポイントを名前空間内へ移動することです。
  • User名前空間の作成には、他の名前空間タイプとは異なる資格情報とマッピングの規則があります。 setns() が成功したからといって、ホストの特権が付与されるとは限りません。

カーネルは関連するUser名前空間でケイパビリティを確認し、安全でない遷移を拒否します。 正確なエラー条件は名前空間タイプとカーネルリリースによって異なるため、呼び出し元は システムコールのマニュアルページと対象カーネルのソースを使用してください。

ハンドルとライフタイム #

/proc/PID/ns/<type> は、名前空間ファイルディスクリプターとしてオープンできます。 タスクまたは名前空間ファイルディスクリプターが参照している間、名前空間は存続します。 このエントリのbind mountも参照を保持するため、最後のプロセスが終了した後も、監督プロセスが 名前空間を保持できます。

sh
sudo mkdir -p /run/netns/demo
sudo touch /run/netns/demo
sudo mount --bind /proc/"$PID"/ns/net /run/netns/demo
ip netns exec demo ip link

不要になったbind mountはアンマウントする必要があります。名前空間ハンドルは権限を伴う オブジェクトとして扱ってください。/proc/PID/ns へのアクセスは、/proc の可視性と ptrace形式のアクセスチェックの対象です。また、継承されたディスクリプターによって、受領者が setns() を呼び出せる場合があります。

User名前空間とIDマッピング #

User名前空間は、名前空間内の連続したID範囲を、親User名前空間のIDへマッピングします。 作成者は --map-root-user によって、名前空間内の有効UID 0を取得できることがありますが、 そのIDが、マッピングされていないホストIDやグローバルなホストリソースに対する特権を 自動的に持つわけではありません。

非特権セットアップでは、監督プロセスが通常、uid_map に書き込んだ後、setgroups に deny を書き込み、その後で gid_map に書き込みます。この順序により、マッピングされて いないグループへの遷移を通じてプロセスがグループベースのアクセスを得ることを防ぎます。 マッピング規則は意図的に制限されており、委譲された範囲と newuidmap・newgidmap ヘルパーが、呼び出し元が直接書き込めないマッピングを処理します。

ケイパビリティはUser名前空間を基準に評価されます。子User名前空間内で CAP_SYS_ADMIN を持つプロセスは、その名前空間によって管理される操作、たとえば マウント名前空間の設定を実行できます。しかし、初期User名前空間ではそのケイパビリティを 持ちません。祖先名前空間が所有するカーネルオブジェクト、デバイスアクセス、LSMポリシーは、 依然としてセキュリティ境界を構成します。

コンテナの構成 #

コンテナは、単一の名前空間ではなく、複数の分離機構を組み合わせたものです。実用的な セットアップ順序の一例を示します。

  1. User名前空間を作成し、意図したUID/GIDマッピングを設定します。後続のセットアップに 必要な、名前空間にスコープされたケイパビリティが提供されるためです。
  2. マウント名前空間を作成し、伝播を明示的に変更して、ファイルシステムビューを構築します。
  3. PID名前空間を作成し、意図したinitプロセスをforkし、マウント名前空間から新しい /proc をマウントします。これにより、プロセス情報がPIDビューと一致します。
  4. 必要に応じてNetwork、IPC、UTS、Time、cgroup名前空間を作成または参加し、特権を持つ ホスト側マネージャーからネットワークリンクを設定します。
  5. 実行前にワークロードをホスト管理のcgroupへ配置し、検査と終了処理のために名前空間 ファイルディスクリプターを保持します。

PID 1には、孤立した子をreapし、特殊なシグナル動作を持つため、明示的な処理が必要です。 PID名前空間を作成するだけの最小限のコンテナコマンドでは、ゾンビが残ったり、終了シグナルが 無視されたりする可能性があります。そのためランタイムには、init/reaperまたは同等の スーパービジョン機構が必要です。

マウント名前空間はファイルシステムのマウント可視性を制御します。一方、chroot(2) は パス名解決だけを変更します。意図しないマウントの公開や受信を避けるには、両者を慎重な マウント伝播設定と組み合わせる必要があります。

CgroupとCgroup名前空間 #

Cgroup名前空間は、タスクのcgroupルートへのパスを仮想化します。これにより、タスクが /proc/PID/cgroup や、その名前空間にマウントされたcgroupファイルシステムから読み取る 内容が変わり、内部ワークロードが祖先のパスを発見することを防ぎます。独立したcgroup 階層を作成するものではなく、ホストのCPU、メモリ、I/O、PIDの制限を弱めるものでもありません。

完全な名前空間ABIの説明については、対象リリースの namespaces(7) マニュアルページ と、対象リリースの カーネルソース を併せて参照してください。

コメント

GitHub で閲覧・コメントする(投稿にはログインが必要です)