- Authors

- Name
- Youngju Kim
- @fjvbn20031
containerdネットワーキングとストレージ
containerdはネットワーキングとストレージを直接実装せず、標準インターフェースを通じて外部プラグインと統合します。この記事ではCNIによるネットワーク構成、ネームスペース管理、ボリュームマウント、デバイスアクセス、セキュリティモジュール統合を分析します。
1. CNI統合
1.1 CNI概要
Container Network Interface(CNI)はコンテナネットワーキングの標準インターフェースです。containerdはCNIプラグインを呼び出してネットワークを構成します。
CNI呼び出しフロー:
kubelet -> containerd(CRI RunPodSandbox)
|
v
ネットワークネームスペース作成
|
v
CNIプラグイン呼び出し
(ADDコマンド)
|
v
IP割り当て、ルーティング設定、インターフェース作成
|
v
結果をcontainerdに返す
1.2 CNI設定
CNI設定ファイル位置:
設定ディレクトリ:/etc/cni/net.d/
バイナリディレクトリ:/opt/cni/bin/
containerd CNI設定(config.toml):
[plugins."io.containerd.grpc.v1.cri".cni]
bin_dir = "/opt/cni/bin"
conf_dir = "/etc/cni/net.d"
max_conf_num = 1
1.3 CNIプラグインチェーン
CNI設定例(10-calico.conflist):
ネットワーク構成はプラグインチェーンで定義:
1. メインプラグイン(calico、cilium、flannelなど):
- ネットワークインターフェース作成
- IP割り当て(IPAM)
- ルーティングルール設定
2. メタプラグイン(bandwidth、portmapなど):
- 帯域幅制限
- ポートマッピング
- ファイアウォールルール
実行順序:
ADD:メイン -> メタプラグイン(順方向)
DEL:メタ -> メインプラグイン(逆方向)
1.4 CNI呼び出し詳細
CNI ADD実行詳細:
1. containerdがネットワークネームスペースパスを決定
/var/run/netns/cni-abc123
2. CNI環境変数設定:
CNI_COMMAND=ADD
CNI_CONTAINERID=abc123
CNI_NETNS=/var/run/netns/cni-abc123
CNI_IFNAME=eth0
CNI_PATH=/opt/cni/bin
3. CNIプラグインバイナリ実行
stdinで設定JSONを渡す
4. プラグインがstdoutで結果を返す:
- 割り当てられたIPアドレス
- ゲートウェイアドレス
- DNS設定
- ルーティング情報
5. containerdが結果を保存
2. ネットワークネームスペース
2.1 ネームスペース作成
Podネットワークネームスペース:
Pod Sandbox作成時:
1. unshare(CLONE_NEWNET)で新しいネットワークネームスペース作成
2. /var/run/netns/にバインドマウントで永続化
3. そのネームスペースでCNIプラグイン実行
4. PodのすべてのコンテナがこのネームスペースをShare
ネームスペース共有:
PauseコンテナがネットワークネームスペースをProperty
Appコンテナが同じネームスペースに参加
-> Pod内コンテナがlocalhostで通信可能
2.2 ネームスペースクリーンアップ
ネームスペースクリーンアップ:
Pod削除時:
1. CNI DELコマンドでネットワークリソース解放
- IPアドレス返却
- インターフェース削除
- ルーティングルール削除
2. /var/run/netns/のバインドマウント解除
3. ネットワークネームスペース自動削除
3. ボリュームマウント
3.1 マウントタイプ
containerdはOCIスペックのマウント構成を通じてボリュームを管理します:
マウントタイプ:
1. bindマウント:
- ホストファイル/ディレクトリをコンテナにマウント
- ホストとコンテナが同一データを共有
- ConfigMap、Secret、emptyDirなどに使用
2. tmpfsマウント:
- メモリベースのファイルシステム
- コンテナ終了時にデータ消滅
- /dev/shm、/runなどに使用
3. 特殊ファイルシステム:
- proc:/proc
- sysfs:/sys
- cgroup:/sys/fs/cgroup
- devpts:/dev/pts
3.2 マウント伝播
マウント伝播(Propagation)オプション:
1. private:
- マウントイベント伝播なし
- デフォルト
2. rprivate:
- 再帰的private
3. shared:
- マウントイベントを双方向伝播
- ホストでマウント -> コンテナでも見える
- コンテナでマウント -> ホストでも見える
4. rshared:
- 再帰的shared
5. slave:
- ホスト -> コンテナ片方向伝播
- ボリュームプラグインに有用
6. rslave:
- 再帰的slave
Kubernetesでの使用:
- MountPropagationフィールドで制御
- CSIドライバーは主にBidirectional(shared)を使用
3.3 CRIボリューム処理
CRIによるボリューム処理:
kubeletがOCIスペックにマウントを追加:
1. emptyDir:
- kubeletがホストにディレクトリ作成
- bindマウントでコンテナに渡す
2. hostPath:
- ホストパスを直接bindマウント
3. ConfigMap/Secret:
- kubeletがtmpfsにデータ作成
- bindマウントでコンテナに渡す
4. PersistentVolumeClaim:
- kubeletがCSIドライバーでボリュームマウント
- マウントされたパスをbindマウントで渡す
containerdの役割:
- kubeletが準備したマウント情報をOCIスペックに反映
- runcが実際のマウントを実行
4. デバイスアクセス
4.1 デバイスマッピング
デバイスアクセスメカニズム:
OCIスペックのdevicesセクション:
linux:
devices:
- path: "/dev/nvidia0"
type: "c"
major: 195
minor: 0
fileMode: 438
uid: 0
gid: 0
cgroupデバイスアクセス制御:
linux:
resources:
devices:
- allow: true
type: "c"
major: 195
access: "rwm"
4.2 GPUサポート
GPUアクセス(NVIDIA):
NVIDIA Container Toolkit統合:
1. nvidia-container-runtime-hook:
- OCIランタイムフックとして動作
- コンテナ起動前に実行
- NVIDIAドライバーライブラリをコンテナにマウント
- GPUデバイスノードをコンテナに追加
2. CDI(Container Device Interface):
- デバイスベンダー中立的標準
- /etc/cdi/にデバイススペック定義
- containerdがCDIスペックを読んでOCIスペックに反映
CDIスペック例:
cdiVersion: "0.5.0"
kind: "nvidia.com/gpu"
devices:
- name: "0"
containerEdits:
deviceNodes:
- path: "/dev/nvidia0"
mounts:
- hostPath: "/usr/lib/x86_64-linux-gnu/libnvidia-ml.so"
containerPath: "/usr/lib/x86_64-linux-gnu/libnvidia-ml.so"
4.3 その他のデバイス
その他のデバイスアクセス:
1. FPGA:
- CDIスペックでFPGAデバイスを公開
- ベンダー別デバイスプラグイン
2. InfiniBand/RDMA:
- /dev/infiniband/*デバイスマッピング
- ネットワークデバイスネームスペース共有
3. シリアル/USB:
- ホストデバイス直接マッピング
- privilegedモードまたは明示的デバイス許可
5. SELinux統合
5.1 SELinuxコンテキスト
SELinuxコンテナセキュリティ:
OCIスペックのSELinux設定:
linux:
mountLabel: "system_u:object_r:container_file_t:s0:c1,c2"
processLabel: "system_u:system_r:container_t:s0:c1,c2"
構成要素:
- user:system_u
- role:system_r(プロセス)/ object_r(ファイル)
- type:container_t(プロセス)/ container_file_t(ファイル)
- level:s0:c1,c2(MCSカテゴリ)
MCS(Multi-Category Security):
- 各コンテナに一意のカテゴリを割り当て
- 他のコンテナのファイルにアクセス不可
- ホストとコンテナ間の分離
5.2 SELinux処理フロー
SELinux適用:
1. kubeletがPodのSELinuxオプションを決定
- securityContext.seLinuxOptions
- 自動MCSラベル割り当て
2. CRIを通じてcontainerdに伝達
- processLabel:プロセスセキュリティコンテキスト
- mountLabel:ファイルセキュリティコンテキスト
3. containerdがOCIスペックに反映
4. runcが実行時に:
- プロセスにSELinuxラベル適用
- rootfsにSELinuxラベル適用
- マウントにSELinuxラベル適用
6. AppArmor統合
6.1 AppArmorプロファイル
AppArmorコンテナセキュリティ:
デフォルトプロファイル:cri-containerd.apparmor.d
主要ルール:
- ファイルシステムアクセス制限
deny /proc/kcore r,
deny /sys/firmware/** r,
- ネットワークアクセス制御
- 能力(capability)制限
- マウント操作制限
プロファイル適用:
OCIスペック:
process:
apparmorProfile: "cri-containerd.apparmor.d"
6.2 カスタムプロファイル
カスタムAppArmorプロファイル:
1. ホストにプロファイルインストール:
/etc/apparmor.d/にプロファイルファイル配置
apparmor_parser -r /etc/apparmor.d/my-profile
2. Podで指定:
annotations:
container.apparmor.security.beta.kubernetes.io/app: localhost/my-profile
3. containerdがOCIスペックに反映:
process:
apparmorProfile: "my-profile"
7. Seccomp統合
7.1 Seccompプロファイル
Seccomp(Secure Computing):
許可/ブロックするシステムコールを定義:
デフォルトアクション:SCMP_ACT_ERRNO(拒否)
許可システムコール例:
- read、write、open、close
- mmap、mprotect、munmap
- socket、connect、accept
- ...
ブロックシステムコール例:
- mount、umount(コンテナ脱出防止)
- reboot
- kexec_load
- ptrace(一部環境)
7.2 Seccomp適用
Seccompプロファイル適用:
1. Kubernetes SecurityContext:
securityContext:
seccompProfile:
type: RuntimeDefault
2. RuntimeDefaultプロファイル:
- containerd/runcデフォルトSeccompプロファイル
- 危険なシステムコールをブロック
- 大半のワークロードに適合
3. カスタムプロファイル:
securityContext:
seccompProfile:
type: Localhost
localhostProfile: "profiles/my-seccomp.json"
8. まとめ
containerdのネットワーキングとストレージは標準インターフェースによる委譲モデルに従います。CNIによるネットワーク構成、OCIスペックによるマウント管理、CDIによるデバイスアクセス、SELinux/AppArmor/Seccompによるセキュリティ分離が核心です。この標準ベースの設計によりcontainerdは多様なネットワーキングソリューションとセキュリティモジュールを柔軟に統合します。