راهاندازی cert-manager برای صدور و تمدید خودکار گواهی SSL در Kubernetes خودمیزبان
اگر کلاستر Kubernetes را خودتان روی VPS یا سرور اختصاصی بالا آوردهاید (با kubeadm یا K3s)، مثل سرویسهای ابری نیستید که گواهی SSL را خودکار برایتان بسازند. این کار باید دستی مدیریت شود، مگر اینکه cert-manager را نصب کنید. در این مقاله نصب آن با Helm، ساخت ClusterIssuer برای Let's Encrypt و وصل کردنش به Ingress را قدم به قدم میبینیم.

cert-manager چیست و چه مشکلی را حل میکند
cert-manager یک کنترلر داخل کلاستر است که گواهی SSL را از یک مرجع صدور مثل Let's Encrypt میگیرد، آن را به صورت Secret در namespace موردنظر ذخیره میکند و قبل از انقضا خودش تمدیدش میکند. بدون آن، هر بار که گواهی رو به اتمام است باید certbot را دستی اجرا کنید و Secret را بهروزرسانی کنید؛ کاری که در یک کلاستر با چند Ingress به سرعت فراموش میشود.
روی ابرهای عمومی این کار اغلب توسط Load Balancer مدیریتشده انجام میشود. در Kubernetes خودمیزبان این لایه وجود ندارد، پس cert-manager همان نقش را روی خود کلاستر بازی میکند.
پیشنیازها
قبل از شروع این چند مورد باید آماده باشد:
- کلاستر در حال اجرا (با kubeadm یا با K3s)، با
kubectlمتصل به آن - Ingress controller نصبشده (nginx-ingress رایجترین گزینه است)
- یک دامنه یا سابدامنه که رکورد A آن به IP عمومی سرور (یا LoadBalancer/NodePort) اشاره کند
- Helm نصب روی ماشینی که از آن kubectl اجرا میکنید
اگر nginx-ingress هنوز نصب نیست، اول آن را راه بیندازید و با یک دامنه تست مطمئن شوید ترافیک HTTP به Ingress میرسد. cert-manager بدون Ingress سالم هیچ گواهیای نمیتواند بگیرد، چون چالش HTTP-01 از همین مسیر رد میشود.
نصب cert-manager با Helm
ابتدا CRDهای مورد نیاز cert-manager را نصب کنید، بعد chart را با Helm بیاورید:
kubectl create namespace cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.15.3/cert-manager.crds.yaml
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--version v1.15.3
بعد از چند ثانیه سه پاد باید در وضعیت Running باشند:
kubectl get pods -n cert-manager
اگر یکی از پادها (معمولا cert-manager-webhook) مدت زیادی در Pending یا CrashLoopBackOff بماند، احتمالا منابع CPU/RAM نود کم است یا DNS داخلی کلاستر (CoreDNS) درست کار نمیکند. یک دستور سریع برای چک کردن مصرف منابع:
kubectl top pods -n cert-manager
ساخت ClusterIssuer برای Let's Encrypt
cert-manager خودش گواهی صادر نمیکند؛ به یک Issuer میگوید از کجا بگیرد. برای کلاستری که چند namespace دارد، ClusterIssuer بهتر از Issuer معمولی است چون در کل کلاستر قابل استفاده است، نه فقط یک namespace.
Let's Encrypt دو محیط دارد: staging برای تست (محدودیت نرخ خیلی سبکتر، ولی مرورگر به گواهیاش اعتماد نمیکند) و production برای گواهی واقعی. بهتر است اول روی staging تست کنید تا محدودیت روزانه production را هدر ندهید.
فایل cluster-issuer-staging.yaml:
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
بعد از تست موفق، همان فایل را برای production کپی کنید و فقط server و نامها را عوض کنید:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: you@example.com
privateKeySecretRef:
name: letsencrypt-prod-key
solvers:
- http01:
ingress:
ingressClassName: nginx
kubectl apply -f cluster-issuer-staging.yaml
kubectl apply -f cluster-issuer-prod.yaml
برای چک کردن که Issuer سالم است:
kubectl describe clusterissuer letsencrypt-prod
اگر در بخش Status فیلد Ready: True را دیدید یعنی ارتباط با Let's Encrypt برقرار است.
| محیط | کاربرد | محدودیت نرخ | اعتماد مرورگر |
|---|---|---|---|
| staging | تست تنظیمات | ۳۰ هزار گواهی در هفته | ندارد (هشدار امنیتی نشان میدهد) |
| production | گواهی واقعی سایت | ۵۰ گواهی در هفته برای هر دامنه ثبتشده | دارد |
صدور گواهی از طریق Ingress
راحتترین راه، اضافه کردن annotation به Ingress موجود است؛ cert-manager خودش یک منبع Certificate میسازد و درخواست را پیش میبرد:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: my-app-tls
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-svc
port:
number: 80

بعد از apply کردن، cert-manager به صورت خودکار یک Certificate و یک CertificateRequest میسازد. وضعیتش را اینطور میبینید:
kubectl get certificate -A
kubectl describe certificate my-app-tls
اگر در describe خط Status: Issued ظاهر شد، گواهی صادر شده و داخل Secret با نام my-app-tls نشسته. اگر چند دقیقه در حالت Pending ماند، سراغ رویدادها بروید:
kubectl get events --field-selector involvedObject.name=my-app-tls
رایجترین دلیل گیر کردن، رکورد DNS است که هنوز به IP سرور نرسیده یا پورت ۸۰ از بیرون بسته است — چالش HTTP-01 دقیقا از همین پورت رد میشود.
تمدید خودکار چطور کار میکند
گواهیهای Let's Encrypt ۹۰ روز اعتبار دارند. cert-manager بهطور پیشفرض ۳۰ روز قبل از انقضا (یا طبق مقدار renewBefore که در Certificate تنظیم میکنید) خودش فرآیند تمدید را دوباره اجرا میکند، بدون اینکه Ingress یا Secret را دست بزنید. کافی است یک بار منابع را درست بسازید؛ از آن به بعد تنها کاری که باقی میماند چک دورهای سلامت است:
kubectl get certificate -A -o wide
ستون READY باید True باشد و ستون کنار آن تاریخ انقضای فعلی را نشان میدهد.
نکات برای VPS و سرور اختصاصی خودمیزبان
روی سرور ابری عمومی این مسائل معمولا توسط ارائهدهنده حل شده، اما روی VPS یا سرور اختصاصی خودتان مسئولشان هستید:
- اگر چند زیردامنه یا wildcard (مثل
*.example.com) لازم دارید، چالش HTTP-01 کافی نیست؛ باید solver را به DNS-01 عوض کنید و API ارائهدهنده DNS را به ClusterIssuer معرفی کنید. - پادهای cert-manager بهطور مجموع حدود ۱۰۰ تا ۲۰۰ مگابایت RAM مصرف میکنند؛ روی VPS با منابع محدود این را در برنامهریزی ظرفیت حساب کنید.
- فایروال سرور باید پورت ۸۰ را برای چالش HTTP-01 باز نگه دارد، حتی اگر همه ترافیک واقعی از ۴۴۳ رد میشود.
- Secretهای حاوی کلید خصوصی را backup بگیرید؛ اگر namespace cert-manager را اشتباهی پاک کنید، باید همه گواهیها را از نو بگیرید.
اگر هنوز تصمیم نگرفتهاید روی چه زیرساختی این کلاستر را بالا بیاورید، سرور مجازی آریانت منابع کافی برای یک کلاستر K3s کوچک یا یک نود kubeadm تست دارد، با پهنای باند و IP اختصاصی که چالش HTTP-01 را بدون پیچیدگی اضافه انجام میدهد.
سؤالات متداول
آیا cert-manager برای گواهی وایلدکارد هم کار میکند؟ بله، اما باید solver را از HTTP-01 به DNS-01 تغییر دهید و دسترسی API ارائهدهنده DNS دامنه را به ClusterIssuer بدهید.
روی K3s هم همین مراحل جواب میدهد؟ بله، نصب و تنظیمات یکسان است؛ تنها تفاوت اینکه K3s بهصورت پیشفرض Traefik دارد، پس باید annotation و ingressClassName را متناسب با آن تنظیم کنید یا Traefik را با nginx-ingress جایگزین کنید.
اگر گواهی تمدید نشود چه اتفاقی میافتد؟
سایت با خطای گواهی منقضی به بازدیدکننده نشان داده میشود. به همین دلیل چک دورهای kubectl get certificate -A یا یک آلارم مانیتورینگ روی تاریخ انقضا توصیه میشود.
استفاده از cert-manager و Let's Encrypt هزینه دارد؟ نه، هم cert-manager متنباز و رایگان است و هم Let's Encrypt گواهی را بدون هزینه صادر میکند؛ فقط باید در محدودیت نرخ هفتگی آن بمانید.




