UID / GID をマッピングする - user namespace
コンテナ内の UID/GID をホスト側の別 UID/GID にマッピングする Linux の機能。これにより「コンテナ内では root、ホストから見ると非 root」を実現し、bind mount のパーミッション問題の根本原因にもなる。
概念図
構文
bash
docker run --user 1000:1000 myapp
dockerd --userns-remap=default実例
明示的に UID/GID 1000 で起動
bash
docker run --rm --user 1000:1000 alpine idデーモンの UID リマップを使う
bash
docker run --rm --userns-remap=default alpine idrootless Podman の UID マッピングを確認
bash
podman unshare cat /proc/self/uid_map概要
User namespace は、コンテナ内の UID / GID をホストの別の UID / GID に対応付けるカーネル機能です。
例えばコンテナ内 UID 0(root)をホスト UID 100000 に割り当てることで、「コンテナでは root として動くが、ホストのファイルシステムから見ると一般ユーザー」という構図が作れます。
Podman のデフォルトと Docker の rootless モードはこの仕組みを使い、ホストの /etc/subuid と /etc/subgid で各ユーザーに割り当てられた UID 範囲(通常 65536 個)をコンテナ用にマッピングします。
rootful Docker でも --userns-remap=default でデーモン全体を remap 化できます。
典型的な用途
- Rootless 運用で「コンテナ内 root」の影響範囲を自分の UID に限定する
- bind mount したホストディレクトリの所有権を合わせるために
--user $(id -u):$(id -g)を指定する - 共有ホストで複数ユーザーがコンテナを使う際、UID を分離してファイル干渉を防ぐ
- Kubernetes で
securityContext.runAsUserを指定し、Pod 内プロセスを非 root にする - Dockerfile の
USER指定と組み合わせ、イメージ側でも非 root をデフォルトにする
コマンド例
# 明示的に UID/GID を指定
docker run --rm --user 1000:1000 -v $PWD:/work -w /work alpine sh
# デーモン全体を remap(daemon.json)
# {
# "userns-remap": "default"
# }
# subuid / subgid の確認
cat /etc/subuid
# alice:100000:65536
# rootless Podman のマッピング
podman unshare cat /proc/self/uid_map
# 0 1000 1
# 1 100000 65536
# Dockerfile で非 root をデフォルトに
# RUN addgroup -S app && adduser -S app -G app
# USER app:app
ベストプラクティス
- イメージ側で非 root ユーザーを用意し、Dockerfile の
USERで指定してから push する - bind mount 前にホスト側ディレクトリの所有者をコンテナ UID に揃えておく(
chown -R 1000:1000 ./data) /etc/subuid//etc/subgidの範囲は 65536 以上を確保し、ネストした namespace でも足りるようにする- Kubernetes では PodSecurity
restrictedに合わせてrunAsNonRoot: trueを必ず有効にする - rootful と rootless を同じホストで混在させる場合、ファイル所有者が非直感的になるためドキュメント化する
注意点
- bind mount の UID ミスマッチはもっともよくあるハマりどころ。コンテナ内 UID 1000 で書いたファイルがホスト側では UID 1000 のまま見えるとは限らない
--userns=hostを指定すると user namespace を無効化し、コンテナ内 root がホスト root と同じになる。セキュリティ的に大きな後退- OverlayFS と user namespace の組み合わせは古いカーネルで制限があり、rootless では fuse-overlayfs が使われ IO が遅くなる
- subuid 範囲が枯渇すると
newuidmap failedで起動失敗する。usermod --add-subuidsで拡張する - Kubernetes では long-lived PV の所有者が runAsUser と合わないと書き込みエラーになる(
fsGroupで補正)
関連トピック
rootless- コンテナランタイムとコンテナ内プロセスを非特権ユーザーで動かす方式。万一コンテナから脱出されてもホスト側で root を奪われない構成にできる。Podman はデフォルト、Docker もオプションで対応。 capabilities- Linux の root 権限を約 40 の細かい能力に分割した仕組み。コンテナランタイムはデフォルトで一部だけを付与し、`--cap-drop` / `--cap-add` で絞り込む。最小権限の原則を徹底するための最重要機能。 --read-only- コンテナのルートファイルシステムを読み取り専用で起動し、書き込みが必要な部分だけ tmpfs や volume に分離する構成。マルウェアの書き込みや改ざんを防ぎ、Immutable Infrastructure を強化する。 