エラーの内容
securityContext に runAsNonRoot: true を設定したマニフェストを適用したところ、Kubernetes がその場でポッドを拒否しました:
Error: container has runAsNonRoot and image will run as root (pod: "my-app-7d9f8b-xkp2q", container: "app")
ポッドは起動しません。kubectl get pods を実行すると、Error 状態で止まっているか、Pending のまま凍結しています。これは kubelet による強制拒否であり、コンテナのプルや実行すら試みません。部分的な実行もなく、ログも出ず、ただ死んだポッドがあるだけです。
発生原因
runAsNonRoot: true を設定すると、Kubernetes はコンテナが実行される UID を確認します。イメージの USER ディレクティブが存在しないか root(UID 0)に設定されており、securityContext に runAsUser を指定していない場合、kubelet はそれをブロックします。このチェックはコンテナ起動前に実行されるため、毎回クリーンに失敗します。
主に次の 3 つの状況が原因として挙げられます:
- root をデフォルトとするアップストリームイメージ(nginx、redis、python、node)の使用
runAsNonRoot: trueを自動的に注入するクラスター全体の PodSecurity ポリシーまたは OPA/Gatekeeper ルール- セキュリティ強化のために
runAsNonRoot: trueを追加したが、runAsUserと組み合わせるのを忘れた
修正方法 1:SecurityContext に runAsUser を追加する(最速)
使用する非 root UID を Kubernetes に指定します。0 より大きい任意の UID を選択してください — 1000 または 65534(nobody)が一般的な選択肢です:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000 # ← これを追加
runAsGroup: 1000 # 任意だが推奨
fsGroup: 1000 # 任意:ボリュームの所有権用
containers:
- name: app
image: nginx:latest
securityContext:
runAsNonRoot: true
runAsUser: 1000 # コンテナごとに設定することも可能
allowPrivilegeEscalation: false
適用して確認します:
kubectl apply -f deployment.yaml
kubectl get pods -w
**注意:**公式の nginx を含む一部のイメージは、内部でポート 80 にバインドするため root が必要です。非 root UID を強制すると、セキュリティ拒否ではなくパーミッションエラーで起動時にコンテナが失敗します。代わりに非 root 用に作られたイメージを使用してください:nginxinc/nginx-unprivileged はポート 8080 で UID 101 として動作し、この securityContext でそのまま使用できます。
修正方法 2:イメージが実際に使用する UID を確認する
UID を決める前に、イメージが期待する内容を調べましょう。次の 2 つのコマンドを実行します:
# イメージをローカルで実行して実効ユーザーを確認
docker run --rm nginx:latest id
# uid=0(root) gid=0(root) groups=0(root)
# イメージマニフェストを確認
docker inspect nginx:latest | grep -i user
# "User": ""
# 空 = root がデフォルト
すでに非 root ユーザーがいる場合は、その UID を調べて使用します:
docker run --rm your-image:tag id
# uid=1001(appuser) gid=1001(appuser)
# securityContext での設定:
# runAsUser: 1001
修正方法 3:非 root ユーザーを含むイメージを再ビルドする
ユーザーをイメージに組み込んでおけば、この問題に二度と対処する必要はありません。そのイメージを実行するすべてのクラスターで、securityContext のパッチなしに自動的に正しい UID が使用されます:
FROM node:18-slim
# 非 root ユーザーを作成
RUN groupadd --gid 1001 appgroup && \
useradd --uid 1001 --gid appgroup --shell /bin/bash appuser
WORKDIR /app
COPY --chown=appuser:appgroup . .
RUN npm ci --only=production
USER appuser # ← Kubernetes はここを参照する
CMD ["node", "server.js"]
ビルド、プッシュ、マニフェストを更新します:
docker build -t your-registry/my-app:v2 .
docker push your-registry/my-app:v2
マニフェストのイメージタグを更新して適用します。イメージがすでに宣言しているため、securityContext に runAsUser は不要です。
修正の確認
ポッドのステータスを確認し、コンテナ内部から UID を検証します:
# ポッドが Error/Pending ではなく Running になっているはず
kubectl get pods
# セキュリティエラーがないことを確認
kubectl describe pod my-app-xxx
# コンテナに入ってユーザーを確認
kubectl exec -it my-app-xxx -- id
# 期待値:uid=1000 gid=1000 groups=1000
# 簡単な代替方法:
kubectl exec -it my-app-xxx -- whoami
ポッドが実行中で、UID が非ゼロであれば完了です。
クラスターポリシーによるエラーの場合
自分で runAsNonRoot: true を記述していないのに、このエラーが発生することがあります。それはクラスターが強制しているためです — 通常は PodSecurity アドミッションまたは Gatekeeper によるものです。
# 名前空間に PodSecurity ラベルがあるか確認
kubectl get namespace my-namespace -o yaml | grep pod-security
# 出力例:
# pod-security.kubernetes.io/enforce: restricted
restricted PodSecurity 標準は、その名前空間内のすべてのポッドに runAsNonRoot: true を義務付けます。修正方法は同じです — runAsUser を追加するか、イメージを再ビルドします。制約がマニフェストではなくクラスターから来ていることを把握しておく必要があります。
クイックリファレンス
- 最速の修正:
runAsNonRoot: trueと合わせてrunAsUser: 1000を追加する - ポート 80/443 のイメージ: 非特権バリアントに切り替える(例:ポート 8080、UID 101 の
nginxinc/nginx-unprivileged) - カスタムイメージ: Dockerfile に
USER 1001を追加する - 使用する UID: 0 より大きければ何でも可 — 1000、1001、65534 が一般的
- やってはいけないこと: エラーを消すためだけに
runAsNonRoot: trueを削除しない — これには存在する理由がある

