[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$ffH0hgb7V0oKbjlcvS3n5yERrm0UW9zwYXlo4b2-oLns":3},{"data":4,"related":88},{"id":5,"title":6,"slug":7,"excerpt":8,"cover":9,"category":11,"author":14,"track":20,"level":23,"reading_minutes":26,"is_featured":27,"published_at":28,"updated_at":28,"body":29,"toc":30,"tags":63,"faqs":75,"related_services":85,"comments_enabled":86,"meta_title":19,"meta_description":87,"canonical_url":19,"noindex":27,"is_live":86},17,"خطای runAsNonRoot در Kubernetes؛ وقتی ایمیج با root بالا می‌آید","kubernetes-runasnonroot-createcontainerconfigerror","بعد از اعمال Pod Security Standards روی restricted، پادها در وضعیت CreateContainerConfigError گیر می‌کنند و kubelet می‌گوید image با root اجرا می‌شود. علت ریشه‌ای و راه‌حل کامل را بررسی می‌کنیم.",{"url":10,"alt":6},"https:\u002F\u002Fapi.cloudicap.com\u002Fmedia\u002Fposts\u002F5553b16d-3d91-4c93-9f4a-423aad8c351e.webp",{"name":12,"slug":13},"امنیت و DevSecOps","security",{"name":15,"slug":16,"role":17,"bio":18,"linkedin_url":19,"avatar_url":19},"تحریریه کلودیکپ","cloudicap-editorial","تیم محتوای کلودیکپ","تیم فنی و محتوای کلودیکپ؛ مهندسانی که هر روز با DevOps، Kubernetes و زیرساخت ابری کار می‌کنند و تجربه‌هایشان را اینجا می‌نویسند.",null,{"value":21,"label":22},"engineers","مهندسان",{"value":24,"label":25},"intermediate","متوسط",7,false,"2026-10-22T11:47:14+00:00","\u003Ch2 id=\"شرح-مسئله-پاد-در-createcontainerconfigerror-گیر-می‌کند\">شرح مسئله: پاد در CreateContainerConfigError گیر می‌کند\u003C\u002Fh2>\u003Cp>سناریوی همیشگی: تیم امنیت تصمیم می‌گیرد namespace سرویس‌ها را از \u003Ccode>baseline\u003C\u002Fcode> به \u003Ccode>restricted\u003C\u002Fcode> ببرد. لیبل را اضافه می‌کنید، چند دقیقه بعد هیچ دیپلوی جدیدی بالا نمی‌آید. نه خطای اپلیکیشن، نه مشکل ایمیج‌پول؛ فقط پادهایی که در فاز کانتینرسازی متوقف شده‌اند:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-bash\">kubectl -n shop get pods\n# NAME                        READY   STATUS                       RESTARTS   AGE\n# checkout-7d9f8c5b6-x2klm     0\u002F1     CreateContainerConfigError   0          2m\n# checkout-7d9f8c5b6-q8w4t     0\u002F1     CreateContainerConfigError   0          2m\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>اولین جای درست برای نگاه کردن، ایونت‌های پاد است نه لاگ کانتینر (کانتینر هرگز استارت نشده که لاگی داشته باشد):\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-bash\">kubectl -n shop describe pod checkout-7d9f8c5b6-x2klm | tail -n 8\n# Events:\n#   Type     Reason  Age   From     Message\n#   ----     ------  ----  ----     -------\n#   Warning  Failed  14s   kubelet  Error: container has runAsNonRoot and image will run as root\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>یک نسخه دیگر از همین خطا هم وجود دارد که بیشتر تیم‌هایی که از \u003Ccode>USER node\u003C\u002Fcode> یا \u003Ccode>USER app\u003C\u002Fcode> استفاده می‌کنند به آن می‌خورند:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-bash\"># Warning  Failed  9s  kubelet  Error: container has runAsNonRoot and image has non-numeric user (node), cannot verify user is non-root\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>و یک حالت سوم که به‌ظاهر خطای دیگری است ولی همان ریشه را دارد: پاد با موفقیت اجرا می‌شود اما چند ثانیه بعد CrashLoopBackOff می‌خورد و در لاگ، \u003Ccode>EACCES: permission denied, mkdir '\u002Fapp\u002F.cache'\u003C\u002Fcode> یا \u003Ccode>permission denied\u003C\u002Fcode> روی \u003Ccode>\u002Ftmp\u003C\u002Fcode> دیده می‌شود؛ چون پروسه حالا با UID غیرصفر اجرا می‌شود و مالکیت فایل‌های ایمیج با آن UID یکی نیست.\u003C\u002Fp>\u003Ch2 id=\"علت-ریشه‌ای-kubelet-نمی‌تواند-non-root-بودن-را-تأیید-کند\">علت ریشه‌ای: kubelet نمی‌تواند non-root بودن را تأیید کند\u003C\u002Fh2>\u003Cp>نکته‌ای که اکثر پست‌ها جا می‌اندازند این است که پیام بالا از \u003Cstrong>admission\u003C\u002Fstrong> نمی‌آید، از \u003Cstrong>kubelet\u003C\u002Fstrong> می‌آید. یعنی پاد از دروازه‌ی Pod Security Admission رد شده و مانع‌اش ادمیشن نبوده؛ در لحظه ساخت کانتینر، kubelet تابع \u003Ccode>verifyRunAsNonRoot\u003C\u002Fcode> را اجرا می‌کند و شکست می‌خورد. همین موضوع سرنخ اصلی است: باید فرق بین «پاد مجاز شد» و «کانتینر مجاز شد» را جدا کنیم.\u003C\u002Fp>\u003Cp>منطق kubelet ساده است:\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cp>اگر در \u003Ccode>securityContext\u003C\u002Fcode> مقدار \u003Ccode>runAsUser\u003C\u002Fcode> مشخص شده باشد، kubelet همان را می‌بیند؛ اگر غیر از صفر باشد، عبور می‌کند.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>اگر \u003Ccode>runAsUser\u003C\u002Fcode> مشخص نشده باشد، kubelet داخل کانفیگ ایمیج نگاه می‌کند (همان فیلد \u003Ccode>User\u003C\u002Fcode> در Dockerfile). اگر خالی باشد یعنی root → پیام \u003Ccode>image will run as root\u003C\u002Fcode>.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>اگر خالی نباشد اما عددی نباشد (مثل \u003Ccode>node\u003C\u002Fcode>)، kubelet عمداً وارد \u003Ccode>\u002Fetc\u002Fpasswd\u003C\u002Fcode> ایمیج نمی‌شود و نمی‌تواند حدس بزند که این نام به یک UID غیرصفر نگاشت می‌شود → پیام \u003Ccode>cannot verify user is non-root\u003C\u002Fcode>.\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>پس ریشه‌ی مشکل همیشه یکی از این دو است: ایمیج غیرعددی یا بدون \u003Ccode>USER\u003C\u002Fcode> ساخته شده، یا منیفست به کانتینر \u003Ccode>runAsUser\u003C\u002Fcode> نداده و انتظار دارد ایمیج این کار را کرده باشد.\u003C\u002Fp>\u003Cp>یک تصور غلط رایج هم که وقت زیادی از تیم‌ها می‌گیرد: پروفایل \u003Ccode>restricted\u003C\u002Fcode> الزام می‌کند \u003Ccode>runAsNonRoot: true\u003C\u002Fcode>، \u003Ccode>allowPrivilegeEscalation: false\u003C\u002Fcode>، \u003Ccode>capabilities.drop: [\"ALL\"]\u003C\u002Fcode>، \u003Ccode>seccompProfile.type: RuntimeDefault\u003C\u002Fcode> و محدود بودن نوع volume، اما \u003Ccode>readOnlyRootFilesystem\u003C\u002Fcode> \u003Cstrong>جزو الزامات این پروفایل نیست\u003C\u002Fstrong>. اگر پاد فقط به خاطر همین خطا رد می‌شود، لازم نیست کل اپلیکیشن را read-only کنید؛ ولی چون در عمل خوب است، در ادامه هر دو را با هم می‌آوریم.\u003C\u002Fp>\u003Ch2 id=\"راه‌حل-گام‌به‌گام\">راه‌حل گام‌به‌گام\u003C\u002Fh2>\u003Ch3 id=\"گام-صفر-اول-warn-و-audit-بعد-enforce\">گام صفر: اول warn و audit، بعد enforce\u003C\u002Fh3>\u003Cp>قبل از اینکه یک namespace را قفل کنید، همان قوانین را در حالت هشدار بگذارید تا فهرست دقیق تخلف‌ها را ببینید:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-bash\">kubectl label --overwrite ns shop \\\n  pod-security.kubernetes.io\u002Fwarn=restricted \\\n  pod-security.kubernetes.io\u002Fwarn-version=latest \\\n  pod-security.kubernetes.io\u002Faudit=restricted \\\n  pod-security.kubernetes.io\u002Faudit-version=latest\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>از این به بعد هر \u003Ccode>kubectl apply\u003C\u002Fcode>، خط‌های هشدار را روی stderr چاپ می‌کند و در audit log هم ثبت می‌شود:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-bash\">kubectl -n shop apply -f deploy.yaml\n# Warning: would violate PodSecurity \"restricted:latest\":\n#   allowPrivilegeEscalation != false\n#   unrestricted capabilities: container \"checkout\" must set securityContext.capabilities.drop=[\"ALL\"]\n#   runAsNonRoot != true: container \"checkout\" must not be privileged,\n#     must not set allowPrivilegeEscalation=true, and must not set runAsUser=0\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3 id=\"گام-یک-ایمیج-را-با-uid-عددی-بسازید\">گام یک: ایمیج را با UID عددی بسازید\u003C\u002Fh3>\u003Cp>مطمئن‌ترین راه این است که ایمیج، کاربر خودش را با UID ثابت داشته باشد. برای ایمیج‌های Debian-based:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-dockerfile\">FROM node:20-bookworm-slim AS build\nWORKDIR \u002Fapp\nCOPY package*.json .\u002F\nRUN npm ci\nCOPY . .\nRUN npm run build\n\nFROM node:20-bookworm-slim\nENV NODE_ENV=production\nWORKDIR \u002Fapp\n\n# UID\u002FGID ثابت و عددی؛ کلید عبور از بررسی kubelet\nRUN groupadd --gid 10001 app \\\n &amp;&amp; useradd --uid 10001 --gid 10001 --create-home --shell \u002Fusr\u002Fsbin\u002Fnologin app\n\nCOPY --from=build --chown=10001:10001 \u002Fapp\u002Fdist .\u002Fdist\nCOPY --from=build --chown=10001:10001 \u002Fapp\u002Fnode_modules .\u002Fnode_modules\n\n# حتماً به شکل عددی بنویسید، نه USER app\nUSER 10001:10001\nEXPOSE 8080\nCMD [\"node\", \"dist\u002Fmain.js\"]\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>اگر پایه ایمیج‌تان Alpine است، معادل BusyBox آن این است: \u003Ccode>RUN addgroup -g 10001 -S app &amp;&amp; adduser -u 10001 -S app -G app\u003C\u002Fcode>. نکته مهم \u003Ccode>--chown\u003C\u002Fcode> است؛ بدون آن پروسه‌ای که حالا با UID 10001 اجرا می‌شود نمی‌تواند فایل‌ها را بخواند و خطای permission denied می‌گیرید.\u003C\u002Fp>\u003Ch3 id=\"گام-دو-securitycontext-را-کامل-کنید\">گام دو: securityContext را کامل کنید\u003C\u002Fh3>\u003Cp>حتی با ایمیج درست، بدون تعریف صریح این بلوک نمی‌توانید روی الزامات \u003Ccode>restricted\u003C\u002Fcode> حساب کنید. یک منیفست عبورکرده از هر پنج کنترل:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-yaml\">apiVersion: apps\u002Fv1\nkind: Deployment\nmetadata:\n  name: checkout\n  namespace: shop\nspec:\n  replicas: 2\n  selector:\n    matchLabels:\n      app: checkout\n  template:\n    metadata:\n      labels:\n        app: checkout\n    spec:\n      automountServiceAccountToken: false\n      securityContext:\n        runAsNonRoot: true\n        runAsUser: 10001\n        runAsGroup: 10001\n        fsGroup: 10001\n        seccompProfile:\n          type: RuntimeDefault\n      containers:\n        - name: checkout\n          image: registry.example.com\u002Fshop\u002Fcheckout:1.4.2\n          ports:\n            - containerPort: 8080\n          securityContext:\n            runAsNonRoot: true\n            runAsUser: 10001\n            allowPrivilegeEscalation: false\n            readOnlyRootFilesystem: true\n            capabilities:\n              drop:\n                - ALL\n          volumeMounts:\n            - name: tmp\n              mountPath: \u002Ftmp\n            - name: cache\n              mountPath: \u002Fapp\u002F.cache\n      volumes:\n        - name: tmp\n          emptyDir: {}\n        - name: cache\n          emptyDir: {}\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>دو نکته که معمولاً از چشم می‌افتد: \u003Ccode>fsGroup: 10001\u003C\u002Fcode> باعث می‌شود volumeهای \u003Ccode>emptyDir\u003C\u002Fcode> با گروه درست mount شوند و نوشتن در \u003Ccode>\u002Ftmp\u003C\u002Fcode> شکست نخورد. و \u003Ccode>emptyDir\u003C\u002Fcode> در فهرست volumeهای مجاز \u003Ccode>restricted\u003C\u002Fcode> هست، پس با این تغییر قانون را نمی‌شکنید.\u003C\u002Fp>\u003Ch3 id=\"گام-سه-ایمیج‌های-third-party-را-بررسی-کنید\">گام سه: ایمیج‌های third-party را بررسی کنید\u003C\u002Fh3>\u003Cp>همیشه نمی‌توانید ایمیج را rebuild کنید. قبل از هر چیز ببینید ایمیج چه می‌گوید:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-bash\">docker image inspect registry.example.com\u002Fthirdparty\u002Fagent:2.1 \\\n  --format '{{.Config.User}}'\n# خروجی خالی یعنی root؛ خروجی \"agent\" یعنی غیرعددی\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>در هر دو حالت می‌توانید با ست کردن صریح \u003Ccode>runAsUser\u003C\u002Fcode> در منیفست از بررسی ایمیج عبور کنید، چون kubelet وقتی UID عددی می‌بیند دیگر داخل ایمیج نگاه نمی‌کند:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-yaml\">          securityContext:\n            runAsNonRoot: true\n            runAsUser: 10001\n            runAsGroup: 10001\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>اما این ترفند فقط زمانی جواب می‌دهد که اپلیکیشن واقعاً به root نیاز نداشته باشد. ایمیجی که روی پورت زیر ۱۰۲۴ bind می‌کند، در \u003Ccode>\u002Fvar\u002Flib\u003C\u002Fcode> می‌نویسد یا فایل‌هایش مالک root با مود 600 است، با این روش در فاز اجرا می‌شکند. برای چنین workloadهایی، مسیر درست ساختن یک namespace جداگانه با پروفایل \u003Ccode>baseline\u003C\u002Fcode> و مستندسازی استثناست، نه شل کردن کل خوشه.\u003C\u002Fp>\u003Ch3 id=\"گام-چهار-enforce-با-نسخه‌ی-پین‌شده\">گام چهار: enforce با نسخه‌ی پین‌شده\u003C\u002Fh3>\u003Cpre>\u003Ccode class=\"language-bash\">kubectl label --overwrite ns shop \\\n  pod-security.kubernetes.io\u002Fenforce=restricted \\\n  pod-security.kubernetes.io\u002Fenforce-version=v1.30\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>\u003Ccode>enforce-version\u003C\u002Fcode> را پین کنید. اگر \u003Ccode>latest\u003C\u002Fcode> بگذارید، با هر ارتقای خوشه پروفایل ممکن است سخت‌تر شود و بی‌خبر، دیپلوی تیم دیگری بشکند.\u003C\u002Fp>\u003Ch2 id=\"چطور-مطمئن-شویم-مشکل-واقعا-حل-شده-است\">چطور مطمئن شویم مشکل واقعاً حل شده است\u003C\u002Fh2>\u003Cp>اینکه پاد Running شد کافی نیست؛ باید تأیید کنید که فرآیند واقعاً با UID غیرصفر اجرا می‌شود و ایمیج هم بدون ترفند قبول شده است:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-bash\">kubectl -n shop rollout status deploy\u002Fcheckout\nkubectl -n shop exec deploy\u002Fcheckout -- id\n# uid=10001(app) gid=10001(app) groups=10001(app)\n\nkubectl -n shop exec deploy\u002Fcheckout -- grep CapEff \u002Fproc\u002F1\u002Fstatus\n# CapEff: 0000000000000000   ← هیچ capability باقی نمانده\n\nkubectl -n shop exec deploy\u002Fcheckout -- sh -c 'touch \u002Ftmp\u002Fhealth &amp;&amp; echo writable'\n# writable\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>سپس بررسی کنید که دیگر هشدار ادمیشن صادر نمی‌شود؛ یعنی منیفست از نظر خود API Server کاملاً منطبق است:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-bash\">kubectl -n shop apply --dry-run=server -f deploy.yaml\n# اگر هیچ خط Warning چاپ نشد، منیفست سازگار است\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>و در نهایت، ایونت پاد نباید هیچ \u003Ccode>Failed\u003C\u002Fcode> مربوط به kubelet داشته باشد:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-bash\">kubectl -n shop get events --field-selector reason=Failed --sort-by=.lastTimestamp\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch2 id=\"پیشگیری-و-بهترین-روش‌ها\">پیشگیری و بهترین روش‌ها\u003C\u002Fh2>\u003Cul>\u003Cli>\u003Cp>\u003Cstrong>سیاست را به پایپلاین ببرید، نه به خوشه.\u003C\u002Fstrong> ابزاری مثل kube-linter همان قوانین را قبل از merge می‌گیرد: \u003Ccode>run-as-non-root\u003C\u002Fcode>، \u003Ccode>privilege-escalation-container\u003C\u002Fcode>، \u003Ccode>seccomp-profile\u003C\u002Fcode> و \u003Ccode>no-read-only-root-fs\u003C\u002Fcode> جزو چک‌های آماده‌ی آن هستند.\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cpre>\u003Ccode class=\"language-yaml\"># .kube-linter.yaml\nchecks:\n  addAllBuiltIn: true\n  exclude:\n    - unset-cpu-requirements\n    - unset-memory-requirements\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode class=\"language-bash\">kube-linter lint manifests\u002F --config .kube-linter.yaml\u003C\u002Fcode>\u003C\u002Fpre>\u003Cul>\u003Cli>\u003Cp>\u003Cstrong>Dockerfile را lint کنید.\u003C\u002Fstrong> قاعده‌ی \u003Ccode>DL3002\u003C\u002Fcode> در hadolint دقیقاً همین را می‌گیرد: آخرین \u003Ccode>USER\u003C\u002Fcode> نباید root باشد. یک خط در CI کافی است تا کسی سهواً \u003Ccode>USER\u003C\u002Fcode> را حذف نکند.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>UID و GID را استاندارد کنید.\u003C\u002Fstrong> یک بازه ثابت (مثلاً ۱۰۰۰۰ تا ۱۰۹۹۹) برای همه سرویس‌ها تعیین کنید تا نه با کاربران سیستمی ایمیج تصادم کند و نه موقع نوشتن روی volume اشتراکی مشکل پیش بیاید.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>همیشه \u003C\u002Fstrong>\u003Ccode>runAsUser\u003C\u002Fcode>\u003Cstrong> را صریح بنویسید.\u003C\u002Fstrong> حتی وقتی ایمیج \u003Ccode>USER 10001\u003C\u002Fcode> دارد. این کار بررسی kubelet را مستقل از ایمیج می‌کند و مانع خطای \u003Ccode>cannot verify user is non-root\u003C\u002Fcode> در آینده می‌شود.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>مسیر warn → audit → enforce را در محیط dev حفظ کنید.\u003C\u002Fstrong> اگر از Kyverno یا Gatekeeper استفاده می‌کنید، در فاز اول با حالت \u003Ccode>Audit\u003C\u002Fcode> و mutate برای تزریق پیش‌فرض‌های \u003Ccode>securityContext\u003C\u002Fcode> شروع کنید تا توسعه‌دهنده مجبور نباشد همه‌چیز را از حفظ بنویسد.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>readOnlyRootFilesystem را عادت کنید.\u003C\u002Fstrong> هرچند در پروفایل \u003Ccode>restricted\u003C\u002Fcode> الزامی نیست، اما اگر از روز اول اپلیکیشن را مجبور کنید فقط در \u003Ccode>\u002Ftmp\u003C\u002Fcode> و مسیرهای مشخص بنویسد، مهاجرت به سخت‌گیری‌های بعدی بدون درد خواهد بود.\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>",[31,35,38,41,45,48,51,54,57,60],{"id":32,"text":33,"level":34},"شرح-مسئله-پاد-در-createcontainerconfigerror-گیر-می‌کند","شرح مسئله: پاد در CreateContainerConfigError گیر می‌کند",2,{"id":36,"text":37,"level":34},"علت-ریشه‌ای-kubelet-نمی‌تواند-non-root-بودن-را-تأیید-کند","علت ریشه‌ای: kubelet نمی‌تواند non-root بودن را تأیید کند",{"id":39,"text":40,"level":34},"راه‌حل-گام‌به‌گام","راه‌حل گام‌به‌گام",{"id":42,"text":43,"level":44},"گام-صفر-اول-warn-و-audit-بعد-enforce","گام صفر: اول warn و audit، بعد enforce",3,{"id":46,"text":47,"level":44},"گام-یک-ایمیج-را-با-uid-عددی-بسازید","گام یک: ایمیج را با UID عددی بسازید",{"id":49,"text":50,"level":44},"گام-دو-securitycontext-را-کامل-کنید","گام دو: securityContext را کامل کنید",{"id":52,"text":53,"level":44},"گام-سه-ایمیج‌های-third-party-را-بررسی-کنید","گام سه: ایمیج‌های third-party را بررسی کنید",{"id":55,"text":56,"level":44},"گام-چهار-enforce-با-نسخه‌ی-پین‌شده","گام چهار: enforce با نسخه‌ی پین‌شده",{"id":58,"text":59,"level":34},"چطور-مطمئن-شویم-مشکل-واقعا-حل-شده-است","چطور مطمئن شویم مشکل واقعاً حل شده است",{"id":61,"text":62,"level":34},"پیشگیری-و-بهترین-روش‌ها","پیشگیری و بهترین روش‌ها",[64,66,68,71,73],{"name":65,"slug":65},"docker",{"name":67,"slug":67},"kubernetes",{"name":69,"slug":70},"DevSecOps","devsecops",{"name":72,"slug":72},"pod-security",{"name":74,"slug":74},"security-context",[76,79,82],{"question":77,"answer":78},"آیا فعال کردن readOnlyRootFilesystem برای عبور از پروفایل restricted الزامی است؟","نه. پروفایل restricted در Pod Security Standards مواردی مثل runAsNonRoot، allowPrivilegeEscalation=false، drop همه‌ی capabilityها، seccompProfile از نوع RuntimeDefault و محدودیت نوع volume را الزام می‌کند، اما readOnlyRootFilesystem جزو آن نیست. با این حال فعال کردنش توصیه می‌شود و فقط باید مسیرهای نوشتنی مثل \u002Ftmp را با emptyDir mount کنید.",{"question":80,"answer":81},"اگر ایمیج فقط با کاربر root کار کند چه کار کنیم؟","اول بررسی کنید که آیا واقعاً به root نیاز دارد یا فقط چون USER در Dockerfile ست نشده این‌طور به نظر می‌رسد. اکثر اپلیکیشن‌ها با runAsUser عددی و اصلاح مالکیت فایل‌ها کار می‌کنند. اگر ایمیج واقعاً به root نیاز دارد (مثلاً bind روی پورت زیر ۱۰۲۴ یا نوشتن در \u002Fvar\u002Flib)، آن workload را در namespace جداگانه‌ای با پروفایل baseline نگه دارید و استثنا را مستند کنید؛ هرگز کل خوشه را به خاطر یک سرویس شل نکنید.",{"question":83,"answer":84},"آیا PodSecurity Admission جایگزین PodSecurityPolicy شده است؟","بله. PodSecurityPolicy در Kubernetes 1.25 حذف شد و PodSecurity Admission که از 1.23 به‌صورت بتا و از 1.25 به‌صورت پایدار در دسترس است جای آن را گرفته. تفاوت مهم‌اش این است که PSA فقط admit یا reject می‌کند و مقادیر securityContext را به‌صورت خودکار پر نمی‌کند؛ اگر به تزریق خودکار پیش‌فرض‌ها نیاز دارید باید از Kyverno یا Gatekeeper استفاده کنید.",[],true,"رفع خطای container has runAsNonRoot and image will run as root در Kubernetes: علت، اصلاح Dockerfile، securityContext کامل و فعال‌سازی امن Pod Security restricted.",[89,102,117],{"id":90,"title":91,"slug":92,"excerpt":93,"cover":94,"category":96,"author":97,"track":98,"level":99,"reading_minutes":100,"is_featured":27,"published_at":101,"updated_at":101},10,"رفع خطای 429 در Trivy DB با راه‌اندازی mirror داخلی","trivy-db-429-rate-limit-mirror","اگر مرحله اسکن Trivy در پایپلاین با خطای 429 Too Many Requests شکست می‌خورد، مشکل از کد یا شبکه شما نیست؛ GHCR نرخ pull ناشناس را محدود می‌کند. در این مقاله پایگاه‌داده Trivy را در رجیستری داخلی mirror می‌کنیم و Trivy را به آن وصل می‌کنیم.",{"url":95,"alt":91},"https:\u002F\u002Fapi.cloudicap.com\u002Fmedia\u002Fposts\u002Fcd38c70f-05ae-4f49-aa18-24ae7740ace1.webp",{"name":12,"slug":13},{"name":15,"slug":16,"role":17,"avatar_url":19},{"value":21,"label":22},{"value":24,"label":25},8,"2026-10-11T08:54:50+00:00",{"id":103,"title":104,"slug":105,"excerpt":106,"cover":107,"category":109,"author":111,"track":112,"level":113,"reading_minutes":26,"is_featured":27,"published_at":116,"updated_at":116},16,"پر شدن فضای etcd؛ خطای mvcc: database space exceeded","etcd-mvcc-database-space-exceeded-fix","وقتی فایل backend در etcd از فضای تعیین‌شده عبور می‌کند، کل کلاستر Kubernetes به حالت فقط‌خواندنی می‌رود. در این مقاله علت fragmentation را بررسی می‌کنیم و با defrag، disarm و تنظیم quota کلاستر را برمی‌گردانیم.",{"url":108,"alt":104},"https:\u002F\u002Fapi.cloudicap.com\u002Fmedia\u002Fposts\u002F8e23ae4a-9378-4437-993a-3c839a851a9a.webp",{"name":110,"slug":67},"Kubernetes و کانتینر",{"name":15,"slug":16,"role":17,"avatar_url":19},{"value":21,"label":22},{"value":114,"label":115},"advanced","پیشرفته","2026-10-18T10:56:24+00:00",{"id":118,"title":119,"slug":120,"excerpt":121,"cover":122,"category":124,"author":125,"track":126,"level":127,"reading_minutes":26,"is_featured":27,"published_at":128,"updated_at":128},12,"خطای fsnotify watcher در Kubernetes؛ سقف inotify نود","kubernetes-fsnotify-watcher-inotify-limit","اگر پادهای Grafana، Prometheus یا هر اپلیکیشنی که از inotify استفاده می‌کند با خطای «failed to create fsnotify watcher: too many open files» کرش می‌کنند، مقصر سقف پیش‌فرض هسته لینوکس روی نود است.",{"url":123,"alt":119},"https:\u002F\u002Fapi.cloudicap.com\u002Fmedia\u002Fposts\u002F4781a89b-ab2c-4250-9677-521b30f6f643.webp",{"name":110,"slug":67},{"name":15,"slug":16,"role":17,"avatar_url":19},{"value":21,"label":22},{"value":24,"label":25},"2026-10-13T09:37:29+00:00"]