شهادة cert-manager عالقة في حالة الانتظار؟ استكشاف الأخطاء وإصلاحها (2026)
٨ يوليو ٢٠٢٦
يظل مورد Certificate الخاص بـ cert-manager معلقاً (pending) لأن مورداً تابعاً له — سواء كان CertificateRequest، أو ACME Order، أو Challenge — لم يتم التحقق منه بعد. قم بتشغيل kubectl describe عبر تلك السلسلة للعثور على المورد المحظور بالضبط، ثم قم بإصلاح التكوين الخاطئ لـ HTTP-01/DNS-01 أو حد معدل Let's Encrypt الذي يذكره.1
ملخص
يقوم cert-manager بإصدار شهادة من خلال أربعة موارد مرتبطة: Certificate ينشئ CertificateRequest، والذي — بالنسبة لمصدري ACME مثل Let's Encrypt — ينشئ Order، والذي بدوره ينشئ Challenge واحداً لكل اسم نطاق.1 "عالق في حالة الانتظار" تعني دائماً تقريباً أن أحد موارد Challenge تلك لم يجتز الفحص الذاتي بعد، وسوف يخبرك kubectl describe challenge <name> بالسبب تحديداً: جدار حماية يحظر أداة حل HTTP-01، أو سجل DNS-01 لم ينتشر بعد، أو خطأ في حساب ACME/حد المعدل ظهر في أعلى السلسلة. يستعرض هذا المنشور سلسلة تصحيح الأخطاء الكاملة مع مخرجات cert-manager 1.20 الحقيقية في كل خطوة، ويغطي الحل البديل cert-manager.io/issue-temporary-certificate لأخطاء tls: handshake failure، ويوضح متى يكون حد معدل Let's Encrypt — وليس خطأ في التكوين — هو السبب الحقيقي.23
ما ستتعلمه
- كيفية تتبع سلسلة
Certificate → CertificateRequest → Order → Challengeباستخدامkubectl describe - ما تعنيه رسائل خطأ "الانتظار" والفحص الذاتي بالضبط في كل خطوة
- الفرق بين فشل تحدي HTTP-01 و DNS-01، وكيفية تصحيح أخطاء كل منهما
- متى تستخدم تعليق
cert-manager.io/issue-temporary-certificate - لماذا يعالج cert-manager 60 تحدياً فقط في المرة الواحدة، وماذا يعني ذلك لعمليات طرح الشهادات بالجملة
- ما إذا كان حد معدل Let's Encrypt — وليس ملف YAML الخاص بك — هو ما يمنع الإصدار فعلياً
- لماذا يجب عليك توجيه cert-manager إلى بيئة staging الخاصة بـ Let's Encrypt قبل تصحيح الأخطاء في بيئة الإنتاج
لماذا شهادة cert-manager الخاصة بي عالقة في حالة الانتظار؟
شهادة Certificate الخاصة بك عالقة لأن المورد الذي تعتمد عليه لم يصل إلى حالة نهائية. توضح وثائق cert-manager نفسها ذلك بوضوح: "عند تصحيح أخطاء cert-manager، فإن أفضل صديق لك هو kubectl describe... لا ينصح باستخدام السجلات (logs) لأنها مطولة للغاية."1 ابدأ من الأعلى:
$ kubectl get certificate
NAME READY AGE
example-com-tls False 1h
READY=False تعني فقط أن عملية الإصدار لم تنتهِ بعد — وهي ليست خطأً في حد ذاتها. قم بوصفها لرؤية الحالة الحالية وسجل الأحداث:
$ kubectl describe certificate example-com-tls
Status:
Conditions:
Last Transition Time: 2026-07-08T09:12:03Z
Message: Issuing certificate as Secret does not exist
Reason: DoesNotExist
Status: False
Type: Ready
Next Private Key Secret Name: example-com-tls-wtlww
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Issuing 105s cert-manager Issuing certificate as Secret does not exist
Normal Generated 105s cert-manager Stored new private key in temporary Secret resource "example-com-tls-wtlww"
Normal Requested 104s cert-manager Created new CertificateRequest resource "example-com-tls-bw5t9"
يسمي الحدث الأخير مورد CertificateRequest الذي أنشأه cert-manager. هذه هي محطتك التالية.
كيف يمكنني تصحيح أخطاء سلسلة CertificateRequest و Order و Challenge؟
اتبع السلسلة مورداً تلو الآخر — مخرجات describe لكل مورد تسمي المورد التالي في السلسلة.1 السلسلة الكاملة، مباشرة من مخطط بنية cert-manager، هي:
Ingress (optional) --> Certificate --> CertificateRequest --> Order --> Challenge
(ACME issuers only)
موردا Order و Challenge موجودان فقط لمصدري ACME (مثل Let's Encrypt و ZeroSSL وما شابه)؛ أما مصدرو CA الداخليون أو Vault فيتوقفون عند CertificateRequest.1 قم بوصف CertificateRequest:
$ kubectl describe certificaterequest example-com-tls-bw5t9
Spec:
Issuer Ref:
Group: cert-manager.io
Kind: ClusterIssuer
Name: letsencrypt-production
Status:
Conditions:
Message: Waiting on certificate issuance from order example-com-tls-fqtfg-1: "pending"
Reason: Pending
Status: False
Type: Ready
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal OrderCreated 8m20s cert-manager Created Order resource example-com-tls-fqtfg-1
رسالة Waiting on certificate issuance from order ...: "pending" هي صياغة cert-manager الحرفية والدقيقة — إنها مؤشر وليست السبب الجذري.1 قم بوصف Order المسمى بعد ذلك:
$ kubectl describe order example-com-tls-fqtfg-1
State: pending
URL: https://acme-v02.API.letsencrypt.org/acme/order/41123272/265506123
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Created 1m cert-manager Created Challenge resource "example-com-tls-fqtfg-1-0" for domain "example.com"
أخيراً، يوضح kubectl get challenges السبب الفعلي لمنع الإصدار:
$ kubectl get challenges
NAME STATE DOMAIN REASON AGE
example-com-tls-fqtfg-1-0 pending example.com Waiting for dns-01 challenge propagation 22s
عمود REASON هو المكان الذي يبدأ فيه تصحيح الأخطاء الحقيقي — وينقسم إلى وضعين مختلفين تماماً للفشل اعتماداً على ما إذا كنت تستخدم HTTP-01 أو DNS-01.2
ماذا يعني "Waiting on certificate issuance from order ...: pending" فعلياً؟
يعني أن CertificateRequest ينتظر مورد Order التابع له، والذي ينتظر بدوره واحداً أو أكثر من موارد Challenge لإنهاء التحقق من ملكية النطاق — وهذا ليس خطأً في حد ذاته.1 تمر تحديات HTTP01 و DNS01 بعملية من مرحلتين: يقوم cert-manager أولاً بإجراء "فحص ذاتي" داخلي قبل إخبار خادم ACME بأن التحدي جاهز، وذلك تحديداً حتى لا يستهلك حدود معدل ACME في تحديات ستفشل بوضوح بسبب تأخر انتشار DNS أو موازن التحميل.2 فقط بعد اجتياز الفحص الذاتي، يخبر cert-manager خادم Let's Encrypt بالتحقق، وعند هذه النقطة يتم تحديث حالة Challenge إلى valid وتعود السلسلة إلى الخلف وصولاً إلى Certificate.
HTTP-01 مقابل DNS-01: أي نوع من التحدي يفشل، وكيف يمكنني تصحيح أخطاء كل منهما؟
انظر إلى نطاق Challenge وسلسلة السبب — يوضح kubectl describe challenge آلية الحل المستخدمة وما الذي يفشل بالضبط.2 يفشل الحلان لأسباب مختلفة تماماً تقريباً:
يثبت HTTP-01 الملكية من خلال تقديم رمز مميز (token) على الرابط http://<domain>/.well-known/acme-challenge/<token>. إذا فشل الفحص الذاتي، فسترى Reason مثل:
Waiting for http-01 challenge propagation: failed to perform self check GET request
'http://example.com/.well-known/acme-challenge/_fgdLz0i3TFiZW4LBjuhjgd5nTOkaMBhxYmTY':
Get "http://example.com/...": remote error: tls: handshake failure
اتبع قائمة التحقق هذه بالترتيب: تأكد من إمكانية الوصول إلى رابط التحدي (challenge URL) من الإنترنت العام، ثم تأكد من إمكانية الوصول إليه من داخل بود (Pod) في الكلاستر الخاص بك (وليس فقط من جهازك الشخصي) — تشير وثائق cert-manager تحديداً إلى ضرورة الاختبار من داخل Pod، لأن مسارات الشبكة الداخلية للكلاستر قد تختلف عن الإنترنت العام.2 ظهور خطأ 404 على هذا الرابط يعني أن بود حل ACME (solver pod) لا يعمل أو أن Ingress الذي أنشأه الحل غير متصل — تحقق باستخدام kubectl describe ingress على Ingress الخاص بحل HTTP-01.2 أما خطأ tls: handshake failure فيعني أن متحكم ingress الخاص بك ليس لديه ما يقدمه على المنفذ 443 بعد لهذا المضيف — راجع حل الشهادة المؤقتة أدناه.
تحدي DNS-01 يثبت الملكية عن طريق نشر سجل TXT باسم _acme-challenge.<domain>. إذا كان هذا السجل موجوداً (تحقق باستخدام dig أو لوحة تحكم مزود DNS الخاص بك) ولكن cert-manager لا يزال يبلغ عن التحدي كـ "قيد الانتظار" (pending)، فإن السبب الأكثر شيوعاً هو أن محلل DNS الداخلي لـ cert-manager لا يمكنه رؤية السجل بعد — حتى لو كان الإنترنت العام يراه.2 هناك نمط فشل ثانٍ وأكثر دهاءً لـ DNS-01: يستخدم cert-manager سجلات SOA (Start of Authority) لتحديد منطقة DNS التي يجب كتابة سجل TXT فيها، وبعض المحللات (خاصة dnsmasq مع علم --filterwin2k، الذي يعرضه OpenWRT/LuCI كخيار "Filter useless") تقوم بإزالة سجلات SOA تماماً، مما يتسبب في تعريف cert-manager للمنطقة بشكل خاطئ.2 الحل في كلتا الحالتين هو توجيه الفحص الذاتي لـ DNS-01 الخاص بـ cert-manager إلى مجموعة مختلفة من خوادم الأسماء بدلاً من المحلل الافتراضي للكلاستر.
ما هو التعليق التوضيحي cert-manager.io/issue-temporary-certificate، ومتى أحتاجه؟
استخدمه عندما يفشل الفحص الذاتي لـ HTTP-01 بخطأ tls: handshake failure — فهو يخبر cert-manager بإصدار شهادة مؤقتة موقعة ذاتياً على الفور حتى يكون لدى متحكم ingress الخاص بك شيء ما صالح لتقديمه على المنفذ 443 بينما لا تزال شهادة ACME الحقيقية قيد الإصدار.2 قم بتعيينه مباشرة على مورد Ingress أو Certificate:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-com
annotations:
cert-manager.io/issue-temporary-certificate: "true"
cert-manager.io/cluster-issuer: letsencrypt-production
spec:
# ... rules, tls, etc.
إذا كنت تستخدم Google Cloud Load Balancer (GKE)، فإن وثائق cert-manager نفسها توصي بدمجه مع تعليق توضيحي ثانٍ، وهو acme.cert-manager.io/http01-edit-in-place: "true"، والذي يمنع GCLB من تخصيص عنوان IP ثانٍ لنقطة نهاية حل HTTP-01:2
cert-manager.io/issue-temporary-certificate: "true"
acme.cert-manager.io/http01-edit-in-place: "true"
لماذا يعالج cert-manager 60 تحدياً فقط في المرة الواحدة، وهل يهم ذلك بالنسبة لي؟
هل يمنع حد معدل Let's Encrypt شهادتي، وليس خطأ في الإعدادات؟
أحياناً — ويستحق الأمر استبعاد ذلك قبل قضاء ساعة في تصحيح أخطاء DNS. تفرض Let's Encrypt عدة حدود إنتاج منفصلة، والوصول إلى أي منها سيترك Order أو Challenge عالقاً دون أن يصبح invalid أبداً:3
| الحد | قيمة الإنتاج | معدل التعبئة |
|---|---|---|
| الطلبات الجديدة لكل حساب | 300 / 3 ساعات | 1 كل 36 ثانية |
| الشهادات الجديدة لكل نطاق مسجل | 50 / 7 أيام (عالمياً، لجميع الحسابات) | 1 كل 202 دقيقة |
| الشهادات الجديدة لكل مجموعة محددة من المعرفات | 5 / 7 أيام | 1 كل 34 ساعة |
| فشل التفويض لكل معرف/حساب | 5 / ساعة | 1 كل 12 دقيقة |
| فشل التفويض المتتالي لكل معرف/حساب | 1,152 إجمالاً، ثم يتم الإيقاف المؤقت | تعبئة واحدة/يوم |
النطاق المسجل هنا يعني الجزء الذي اشتريته من مسجل النطاقات الخاص بك — example.com، وليس app.example.com.3 هناك سلوكان يقع فيهما الناس مراراً وتكراراً: إلغاء الشهادة لا يعيد تعيين أي حد للمعدل، لأن الموارد التي استُهلكت لإصدارها قد استُنفدت بالفعل، وإعادة تثبيت عميل ACME الخاص بك أو مسح حالته المحلية بين المحاولات هو أحد أكثر الطرق شيوعاً لاستهلاك حد "مجموعة المعرفات المحددة" البالغ 5 أسبوعياً عن طريق الخطأ، حيث تبدو كل محاولة جديدة كطلب جديد تماماً بدلاً من تجديد.3 إذا كان عميلك يدعم ACME Renewal Info (ARI)، فإن التجديدات التي تشير صراحةً إلى الشهادة التي تستبدلها تُعفى من كل حدود المعدل؛ أما العملاء الأقدم الذين لا يدعمون ARI فيحصلون فقط على إعفاء جزئي (من حدود الحساب والنطاق، ولكن ليس من حدود مجموعة المعرفات أو حدود الفشل) طالما أن مجموعة النطاقات المطلوبة تطابق تماماً الشهادة التي يتم تجديدها، مع تجاهل حالة الأحرف وترتيب الأسماء.3
هل يجب أن أختبر مقابل بيئة staging الخاصة بـ Let's Encrypt أولاً؟
نعم، لأي إعداد مصدر (issuer) جديد، أو DNS-01 webhook، أو نشر جماعي — تستخدم بيئة staging نفس بروتوكول ACME ولكن بحدود أعلى بكثير حتى تتمكن من التكرار دون استهلاك سعة الإنتاج.4 وجه ClusterIssuer الخاص بك إلى دليل ACME الخاص ببيئة staging:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
server: https://acme-staging-v02.API.letsencrypt.org/directory
email: you@example.com
privateKeySecretRef:
name: letsencrypt-staging-key
solvers:
- http01:
ingress:
ingressClassName: nginx
حد "الشهادات الجديدة لكل نطاق مسجل" في بيئة staging هو 30,000 في الثانية (مقابل 50 في الأسبوع في بيئة الإنتاج)، وحد "فشل التفويض لكل معرف لكل حساب" هو 200/ساعة (مقابل 5/ساعة).4 هناك عقبة واحدة: شهادات staging تتصل بجذور (roots) بأسماء صريحة مثل "(STAGING) Pretend Pear X1" وهي غير موثوقة من قبل أي متصفح أو عميل حقيقي — لا تضف جذر staging إلى أي مخزن ثقة تستخدمه لأي شيء بخلاف الاختبار.4 إذا كان سير عملك هو CI بدلاً من التكرار اليدوي، فإن Let's Encrypt توصي صراحةً بـ Pebble — خادم اختبار ACME المحلي المصمم لهذا الغرض — بدلاً من staging، لأن staging لا تزال تجري مكالمات شبكة حقيقية ولا توفر طريقة لتزييف DNS أو نجاح التحدي لعمليات اختبار قابلة للتكرار.4
الخلاصة
لما تلاقي Certificate في cert-manager معلقة، دي مشكلة في "سلسلة الإجراءات" مش لغز: استخدام kubectl describe بالتدرج من CertificateRequest، لـ Order، وبعدين Challenge هيعرفك المورد المتعطل بالظبط ورسالة الخطأ بتاعته في كل مرة تقريبًا، والخطأ ده دايمًا بيقع تحت واحد من تلات احتمالات — غلط في إعدادات الشبكة أو الـ ingress لـ HTTP-01، أو مشكلة في انتشار الـ DNS أو اكتشاف الـ zone لـ DNS-01، أو إنك وصلت لحدود استخدام Let's Encrypt وإنت مش عارف. اختبر إعدادات الـ issuer الجديدة على بيئة staging الخاصة بـ Let's Encrypt الأول، واستخدم الـ annotation بتاع issue-temporary-certificate بس كحل مؤقت لحالة tls: handshake failure المحددة، مش كحل عام. لمسارات عمل تصحيح أخطاء الكلاستر ذات الصلة، شوف أدلتنا عن تصحيح أخطاء الـ pods باستخدام الحاويات المؤقتة (ephemeral containers) لما kubectl exec ميكونش فيها shell، و تحديثات Helm الآمنة والمتكررة (idempotent)، و أتمتة شهادات HTTPS بره Kubernetes باستخدام Caddy.
Footnotes
-
cert-manager, "Troubleshooting," https://cert-manager.io/docs/troubleshooting/ — official resource chain diagram,
kubectl describeguidance, and exact status/event message formats. Fetched 2026-07-08. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 -
cert-manager, "Troubleshooting Problems with ACME / Let's Encrypt Certificates," https://cert-manager.io/docs/troubleshooting/acme/ — Order/Challenge debugging steps, HTTP-01/DNS-01 failure modes,
issue-temporary-certificateandhttp01-edit-in-placeannotations. Fetched 2026-07-08. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 -
Let's Encrypt، "Rate Limits،" https://letsencrypt.org/docs/rate-limits/ (آخر تحديث في 12 يونيو 2025) — قيم حدود المعدل للإنتاج، استثناءات تجديد ARI، سياسة عدم إعادة تعيين الحدود عند الإلغاء. تم الجلب في 08-07-2026. ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Let's Encrypt، "Staging Environment،" https://letsencrypt.org/docs/staging-environment/ (آخر تحديث في 10 أبريل 2026) — رابط ACME لبيئة الاختبار، قيم حدود المعدل للاختبار، أسماء الجذور غير الموثوقة للاختبار، توصية Pebble لـ CI. تم الجلب في 08-07-2026. ↩ ↩2 ↩3 ↩4 ↩5
-
cert-manager، "ACME Orders and Challenges،" https://cert-manager.io/docs/concepts/acme-orders-challenges/ — جدولة التحديات، التزامن الافتراضي لـ 60 تحديًا، فاصل إعادة محاولة الفحص الذاتي لمدة 10 ثوانٍ، قواعد اكتشاف التعارض. تم الجلب في 08-07-2026. ↩ ↩2