第3章:基本的なコンテナ操作
カーネルパラメータとシステム設定の最適化
必須カーネルパラメータ
# 現在のカーネルパラメータを確認
$ sysctl -a | grep -E 'user.max_user_namespaces|kernel.unprivileged_userns_clone'
user.max_user_namespaces = 0 # デフォルトで無効の場合が多い
kernel.unprivileged_userns_clone = 0 # Debian/Ubuntuのデフォルト
# Rootlessコンテナに必要な設定
$ cat > /etc/sysctl.d/99-rootless.conf << EOF
# ユーザー名前空間の最大数
# 各ユーザーが作成できる名前空間数を制限
user.max_user_namespaces = 15000
# 非特権ユーザーの名前空間作成を許可
kernel.unprivileged_userns_clone = 1
# PIDの最大数(大量コンテナ実行時に必要)
kernel.pid_max = 4194304
# inotify監視の上限(ファイル監視に必要)
fs.inotify.max_user_watches = 524288
fs.inotify.max_user_instances = 512
EOF
$ sysctl -p /etc/sysctl.d/99-rootless.conf
パフォーマンスを左右する設定
# I/Oスケジューラの選択(コンテナワークロード向け)
$ echo 'mq-deadline' > /sys/block/nvme0n1/queue/scheduler
# TCPパラメータの最適化(コンテナ間通信向け)
$ cat > /etc/sysctl.d/99-container-network.conf << EOF
# TIME_WAITソケットの再利用を有効化
net.ipv4.tcp_tw_reuse = 1
# コネクション追跡テーブルのサイズ
net.netfilter.nf_conntrack_max = 131072
# ARPキャッシュの拡大
net.ipv4.neigh.default.gc_thresh1 = 4096
net.ipv4.neigh.default.gc_thresh2 = 8192
net.ipv4.neigh.default.gc_thresh3 = 16384
EOF
3.1 プラットフォーム別最適インストール
RHEL/CentOS/Fedora
# システムパッケージ(最新版、SELinux統合済み)
$ sudo dnf install -y podman podman-docker buildah skopeo
# crunのインストール(runcより高速)
$ sudo dnf install -y crun
$ podman --runtime /usr/bin/crun run alpine echo "test"
# SELinuxコンテキストの確認
$ ps -eZ | grep podman
system_u:system_r:container_runtime_t:s0 12345 ? 00:00:01 podman
Ubuntu/Debian
# Ubuntu 22.04以降の場合(Kubicリポジトリから最新版)
$ echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_$(lsb_release -rs)/ /" | \
sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
$ curl -L "https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_$(lsb_release -rs)/Release.key" | \
sudo apt-key add -
$ sudo apt update
$ sudo apt install -y podman buildah skopeo
# AppArmorプロファイルの確認
$ sudo aa-status | grep podman
/usr/bin/podman (enforce)
バイナリ直接インストール(最新機能利用時)
# 最新バイナリのダウンロード
$ curl -L https://github.com/containers/podman/releases/download/v4.8.0/podman-remote-static-linux_amd64.tar.gz | \
tar xz -C /tmp
$ sudo install -m 755 /tmp/bin/podman /usr/local/bin/podman
# 依存関係のインストール
$ sudo dnf install -y \
conmon \
containers-common \
crun \
fuse-overlayfs \
slirp4netns \
iptables
3.2 Rootlessコンテナの詳細設定
UID/GIDマッピングの設計
# ユーザーIDマッピングの確認
$ id
uid=1000(user) gid=1000(user) groups=1000(user)
$ cat /etc/subuid
user:100000:65536
# 意味: userは100000から65536個のUIDを使用可能
# マッピングの実際の動作
$ podman run --rm alpine cat /proc/self/uid_map
0 1000 1 # コンテナ内UID 0 = ホストUID 1000
1 100000 65536 # コンテナ内UID 1-65536 = ホストUID 100000-165535
# 実際のファイル所有者確認
$ podman run -v /tmp/test:/data alpine touch /data/file
$ ls -ln /tmp/test/file
-rw-r--r-- 1 100000 100000 0 Jan 15 10:00 /tmp/test/file
ストレージドライバーの選択
# 現在のストレージドライバー確認
$ podman info --format '\{\{.Store.GraphDriverName\}\}'
overlay
$ podman info --format '\{\{.Store.GraphOptions\}\}'
overlay.mount_program=/usr/bin/fuse-overlayfs
# パフォーマンス測定
$ time podman pull docker.io/library/ubuntu:22.04
# native overlay (カーネル5.11以降)
real 0m8.234s
# fuse-overlayfs
real 0m12.456s
# vfs (互換性重視)
real 0m25.789s
ネットワーク設定の最適化
# Rootless CNIの設定
$ cat ~/.config/containers/containers.conf
[network]
# CNIプラグインディレクトリ
network_config_dir = "/home/user/.config/cni/net.d"
cni_plugin_dirs = ["/usr/libexec/cni", "/usr/lib/cni"]
# デフォルトネットワーク
default_network = "podman"
# ネットワークバックエンド
network_backend = "cni" # または "netavark" (Podman 4.0+)
# カスタムネットワークの作成
$ podman network create \
--subnet 172.20.0.0/16 \
--gateway 172.20.0.1 \
--ip-range 172.20.1.0/24 \
custom-net
# ネットワーク設定の確認
$ cat ~/.config/cni/net.d/custom-net.conflist | jq .
{
"cniVersion": "0.4.0",
"name": "custom-net",
"plugins": [
{
"type": "bridge",
"bridge": "cni-podman1",
"isGateway": true,
"ipMasq": true,
"hairpinMode": true,
"ipam": {
"type": "host-local",
"routes": [{"dst": "0.0.0.0/0"}],
"ranges": [[
{
"subnet": "172.20.0.0/16",
"gateway": "172.20.0.1",
"rangeStart": "172.20.1.1",
"rangeEnd": "172.20.1.254"
}
]]
}
},
{
"type": "portmap",
"capabilities": {
"portMappings": true
}
},
{
"type": "firewall"
},
{
"type": "tuning"
}
]
}
cgroups v2の詳細設定
# cgroups v2の有効化確認
$ mount | grep cgroup
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime)
# Rootlessでのリソース制限設定
$ podman run --memory 512m --cpus 0.5 alpine sh -c '
echo "Memory limit: $(cat /sys/fs/cgroup/memory.max)";
echo "CPU quota: $(cat /sys/fs/cgroup/cpu.max)"'
Memory limit: 536870912
CPU quota: 50000 100000
# systemdスライスでのcgroup管理
$ systemctl --user status
● user@1000.service - User Manager for UID 1000
Loaded: loaded
Active: active (running)
Main PID: 1234 (systemd)
Status: "Ready"
CGroup: /user.slice/user-1000.slice/user@1000.service
├─session.slice
│ └─podman-12345.scope # Podmanコンテナ
│ ├─12345 /usr/bin/conmon
│ └─12367 /usr/bin/crun
# ユーザー単位でのリソース制限
$ systemctl --user set-property user@1000.service \
MemoryMax=8G CPUQuota=200%
ストレージ最適化設定
# ストレージ設定ファイル
$ cat ~/.config/containers/storage.conf
[storage]
driver = "overlay"
runroot = "/run/user/1000/containers"
graphroot = "/home/user/.local/share/containers/storage"
[storage.options]
# マウントオプション
mount_program = "/usr/bin/fuse-overlayfs"
mountopt = "nodev,metacopy=on"
# イメージストアのサイズ制限
size = "10G"
# パフォーマンスオプション
# skip_mount_home = "true" # ホームディレクトリマウントをスキップ
# ストレージ使用状況の確認
$ podman system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 15 5 2.45GB 1.23GB (50%)
Containers 8 3 123MB 89MB (72%)
Local Volumes 3 2 456MB 123MB (27%)
# ガベージコレクション
$ podman system prune -a --volumes
なぜストレージドライバーの選択が重要か
ストレージドライバーは、コンテナのパフォーマンスと機能に直接影響します:
各ドライバーの特性と用途
# ~/.config/containers/storage.conf
[storage]
driver = "overlay" # なぜoverlayを選ぶのか
# overlay: 最高のパフォーマンス、本番環境推奨
# - Copy-on-Write により効率的なレイヤー管理
# - ハードリンクによる容量節約
# - 高速な起動とビルド
[storage.options.overlay]
# Rootlessの場合はfuse-overlayfsが必要(なぜか)
mount_program = "/usr/bin/fuse-overlayfs"
# → カーネルのoverlayfsはroot権限が必要
# → fuseにより、ユーザー空間で同等機能を実現
# ストレージパスの意味
graphroot = "$HOME/.local/share/containers/storage" # イメージとレイヤー保存先
runroot = "$XDG_RUNTIME_DIR/containers" # 実行時の一時データ(高速なtmpfs推奨)
ストレージクォータ設定の必要性
# なぜクォータが必要か
# - ディスク容量の枯渇を防ぐ
# - マルチユーザー環境での公平性確保
# - 暴走したビルドプロセスからの保護
[storage.options.vfs]
size = "10G" # ユーザーごとの上限設定
3.2.3 レジストリ設定
なぜレジストリ設定をカスタマイズするのか
デフォルトのレジストリ設定では、以下の問題が発生する可能性があります:
- セキュリティ: 信頼できないレジストリからの意図しないプル
- パフォーマンス: 地理的に遠いレジストリへのアクセス
- コンプライアンス: 承認されていないイメージの使用
# /etc/containers/registries.conf
unqualified-search-registries = ["docker.io", "quay.io"]
# → "nginx" のような短縮名で、どのレジストリを検索するか
# → セキュリティのため、信頼できるレジストリのみに限定すべき
[[registry]]
location = "docker.io"
insecure = false # HTTPSを強制(なぜ重要か: 中間者攻撃を防ぐ)
[[registry]]
location = "localhost:5000"
insecure = true # 開発環境のみ許可(本番では絶対に使用しない)
# ミラー設定の効果
[[registry]]
location = "docker.io"
[[registry.mirror]]
location = "mirror.gcr.io" # 地理的に近いミラーで高速化
# → グローバル企業では、各地域にミラーを配置してレイテンシを削減
3.3 ネットワーク設定
3.3.1 CNIプラグイン
基本的なCNI設定
{
"cniVersion": "0.4.0",
"name": "podman",
"plugins": [
{
"type": "bridge",
"bridge": "cni-podman0",
"isGateway": true,
"ipMasq": true,
"hairpinMode": true,
"ipam": {
"type": "host-local",
"routes": [{ "dst": "0.0.0.0/0" }],
"ranges": [
[
{
"subnet": "10.88.0.0/16",
"gateway": "10.88.0.1"
}
]
]
}
},
{
"type": "portmap",
"capabilities": {
"portMappings": true
}
},
{
"type": "firewall"
}
]
}
3.3.2 ファイアウォール統合
firewalldとの連携
# Podman用ゾーン作成
sudo firewall-cmd --permanent --new-zone=containers
sudo firewall-cmd --permanent --zone=containers --add-source=10.88.0.0/16
sudo firewall-cmd --permanent --zone=containers --add-port=80/tcp
sudo firewall-cmd --reload
3.4 セキュリティ設定
3.4.1 SELinux統合
SELinuxコンテキスト
# コンテナ用SELinuxコンテキスト
ls -Z /var/lib/containers
system_u:object_r:container_var_lib_t:s0 /var/lib/containers
# ボリュームマウント時のラベル
podman run -v /host/path:/container/path:Z ... # プライベートラベル
podman run -v /host/path:/container/path:z ... # 共有ラベル
3.4.2 seccomp/AppArmor
seccompプロファイル
{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": [
"SCMP_ARCH_X86_64",
"SCMP_ARCH_X86",
"SCMP_ARCH_X32"
],
"syscalls": [
{
"names": [
"accept",
"accept4",
"access",
"alarm",
"bind",
"brk"
],
"action": "SCMP_ACT_ALLOW"
}
]
}
3.5 パフォーマンスチューニング
3.5.1 システムパラメータ
# /etc/sysctl.d/podman.conf
# ネットワークパフォーマンス
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
# ファイルディスクリプタ
fs.file-max = 1048576
fs.nr_open = 1048576
# メモリ設定
vm.max_map_count = 262144
3.5.2 ストレージ最適化
# オーバーレイファイルシステムの最適化
[storage.options.overlay]
# メタデータの非同期化
skip_sync = true
# レイヤー数の制限
force_mask = "0700"
演習問題
- Rootless Podmanをセットアップし、動作確認してください
- プライベートレジストリを設定し、イメージをプッシュしてください
- カスタムCNI設定を作成し、特定のIPレンジを使用してください
参考資料
エンタープライズ環境での詳細な要件については、エンタープライズ要件詳細ガイドを参照してください。