kubectl debug الحاويات المؤقتة: Pods بدون Shell لعام
٢٥ يونيو ٢٠٢٦
لتصحيح أخطاء (debug) بود Kubernetes لا يحتوي على شل (shell)، قم بتشغيل kubectl debug لحقن حاوية مؤقتة (ephemeral container) تحمل أدواتها الخاصة. أضف --target=<container> لمشاركة مساحة أسماء العمليات (process namespace) الخاصة بالتطبيق، ثم اقرأ نظام ملفات التطبيق من خلال /proc/<pid>/root. بالنسبة للبودات التي تعاني من حلقة انهيار (crash-looping)، قم بتصحيح نسخة --copy-to بدلاً من ذلك.
ملخص
صور Distroless و scratch تشحن فقط ملفك الثنائي (binary) — لا شل، لا curl، لا ps — لذا فإن kubectl exec ليس لديه ما يتصل به. الحل هو kubectl debug، الذي يربط حاوية مؤقتة (مستقرة منذ Kubernetes 1.251) ببود يعمل، مشاركاً مساحات الأسماء الخاصة به دون إعادة تشغيل. استخدم --target لرؤية عمليات التطبيق، والوصول إلى ملفاته عند /proc/<pid>/root، واستبدلها بـ nicolaka/netshoot لأدوات الشبكة، واستخدم --copy-to للبودات العالقة في CrashLoopBackOff. ملاحظة: لا يمكن أبداً إزالة الحاويات المؤقتة — حذف البود هو الطريقة الوحيدة للتنظيف. تم التحقق من كل أمر هنا مقابل مرجع Kubernetes 1.36 kubectl (الإصدار المستقر الحالي، الصادر في أبريل 20262).
ما ستتعلمه
- لماذا يفشل
kubectl execعلى حاوية distroless أو منهارة، ومتى تلجأ إلىkubectl debugبدلاً من ذلك - كيفية تصحيح أخطاء بود لا يحتوي على شل باستخدام حاوية مؤقتة
- كيف يشارك
--targetمساحة أسماء العمليات الخاصة بالتطبيق - كيفية قراءة نظام ملفات حاوية distroless من خلال
/proc - كيفية تصحيح أخطاء بود في حالة
CrashLoopBackOffباستخدام--copy-toو--set-image - ماذا يفعل علم
--profileولماذا تغير الافتراضي في Kubernetes 1.36 - كيفية تصحيح مشكلات الشبكة باستخدام صورة
nicolaka/netshoot - كيفية تصحيح أخطاء عقدة (node) Kubernetes باستخدام
kubectl debug node/ - لماذا لا يمكنك إزالة حاوية مؤقتة، وكيفية التنظيف
لماذا لا يمكنني استخدام kubectl exec على بود distroless؟
يقوم kubectl exec بتشغيل أمر داخل حاوية موجودة، لذا فهو يحتاج إلى شيئين لا تملكهما حاويات distroless والحاويات المنهارة: ملف ثنائي للتشغيل (عادةً شل) وعملية حية للارتباط بها.3 تحذف صورة distroless عمداً الشل، و ls، وكل أداة تصحيح أخطاء لتقليص سطح الهجوم، لذا فإن kubectl exec -it mypod -- sh يعيد exec: "sh": executable file not found in $PATH. أما الحاوية المنهارة فلا يتبقى فيها PID 1 للدخول إليه على الإطلاق.
يحل kubectl debug كلتا المشكلتين عن طريق إحضار حاويته الخاصة. بدلاً من تسجيل الدخول إلى حاوية التطبيق، فإنه ينشئ حاوية جديدة — بأي صورة وأدوات تختارها — داخل نفس البود أو نسخة منه.3 يمكن لتلك الحاوية تشغيل نظام تشغيل مختلف، ومشاركة مساحات أسماء التطبيق، وفحص حالته دون تغيير الصورة الأصلية أو إعادة تشغيلها.
النسخة المختصرة من kubectl debug مقابل kubectl exec: استخدم exec عندما تحتوي الحاوية بالفعل على شل وتحتاج إلى أمر سريع واحد؛ استخدم debug عندما تكون الصورة في حدها الأدنى، أو الأدوات مفقودة، أو عندما تنهار الحاوية.
كيف يمكنني تصحيح أخطاء بود لا يحتوي على شل؟
قم بحقن حاوية مؤقتة باستخدام kubectl debug. الحاوية المؤقتة هي حاوية مؤقتة يضيفها Kubernetes إلى بود يعمل لاستكشاف الأخطاء وإصلاحها؛ فهي تشارك الشبكة و (اختيارياً) مساحات أسماء العمليات الخاصة بالبود ولكن لا يتم إعادة تشغيلها أبداً وليست جزءاً من مواصفات البود العادية التي تشحنها.4
# Attach a busybox ephemeral container to a running, shell-less pod
kubectl debug -it mypod --image=busybox --target=myapp
-itيبقي stdin مفتوحاً ويخصص TTY حتى تهبط في شل تفاعلي.5--image=busyboxهي صورة تصحيح الأخطاء؛ اختر أي شيء يحتوي على الأدوات التي تحتاجها.--target=myappيشير إلى الحاوية المسماةmyappفي البود (انظر القسم التالي).
يسمي Kubernetes الحاوية المؤقتة تلقائياً (مثل debugger-abcde) وتنتقل مباشرة إلى شل BusyBox. من هنا لديك ps، و wget، و nslookup، وأصدقاؤهم — وكلها غير موجودة في حاوية تطبيق distroless نفسها. ولأن الحاوية المؤقتة تضاف مباشرة، يستمر التطبيق في خدمة حركة المرور طوال الوقت؛ لا شيء يعاد تشغيله.4
إذا كنت تحتاج فقط إلى أدوات الشبكة ولا تهتم بعمليات التطبيق، يمكنك حذف --target:
kubectl debug -it mypod --image=busybox
سيظل ذلك يشارك مساحة أسماء الشبكة الخاصة بالبود (نفس عنوان IP الخاص بالبود، ونفس localhost)، وهو كافٍ لاختبار الاتصال من داخل البود.
كيف يشارك --target مساحة أسماء العمليات الخاصة بالتطبيق؟
يخبر --target=<container> الحاوية المؤقتة بـ استهداف العمليات في تلك الحاوية، مشاركاً مساحة أسماء العمليات الخاصة بها.5 بدون ذلك، تحصل حاوية تصحيح الأخطاء الخاصة بك على مساحة أسماء PID معزولة خاصة بها ويظهر ps عملية تصحيح الأخطاء فقط — وهو أمر غير مفيد لفحص التطبيق.
باستخدام --target=myapp، فإن تشغيل ps aux داخل الحاوية المؤقتة يسرد عمليات التطبيق أيضاً:
# Inside the ephemeral container
ps aux
# PID USER COMMAND
# 1 nonroot /app/server <- the distroless app
# 14 root ps aux <- your debug process
الآن يمكنك قراءة /proc/1/environ، وإرسال الإشارات، وفحص واصفات الملفات المفتوحة تحت /proc/1/fd، و — الأكثر فائدة — الوصول إلى ملفات التطبيق، وهو القسم التالي. يعتمد --target على دعم وقت تشغيل الحاوية (container runtime) لاستهداف مساحة أسماء العمليات، وهو ما توفره أوقات التشغيل المستخدمة في مجموعات (clusters) Kubernetes الحالية.4
كيف يمكنني الوصول إلى نظام ملفات حاوية distroless؟
عندما تتم مشاركة مساحة أسماء العمليات، يمكنك قراءة نظام ملفات الحاوية المستهدفة من خلال نظام الملفات الوهمي /proc في Linux: /proc/<pid>/root هو رابط رمزي (symlink) لنظام الملفات الجذري لتلك العملية.6 ابحث أولاً عن PID الخاص بالتطبيق باستخدام ps، ثم تصفح جذره:
# Inside the ephemeral container, after `ps aux` showed the app at PID 1
ls -la /proc/1/root/app/
cat /proc/1/root/etc/config/app.yaml
عادةً ما تكون العملية الرئيسية للتطبيق — ولكن ليس دائماً — هي PID 1، لذا يفضل قراءة PID من ps بدلاً من كتابة /proc/1/root بشكل ثابت. هذه هي الطريقة التي تفحص بها ملفات التكوين، أو السجلات المكتوبة على القرص، أو الشهادات، أو إصدار ملف ثنائي داخل صورة لا تحتوي على cat ولا ls خاصة بها. أنت تستخدم أدوات BusyBox للنظر في ملفات التطبيق. لا يتم نسخ أي شيء داخل أو خارج صورة distroless.
كيف يمكنني تصحيح أخطاء بود في حالة CrashLoopBackOff لا يحتوي على شل؟
لا يمكن للحاوية المؤقتة (ephemeral container) تصحيح أخطاء حاوية في حالة "crash-looping" بشكل موثوق: فعملية التطبيق تستمر في التوقف قبل أن تتمكن من فحص حالتها المباشرة، لذا لا يوجد شيء مستقر لمشاركة مساحة الاسم (namespace) معه.3 بدلاً من ذلك، قم بتصحيح أخطاء نسخة من الـ pod باستخدام --copy-to، مع تجاوز نقطة الإدخال (entrypoint) بحيث تبدأ النسخة واجهة أوامر (shell) بدلاً من الأمر الذي يتسبب في الانهيار:
# إنشاء نسخة باسم mypod-debug وتشغيل shell في الحاوية المستهدفة
kubectl debug mypod -it --copy-to=mypod-debug --container=myapp -- sh
يقوم --copy-to=mypod-debug بإنشاء pod جديد (يُترك الأصلي كما هو)، وكل ما بعد -- يستبدل أمر تلك الحاوية، لذا يتم التشغيل في sh بدلاً من الدخول في حلقة الانهيار (crash-looping). يمكنك الآن تشغيل الملف الثنائي (binary) يدوياً ومراقبته وهو يفشل مع عرض المخرجات كاملة.
إذا كانت الصورة من نوع distroless، فلن يوجد sh لتجاوز الأمر به — لذا قم بتبديل الصورة في نفس الوقت باستخدام --set-image:
# استبدال صورة distroless بـ busybox في النسخة، ثم الحصول على shell
kubectl debug mypod -it --copy-to=mypod-debug \
--set-image=myapp=busybox -- sh
يغير --set-image=myapp=busybox صورة الحاوية myapp فقط في النسخة (الصيغة تشبه kubectl set image).5 قم بتركيب (mount) نفس الإعدادات والبيئة (env) كالأصل ويمكنك إعادة إنتاج الانهيار بشكل تفاعلي. عند الانتهاء، احذف النسخة: kubectl delete pod mypod-debug. لن يتم تعديل الـ pod الأصلي وحالة CrashLoopBackOff الخاصة به أبداً.
ماذا يفعل علم --profile؟
يطبق --profile حزمة مسبقة الضبط من سياق الأمان (security context) وإعدادات مساحة الاسم على حاوية تصحيح الأخطاء حتى لا تضطر لصياغتها يدوياً.7 الخيارات المتاحة هي general، و baseline، و restricted، و netadmin، و sysadmin.5
general— مجموعة افتراضية معقولة من القدرات لتصحيح الأخطاء اليومي.baseline— متوافق مع معيار Pod Securitybaseline.restricted— متوافق مع معيار Pod Securityrestricted(أقل الامتيازات).netadmin— يضيفNET_ADMINوما شابهها لتصحيح أخطاء الشبكة.sysadmin— ملف تعريف ذو امتيازات لتصحيح أخطاء النظام منخفضة المستوى.
ملاحظة هامة بخصوص الإصدار: تغير ملف التعريف الافتراضي إلى general في Kubernetes 1.36. في الإصدار 1.35 وما قبله، كان الافتراضي هو ملف التعريف legacy المهجور.8 إذا تم رفض عملية ذات امتيازات (مثل قراءة ملفات /proc لحاوية أخرى أو تشغيل أدوات ذات امتيازات) على عنقود (cluster) حديث، فقم بتعيين ملف التعريف صراحةً:
kubectl debug -it mypod --image=busybox --target=myapp --profile=sysadmin
في العناقيد الأقدم من 1.36، يطبع kubectl تحذيراً من الهجر عندما لا تمرر --profile، مما يحثك على اتخاذ خيار صريح قبل أن يتغير الافتراضي.8
كيف يمكنني تصحيح مشكلات الشبكة باستخدام netshoot؟
وجه --image إلى nicolaka/netshoot، وهي صورة مخصصة لاستكشاف أخطاء الشبكة وإصلاحها تجمع بين curl، و dig، و tcpdump، و nmap، و iperf، و netstat، وعشرات الأدوات الأخرى في حاوية واحدة.9
# تصحيح أخطاء شبكة الـ pod من داخل مساحة اسم الشبكة الخاصة به
kubectl debug -it mypod --image=nicolaka/netshoot --target=myapp
نظراً لأن الحاوية المؤقتة تشارك مساحة اسم الشبكة الخاصة بالـ pod، فإن كل أمر يتم تشغيله باستخدام عنوان IP الخاص بالـ pod، وإعدادات DNS، وجدول التوجيه (routing table) — لذا فإن دقة DNS، واتصال الخدمة، ومصافحات TLS تتصرف تماماً كما تفعل في التطبيق الحقيقي:
# داخل netshoot
dig +short my-service.default.svc.cluster.local
curl -v http://my-service:8080/healthz
tcpdump -i any port 8080
لالتقاط البيانات على مستوى العقدة (node) أو التي تتطلب NET_ADMIN، ادمجها مع --profile=netadmin.
كيف يمكنني تصحيح أخطاء عقدة Kubernetes؟
استخدم kubectl debug node/<node-name>. يؤدي هذا إلى تشغيل pod لتصحيح الأخطاء على العقدة، يعمل في مساحات أسماء المضيف (host)، مع تركيب نظام ملفات الجذر الخاص بالعقدة في /host:5
kubectl debug node/ip-10-0-1-23 -it --image=busybox --profile=sysadmin
# بالداخل: نظام ملفات العقدة موجود في /host
chroot /host
journalctl -u kubelet --no-pager | tail -50
يمنحك ذلك سجلات kubelet، ومقبس وقت تشغيل الحاوية (container runtime socket)، و /etc/Kubernetes، وشبكة المضيف — وهو أمر مفيد عندما تكون العقدة في حالة NotReady أو عندما لا يتم جدولة الـ pods. تنبيه واحد: يعمل pod تصحيح أخطاء العقدة في مساحات أسماء IPC والشبكة و PID الخاصة بالمضيف ولكنه ليس ذا امتيازات بشكل افتراضي، لذا قد تفشل عملية chroot /host وبعض قراءات /proc ما لم تضف --profile=sysadmin (الذي يضبط privileged: true).10 إنه نفس سير عمل kubectl debug، ولكنه موجه نحو عقدة بدلاً من pod. (لتغيير حجم أعباء العمل دون إعادة تشغيلها، راجع دليلنا حول تغيير حجم pods Kubernetes بدون إعادة تشغيل.)
هل يمكنك إزالة حاوية مؤقتة من pod؟
لا. بمجرد إضافتها، تستمر الحاوية المؤقتة في مواصفات الـ pod حتى يتم حذف الـ pod نفسه — لا توجد عملية في Kubernetes API لتغييرها أو إزالتها.4 هذا مقصود: يتم تسجيل الحاويات المؤقتة كجزء من تاريخ الـ pod.
لذا فإن التنظيف الوحيد هو استبدال الـ pod:
# سرد الحاويات المؤقتة العالقة في pod
kubectl get pod mypod -o jsonpath='{.spec.ephemeralContainers[*].name}'
# الطريقة الوحيدة لإزالتها: حذف الـ pod (سيقوم الـ Deployment بإعادة جدولته)
kubectl delete pod mypod
إذا كان الـ pod مداراً بواسطة Deployment أو StatefulSet أو DaemonSet، فسيقوم المتحكم (controller) بإعادة إنشاء pod جديد بدون الحاوية المؤقتة. بالنسبة للـ pod المستقل (bare pod)، ستفقده — لذا فإن نسخ تصحيح الأخطاء (--copy-to) تكون أكثر أماناً عندما تريد تصحيح أخطاء قابلاً للتخلص منه والحذف.
الخلاصة
تجعل صور Distroless الإنتاج أكثر أماناً ولكنها تكسر عادة kubectl exec القديمة. الحل الحديث هو kubectl debug: قم بحقن حاوية مؤقتة (ephemeral container) في Pod قيد التشغيل باستخدام --target، واقرأ ملفات التطبيق من خلال /proc/<pid>/root، واستخدم nicolaka/netshoot لمشاكل الشبكة، والجا إلى نسخة --copy-to عندما يكون الـ Pod في حالة crash-looping. تذكر أمرين هامين — قم بتعيين --profile صراحةً في المجموعات (clusters) ذات الإصدارات المختلطة، وتعامل مع الحاويات المؤقتة على أنها دائمة.
لمزيد من عمليات Kubernetes، راجع أدلتنا حول هجرة Ingress إلى Kubernetes Gateway API و إضافة قابلية الملاحظة (observability) باستخدام Workers Logs و Sentry.
Footnotes
-
"Kubernetes v1.25: Combiner" — ephemeral containers graduated to Stable in v1.25 (released 2022-08-23). Retrieved 2026-06-25. https://Kubernetes.io/blog/2022/08/23/Kubernetes-v1-25-release/ ↩
-
"Kubernetes Releases" — v1.36 ("Haru") is the current stable line, released 2026-04-22; supported branches 1.36/1.35/1.34. Retrieved 2026-06-25. https://Kubernetes.io/releases/ ↩
-
"Debug Running Pods" — Kubernetes documentation (ephemeral containers vs
kubectl exec, copies of pods). Retrieved 2026-06-25. https://Kubernetes.io/docs/tasks/debug/debug-application/debug-running-pod/ ↩ ↩2 ↩3 -
"Ephemeral Containers" — Kubernetes documentation (purpose, namespace sharing, and the rule that they cannot be changed or removed after creation). Retrieved 2026-06-25. https://Kubernetes.io/docs/concepts/workloads/pods/ephemeral-containers/ ↩ ↩2 ↩3 ↩4
-
"kubectl debug" — generated CLI reference (
--target,--copy-to,--set-image,--profileDefault: "general", node debug mounts host fs at/host). Retrieved 2026-06-25. https://Kubernetes.io/docs/reference/kubectl/generated/kubectl_debug/ ↩ ↩2 ↩3 ↩4 ↩5 -
"/proc" symlinks — a process's root filesystem is reachable at
/proc/<pid>/rootwhen the process namespace is shared; standard Linuxproc(5)behavior used by distroless debugging guides. Retrieved 2026-06-25. https://man7.org/linux/man-pages/man5/proc.5.html ↩ -
"Debug Running Pods — Debugging profiles" — Kubernetes documentation describing the
--profilepresets. Retrieved 2026-06-25. https://Kubernetes.io/docs/tasks/debug/debug-application/debug-running-pod/#debugging-profiles ↩ -
"kubectl debug: change default profile and remove legacy profile" — Kubernetes/kubectl issue #1780 (legacy default through 1.35;
generalbecomes the default in 1.36). Retrieved 2026-06-25. https://GitHub.com/Kubernetes/kubectl/issues/1780 ↩ ↩2 -
"nicolaka/netshoot" — a Docker + Kubernetes network troubleshooting swiss-army container (curl, dig, tcpdump, nmap, iperf, and more). Retrieved 2026-06-25. https://GitHub.com/nicolaka/netshoot ↩
-
"Debugging Kubernetes Nodes With Kubectl" — node debug pods run in host namespaces with the node filesystem at
/hostbut are not privileged by default; use--profile=sysadminfor privileged access. Retrieved 2026-06-25. https://Kubernetes.io/docs/tasks/debug/debug-cluster/kubectl-node-debug/ ↩