Linux Namespaces: コンテナを支える「見えない壁」

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

現実:コンテナは「幻想」である

Dockerコンテナ内で ps aux を実行すると、プロセスが3つほどしか表示されないかもしれません。しかし、ホスト側で実行すれば、数百ものプロセスが表示されます。これは魔法ではありません。Linuxカーネルには、実際には「コンテナ」というオブジェクトは存在しません。その代わりに、コンテナはハードウェア制限のための Control Groups (cgroups) と、分離のための Namespaces という2つの特定のカーネル機能でラップされた、ただの標準的なプロセスに過ぎないのです。

Namespacesは、プロセスに自分専用のシステムリソースがあると思い込ませます。これにより, あるコンテナ内のウェブサーバーが別のコンテナ内のデータベースファイルを見ることができないようにする仮想化レイヤーが提供されます。現在、カーネルは8種類の名前空間をサポートしていますが、ここでは現代のコンテナエンジンの根幹をなす6つの名前空間(UTS、PID、NET、Mount、IPC、User)に焦点を当てます。

ラボ環境の構築

Namespacesは apt でインストールするものではありません。バージョン2.6.24以降、Linuxカーネルの一部として組み込まれています。ただし、それらを操作するためのユーザー空間ツールが必要です。Ubuntu 22.04やFedora 38のような最新のディストリビューションを使用している場合、これらのツールはすでに util-linux および iproute2 パッケージに含まれています。

これらのコマンドは、本番環境ではないVMでテストすることをお勧めします。以下の例では、2 vCPUと4GBのRAMを搭載した標準的なt3.mediumインスタンスを使用しました。

# 環境の準備ができているか確認
sudo apt update && sudo apt install util-linux iproute2 -y

# カーネルが必要な名前空間をサポートしているか確認
lsns --version

unshare コマンドは新しい名前空間を作成します。逆に、nsenter は既存の名前空間の中に入るために使用します。unshare を「部屋を作る」こと、nsenter を「ドアを通って中に入る」ことだと考えてください。

主要な6つのNamespaces実践ガイド

1. UTS Namespace(ホスト名の分離)

UTS (UNIX Timesharing System) 名前空間は、最もイメージしやすいものです。これにより、プロセスが独自のホスト名を持つことが可能になります。これは、 $(hostname) コマンドで自身を識別するアプリケーションのインスタンスを複数実行する場合に不可欠です。

# 新しいUTS名前空間でbashシェルを開始
sudo unshare --uts /bin/bash

# このシェル内でのみ名前を変更
hostname isolated-node-01

# 変更を確認
hostname

# 'exit'と入力してホストに戻る。ホストの名前は変更されていない
exit

2. PID Namespace(プロセスIDの分離)

PID名前空間では、プロセスにPID 1が再割り当てされます。これがコンテナのinitシステムの基礎となります。ホスト上では、そのプロセスはPID 10452かもしれませんが、名前空間内ではシステムの最初のプロセスであると認識されます。

# 新しいPID名前空間を作成し、プロセスをフォークする
sudo unshare --pid --fork --mount-proc /bin/bash

# 分離されたプロセスリストを表示
ps aux

--mount-proc フラグは必須です。 ps ツールは /proc ディレクトリからデータを読み取るため、ホスト上の他のプロセスが見えないように、プライベートな /proc をマウントする必要があるからです。

3. Network Namespace(スタックの分離)

Network名前空間は、独自のIPアドレスやルーティングテーブルを含むプライベートなネットワーキングスタックを提供します。Ubuntu 22.04サーバーでのテストでは、マイクロサービスをそれぞれのNET名前空間に分離することで、複数のサービスがポート8080にバインドしようとしても、ポートの競合をゼロに抑えることができました。

この分離されたスタックをインターネットに接続するには、仮想イーサネット (veth) ペアを使用します:

# ウェブサーバー用の名前空間を作成
sudo ip netns add web-ns

# 仮想の「ケーブル」(vethペア)を作成
sudo ip link add veth-host type veth peer name veth-child

# 片方を名前空間に差し込む
sudo ip link set veth-child netns web-ns

# IPを割り当ててプライベートな10.0.0.0/24サブネットを作成
sudo ip addr add 10.0.0.1/24 dev veth-host
sudo ip link set veth-host up

# 内部インターフェースを設定
sudo ip netns exec web-ns ip addr add 10.0.0.2/24 dev veth-child
sudo ip netns exec web-ns ip link set veth-child up

# ホストから「コンテナ」にpingを送信
ping -c 2 10.0.0.2

4. Mount Namespace(ファイルシステムの分離)

Mount名前空間は、2002年に最初に追加されたタイプです。これにより、ホストに影響を与えることなく、プロセスがファイルシステムをマウントまたはアンマウントできるようになります。Dockerはこれを利用して、コンテナのルートファイルシステム (rootfs) を一時的なレイヤーとしてマウントし、ホストの /etc/mtab が汚れないようにしています。

5. IPC Namespace(プロセス間通信)

IPC名前空間は、System V IPCオブジェクトやPOSIXメッセージキューを分離します。これにより、あるコンテナ内のプロセスが別のコンテナの共有メモリセグメントに誤ってアクセスするのを防ぎます。これは、異なるユーザーが同じカーネルを共有するマルチテナント環境において、重要なセキュリティの壁として機能します。

6. User Namespace(セキュリティと権限)

これはセキュリティ上の大きな利点です。User名前空間を使用すると、ホスト上では標準的な低権限ユーザー(UID 1000)のままでありながら、名前空間内ではルート権限(UID 0)を持つことができます。攻撃者がコンテナから脱出したとしても、ホスト上では管理権限を持たない状態になります。

# 現在のユーザーを新しい名前空間内のルートにマップする
unshare --user --map-root-user /bin/bash

# 自分のIDを確認。uid=0(root)と表示されるはず
id

名前空間の監視とデバッグ

複数の名前空間を管理するのは混乱を招くことがあります。私は本番ノードで何が動いているかを把握するために、3つの特定のテクニックを使用しています。

1. すべてのアクティブな名前空間をリスト表示する

lsns コマンドは、システムを監査する最も速い方法です。すべてのアクティブな名前空間、そのタイプ、およびそれを所有するプロセスのPIDを表示します。

sudo lsns

2. /proc 経由での調査

すべてのプロセスには ns ディレクトリがあります。2つのプロセスがネットワークスタックを共有している疑いがある場合は、それらのinode番号を確認してください。番号が一致すれば、それらは同じ名前空間にあります。

# 1234を対象のPIDに置き換えてください
ls -l /proc/1234/ns

3. 実行中の名前空間に入る

コンテナのネットワークに不具合がある場合は、 nsenter を使用してその名前空間に入り、 tcpdumpip addr などの診断ツールを実行します。

# 特定のプロセスのネットワーク名前空間に入る
sudo nsenter -t 1234 --net /bin/bash

プロからのアドバイス: ip netns add を使用して、ネットワーク名前空間には常に分かりやすい名前を付けてください。クイックテストには unshare で十分ですが、名前付きの名前空間の方がクリーンアップが格段に容易です。私はラボセッションの後、未使用のvethペアを削除し、ホストシステム上の「インターフェースの肥大化」を防ぐために、必ずクリーンアップスクリプトを実行しています。

これらのプリミティブを理解すると、クラウドの見え方が変わります。Dockerはもはや謎のエンジンではなく、これらの標準的なカーネル機能を巧みに操るオーケストレーターです。複雑なKubernetesのCNIの問題をデバッグする場合でも、サンドボックスを強化する場合でも、Namespacesは最も頼りになるツールとなるでしょう。

Share: