Установка Cert‑Manager и выпуск сертификатов Let's Encrypt в Kubernetes

Кратко о Cert‑Manager
Cert‑Manager — это контроллер Kubernetes для управления сертификатами TLS. Он автоматизирует выпуск, проверку и продление сертификатов от разных поставщиков (Let’s Encrypt, HashiCorp Vault, Venafi, собственная подпись и прочие). Cert‑Manager следит за сроками действия сертификатов и обновляет их до истечения срока.
Ключевые объекты Cert‑Manager (в одной строке):
- Issuer / ClusterIssuer — параметризуют CA и способ получения сертификата.
- Certificate — namespaced ресурс, который ссылается на Issuer/ClusterIssuer и автоматически обновляется.
- CertificateRequest — запрос на выпуск сертификата.
- ACME Order / Challenge — внутренняя модель для взаимодействия с ACME (Let’s Encrypt).
- Webhook — валидация и конверсия CRD.
- CA Injector — внедряет CA в манифесты webhook’ов.
Важно: этот материал фокусируется на установке через Helm и интеграции с Ingress (HTTP‑01 challenge). Предполагается базовое знание Kubernetes и Ingress.
Что мы сделаем
- Проверим Ingress Controller в кластере
- Установим Cert‑Manager через Helm
- Создадим манифесты для образца приложения (3 приложения nginx)
- Настроим ClusterIssuer для Let’s Encrypt (staging и production)
- Развернём приложение и Ingress с аннотацией cert‑manager
- Проверим сертификаты, секреты и доступ по HTTPS
Предпосылки
- Аккаунт в облаке (например, AWS).
- Рабочий Kubernetes‑кластер.
- NGINX Ingress Controller в кластере.
- Helm v3 (в примере использована v3.5.3).
- S3 для бэкапов/хранилища (если используется).
- Доменное имя и настройка DNS (A/ALIAS/Кластерный балансировщик).
- IAM с правами администратора (для примера на AWS).
Примечание: проверки по установке Ingress Controller, Helm и созданию кластера приведены как ссылки в оригинале; здесь предполагается, что вы уже прошли эти шаги.
Проверка Ingress Controller в кластере
Убедитесь, что контроллер Ingress запущен:
kubectl get podskubectl get svcЕсли в выводе виден nginx‑ingress (или иной ingress controller), можно продолжать.
Установка Cert‑Manager через Helm
Пример с Helm (в исходном блоге использовался локальный бинарь ./helm — у вас может быть глобальная команда helm):
kubectl create namespace cert-managerhelm repo add jetstack https://charts.jetstack.iohelm repo update
helm install cert-manager jetstack/cert-manager --namespace cert-manager --version v1.2.0 --set installCRDs=true
Проверьте созданные поды в namespace cert‑manager:
kubectl get pods -n cert-manager
Ожидаемые компоненты: cert‑manager, cert‑manager‑webhook, cert‑manager‑cainjector.
Создание манифестов для примера приложения и Issuer’ов
Ниже — mанифесты из оригинала. Сохраните их как файлы и примените командой kubectl apply -f <файл>.
Создаём 1‑nginx‑main‑app.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
run: nginx
name: nginx-deploy-main
spec:
replicas: 1
selector:
matchLabels:
run: nginx-main
template:
metadata:
labels:
run: nginx-main
spec:
containers:
- image: nginx
name: nginx
---
apiVersion: v1
kind: Service
metadata:
name: nginx-deploy-main
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
selector:
run: nginx-mainСоздаём 2‑nginx‑green‑app.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
run: nginx
name: nginx-deploy-green
spec:
replicas: 1
selector:
matchLabels:
run: nginx-green
template:
metadata:
labels:
run: nginx-green
spec:
volumes:
- name: webdata
emptyDir: {}
initContainers:
- name: web-content
image: busybox
volumeMounts:
- name: webdata
mountPath: "/webdata"
command: ["/bin/sh", "-c", 'echo "I am GREEN
" > /webdata/index.html']
containers:
- image: nginx
name: nginx
volumeMounts:
- name: webdata
mountPath: "/usr/share/nginx/html"
---
---
apiVersion: v1
kind: Service
metadata:
name: nginx-deploy-green
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
selector:
run: nginx-green Создаём 3‑nginx‑blue‑app.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
run: nginx
name: nginx-deploy-blue
spec:
replicas: 1
selector:
matchLabels:
run: nginx-blue
template:
metadata:
labels:
run: nginx-blue
spec:
volumes:
- name: webdata
emptyDir: {}
initContainers:
- name: web-content
image: busybox
volumeMounts:
- name: webdata
mountPath: "/webdata"
command: ["/bin/sh", "-c", 'echo "I am BLUE
" > /webdata/index.html']
containers:
- image: nginx
name: nginx
volumeMounts:
- name: webdata
mountPath: "/usr/share/nginx/html"
---
apiVersion: v1
kind: Service
metadata:
name: nginx-deploy-blue
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
selector:
run: nginx-blueСоздаём Ingress для staging (4‑tls‑ingress.yaml):
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
cert-manager.io/cluster-issuer: letsencrypt-staging
name: ingress-resource-3
spec:
tls:
- hosts:
- kops.devopslee.com
secretName: sample-kubernetes-tls
rules:
- host: kops.devopslee.com
http:
paths:
- path: /
backend:
serviceName: nginx-deploy-main
servicePort: 80
- path: /blue
backend:
serviceName: nginx-deploy-blue
servicePort: 80
- path: /green
backend:
serviceName: nginx-deploy-green
servicePort: 80Ingress для production (5‑tls‑ingress‑prod‑issuer.yaml) отличается только аннотацией:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
cert-manager.io/cluster-issuer: letsencrypt-production
name: ingress-resource-3
spec:
tls:
- hosts:
- kops.devopslee.com
secretName: sample-kubernetes-tls
rules:
- host: kops.devopslee.com
http:
paths:
- path: /
backend:
serviceName: nginx-deploy-main
servicePort: 80
- path: /blue
backend:
serviceName: nginx-deploy-blue
servicePort: 80
- path: /green
backend:
serviceName: nginx-deploy-green
servicePort: 80ClusterIssuer для Let’s Encrypt Staging (staging_issuer.yaml):
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
# Email address used for ACME registration
email: your-email-id-here
server: https://acme-staging-v02.api.letsencrypt.org/directory
privateKeySecretRef:
# Name of a secret used to store the ACME account private key
name: letsencrypt-staging-private-key
# Add a single challenge solver, HTTP01 using nginx
solvers:
- http01:
ingress:
class: nginxClusterIssuer для Let’s Encrypt Production (production_issuer.yaml):
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-production
spec:
acme:
# Email address used for ACME registration
email: your-email-id-here
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
# Name of a secret used to store the ACME account private key
name: letsencrypt-production-private-key
# Add a single challenge solver, HTTP01 using nginx
solvers:
- http01:
ingress:
class: nginxВсе файлы можно хранить в Git и применять из репозитория.
Установка ClusterIssuer (staging и production)
Применяем staging Issuer:
kubectl apply -f cluster-issuer/staging_issuer.yamlЛогирование cert‑manager поможет наблюдать процесс:
kubectl logs -n cert-manager -f deploy/cert-managerПосле успешного применения появится секрет с приватным ключом ACME‑аккаунта:
kubectl get secret letsencrypt-staging-private-key -n cert-manager -o json
Аналогично для production:
kubectl apply -f cluster-issuer/production_issuer.yamlkubectl get secret letsencrypt-production-private-key -n cert-manager -o json
Развёртывание образца приложения
Применяем три приложения:
kubectl apply -f sample-app/1-nginx-main-app.yaml
kubectl apply -f sample-app/2-nginx-green-app.yaml
kubectl apply -f sample-app/3-nginx-blue-app.yamlПроверяем ресурсы:
kubectl get deployments
kubectl get pods
kubectl get svc
Развёртывание Ingress и автоматический выпуск сертификата (staging)
Применяем Ingress со ссылкой на letsencrypt‑staging:
kubectl apply -f sample-app/4-tls-ingress.yamlПроверяем Ingress и его состояние:
kubectl get ingress
kubectl describe ingress ingress-resource-3
Cert‑Manager создаст объекты Certificate, CertificateRequest, Order и Challenges:
kubectl get certificate -A
kubectl get certificaterequests.cert-manager.io -A
kubectl get orders.acme.cert-manager.io -A
kubectl get challenges.acme.cert-manager.io -AИ секрет с TLS материалами:
kubectl get secret sample-kubernetes-tls -o yaml
Переход по HTTPS покажет предупреждение в браузере, если использован staging (невалидный CA для браузеров):

Переход на production Issuer
Удаляем staging Ingress и создаём Ingress с production‑issuer:
kubectl delete -f sample-app/4-tls-ingress.yaml
kubectl apply -f sample-app/5-tls-ingress-prod-issuer.yamlПроверяем, что cert‑manager обработал запрос и сертификат выдан от Let’s Encrypt production. При корректной конфигурации браузер не покажет предупреждений.


Отладка и часто встречаемые проблемы
- ACME challenge не проходит: проверьте, что Ingress доступен извне и DNS указывает на ваш балансировщик.
- Неправильный класс Ingress: убедитесь, что в ClusterIssuer solver указан ingress.class: nginx, если у вас nginx controller.
- Firewall / Security Group блокирует HTTP (80): HTTP‑01 требует доступ по 80 порту.
- Секрет не создаётся: посмотрите логи cert‑manager и описания Certificate/CertificateRequest для ошибок.
Команды для диагностики:
kubectl describe certificaterequest -n
kubectl describe challenge -n
kubectl logs -n cert-manager deploy/cert-manager Резервный план и ограничения
- Если DNS‑провайдер не поддерживает быструю пропагацию, ACME‑challenge по HTTP может падать — используйте DNS‑01 (требует API доступа к DNS).
- Для приватных кластеров без внешнего доступа используйте Vault/ACME DNS‑01 или внутренний CA.
Контрольные списки по ролям
Администратор кластера:
- Создать namespace cert‑manager
- Установить Helm chart с installCRDs=true
- Обеспечить доступ к 80/443 извне
- Настроить RBAC для cert‑manager
DevOps-инженер:
- Подготовить ClusterIssuer и email для ACME
- Настроить DNS и проверить A/ALIAS записи
- Развернуть Ingress с аннотацией cert-manager.io/cluster-issuer
Разработчик приложения:
- Убедиться, что сервисы работают на ожидаемых портах
- Добавить readiness/liveness probes
- Тестировать доступ через Ingress по HTTP и HTTPS
Мини‑методология выпуска TLS‑сертификата (шаги)
- Установить cert‑manager и CRD.
- Настроить ClusterIssuer (staging для тестов, production для реального трафика).
- Развернуть приложение и Service.
- Создать Ingress с аннотацией cert‑manager и TLS секцией.
- Проверить объекты Certificate / CertificateRequest / Order / Challenge.
- Подтвердить получение секрета и доступ по HTTPS.
- Настроить мониторинг и оповещения на ошибки продления.
Критерии приёмки
- Certificate успешно создан и имеет статус Ready.
- Секрет sample-kubernetes-tls содержит tls.crt и tls.key.
- HTTPS на домене доступен без предупреждений (для production).
- Cert‑Manager автоматически продлевает сертификат за N дней до истечения (N определяется в spec.Certificate).
Тесты и приёмочные сценарии
- Применить staging ClusterIssuer и Ingress → ожидать создание Certificate и секретов.
- Удалить Ingress → Certificate не должен автоматически удалять секрет (поведение зависит от spec).
- Переключиться на production ClusterIssuer и убедиться, что сертификат меняется без аварийного простоя.
Примеры, когда этот подход не сработает
- Отсутствует внешний доступ по HTTP (порт 80) — HTTP‑01 не пройдёт.
- DNS‑провайдер не предоставляет API для автоматизации (для DNS‑01 потребуется ручная подстановка TXT).
- Приватная сеть, где внешний ACME‑сервер не видит ваш Ingress — нужен внутренний CA.
Факт‑бокс — ключевые объекты и поведение
- Issuer / ClusterIssuer — задаёт параметры CA и challenge solver.
- Certificate — создает Secret, содержащий tls.crt/tls.key.
- ACME workflow: CertificateRequest → Order → Challenge → Validation → Certificate.
- Webhook и CA injector обеспечивают корректную работу CRD и автоматическую подстановку CA в webhook’ы.
Диаграмма принятия решения (Mermaid)
flowchart TD
A[Нужен TLS для домена?] -->|Да| B{Есть внешний доступ по HTTP?
}
B -- Да --> C[Использовать HTTP-01 через Ingress]
B -- Нет --> D{Можно ли управлять DNS через API?}
D -- Да --> E[Использовать DNS-01]
D -- Нет --> F[Использовать внутренний CA или Vault]
A -->|Нет| G[Оставить HTTP]Безопасность и эксплуатация
- Храните секреты TLS в Kubernetes в зашифрованном виде (например, использовать KMS или Sealed Secrets).
- Контролируйте доступ к namespace cert‑manager и ClusterIssuer ресурсам.
- Логи cert‑manager не должны содержать приватных ключей.
Краткий глоссарий (1‑строка)
- ACME — протокол автоматического выпуска сертификатов (используется Let’s Encrypt).
- HTTP‑01 — ACME challenge, где CA проверяет доступность ресурса по HTTP.
- DNS‑01 — ACME challenge через TXT запись в DNS.
Локальные рекомендации и ошибки для региона
- При использовании облачных провайдеров убедитесь, что DNS записи обновляются быстро; в некоторых регионах возможна задержка репликации DNS.
- Для корпоративных сред с жёсткой сетевой политикой предпочтительнее DNS‑01 или внутренний CA.
Заключение
Мы прошли полный путь: установка Cert‑Manager через Helm, создание ClusterIssuer для Let’s Encrypt (staging и production), развёртывание трёх демонстрационных приложений и настройка Ingress с автоматическим выпуском TLS‑сертификатов. Cert‑Manager автоматизирует рутинную часть управления сертификатами, но требует корректной настройки сетевого доступа, DNS и ролей доступа.
Краткие рекомендации для эксплуатации: используйте staging для тестов, всегда проверяйте доступность HTTP/80 перед запуском HTTP‑01, поставьте мониторинг и оповещения о неудачных продлениях.
Дополнительно проверьте официальную документацию Cert‑Manager для сложных сценариев (DNS‑01, Vault, Venafi и т.д.).
Похожие материалы
Несколько аккаунтов Skype: Multi Skype Launcher
Журнал для работы: повысить продуктивность
Персональные звуки уведомлений на Android
Скачивание шоу Hulu для офлайн‑просмотра
Microsoft Start: персонализированная новостная лента