Lỗi Gặp Phải
Bạn áp dụng một manifest có runAsNonRoot: true trong securityContext, và Kubernetes từ chối pod ngay lập tức:
Error: container has runAsNonRoot and image will run as root (pod: "my-app-7d9f8b-xkp2q", container: "app")
Pod không bao giờ khởi động được. kubectl get pods cho thấy nó bị kẹt ở trạng thái Error hoặc đứng yên ở Pending. Đây là lỗi bị kubelet chặn cứng — nó thậm chí không thử pull hay chạy container. Không có quá trình thực thi nào xảy ra, không có log, chỉ là một pod chết hoàn toàn.
Nguyên Nhân
Khi bạn đặt runAsNonRoot: true, Kubernetes kiểm tra UID mà container sẽ chạy với. Nếu chỉ thị USER trong image bị thiếu hoặc được đặt là root (UID 0), và bạn chưa chỉ định runAsUser trong securityContext, kubelet sẽ chặn lại. Việc kiểm tra diễn ra trước khi container khởi động — lỗi ngay, không ngoại lệ.
Ba tình huống thường gây ra lỗi này:
- Sử dụng image upstream (nginx, redis, python, node) mặc định chạy bằng root
- Cluster có chính sách PodSecurity hoặc rule OPA/Gatekeeper tự động inject
runAsNonRoot: true - Bạn thêm
runAsNonRoot: trueđể tăng cường bảo mật nhưng quên đi kèmrunAsUser
Cách Sửa 1: Thêm runAsUser vào SecurityContext (Nhanh Nhất)
Chỉ định cho Kubernetes biết dùng UID non-root nào. Chọn bất kỳ UID nào lớn hơn 0 — 1000 hoặc 65534 (nobody) là các lựa chọn thông dụng:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000 # ← thêm dòng này
runAsGroup: 1000 # tùy chọn nhưng nên có
fsGroup: 1000 # tùy chọn: để phân quyền volume
containers:
- name: app
image: nginx:latest
securityContext:
runAsNonRoot: true
runAsUser: 1000 # có thể đặt riêng cho từng container
allowPrivilegeEscalation: false
Áp dụng và theo dõi:
kubectl apply -f deployment.yaml
kubectl get pods -w
Lưu ý: Một số image — bao gồm nginx chính thức — bind vào cổng 80 nội bộ, điều này yêu cầu quyền root. Ép dùng UID non-root sẽ khiến container thất bại lúc khởi động với lỗi permission, không phải lỗi bảo mật. Hãy dùng image được xây dựng sẵn cho non-root: nginxinc/nginx-unprivileged chạy trên cổng 8080 với UID 101 và hoạt động tốt với securityContext này.
Cách Sửa 2: Kiểm Tra UID Thực Tế Của Image
Trước khi chốt một UID, hãy xem image yêu cầu gì. Chạy hai lệnh sau:
# Chạy image cục bộ và kiểm tra user hiệu lực
docker run --rm nginx:latest id
# uid=0(root) gid=0(root) groups=0(root)
# Kiểm tra manifest của image
docker inspect nginx:latest | grep -i user
# "User": ""
# Để trống = mặc định là root
Image đã có non-root user? Tìm UID của nó và dùng luôn:
docker run --rm your-image:tag id
# uid=1001(appuser) gid=1001(appuser)
# Sau đó trong securityContext:
# runAsUser: 1001
Cách Sửa 3: Rebuild Image Với Non-Root User
Đưa user vào thẳng image và bạn sẽ không bao giờ phải xử lý vấn đề này nữa. Mọi cluster chạy image đó đều tự động có đúng UID, không cần vá securityContext:
FROM node:18-slim
# Tạo non-root user
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 # ← đây là thứ Kubernetes đọc
CMD ["node", "server.js"]
Build, push và cập nhật manifest:
docker build -t your-registry/my-app:v2 .
docker push your-registry/my-app:v2
Cập nhật image tag trong manifest và áp dụng. Không cần runAsUser trong securityContext nữa — image đã khai báo sẵn rồi.
Xác Nhận Đã Sửa Thành Công
Kiểm tra trạng thái pod, sau đó xác nhận UID từ bên trong container:
# Pod phải ở trạng thái Running, không phải Error/Pending
kubectl get pods
# Describe để xác nhận không còn lỗi bảo mật
kubectl describe pod my-app-xxx
# Exec vào và kiểm tra user
kubectl exec -it my-app-xxx -- id
# Kết quả mong đợi: uid=1000 gid=1000 groups=1000
# Cách nhanh hơn:
kubectl exec -it my-app-xxx -- whoami
Pod đang chạy, UID khác 0 — bạn đã xong.
Nếu Lỗi Đến Từ Chính Sách Cluster
Đôi khi bạn gặp lỗi này mà không hề tự viết runAsNonRoot: true. Điều đó có nghĩa là cluster đang tự enforce nó cho bạn — thường thông qua PodSecurity admission hoặc Gatekeeper.
# Kiểm tra xem namespace có PodSecurity label không
kubectl get namespace my-namespace -o yaml | grep pod-security
# Ví dụ kết quả:
# pod-security.kubernetes.io/enforce: restricted
Chuẩn PodSecurity restricted bắt buộc runAsNonRoot: true trên mọi pod trong namespace đó. Cách sửa hoàn toàn giống nhau — thêm runAsUser hoặc rebuild image. Bạn chỉ cần biết rằng ràng buộc đến từ cluster, không phải từ manifest của bạn.
Tóm Tắt Nhanh
- Sửa nhanh nhất: Thêm
runAsUser: 1000cùng vớirunAsNonRoot: true - Image dùng cổng 80/443: Chuyển sang variant unprivileged (ví dụ:
nginxinc/nginx-unprivilegedtrên cổng 8080, UID 101) - Image tự build: Thêm
USER 1001vào Dockerfile - Dùng UID nào: Bất kỳ giá trị nào lớn hơn 0 — 1000, 1001 và 65534 là các lựa chọn thông dụng
- Không nên: Xóa
runAsNonRoot: truechỉ để tắt lỗi — nó tồn tại có lý do của nó

