WEBKT

告别证书噩梦:Kubernetes下百个微服务Let's Encrypt自动化之道

79 0 0 0

在微服务架构盛行的今天,将应用容器化并部署到Kubernetes已是常态。但当服务的数量从个位数膨胀到上百个,并且每个服务都拥有独立的域名,运维的复杂度会呈几何级数增长。其中,“证书管理”无疑是许多DevOps工程师心中的一道坎,尤其是在使用免费、短期有效的Let's Encrypt证书时。

想象一下:每个月都要手动为上百个域名申请或续期证书,填表、验证、部署,这些重复性工作不仅效率低下,而且极易出错。一个不留神,证书过期,线上服务瞬间宕机,这简直是运维人员的噩梦。那么,有没有一种高效、可靠,并且能与现有CI/CD流程无缝集成的自动化方案呢?答案是肯定的:Cert-Manager

为什么手动管理Let's Encrypt证书是噩梦?

  1. 规模化挑战: 随着微服务数量增多,手动操作的耗时与出错率急剧上升。
  2. 续期频率: Let's Encrypt证书通常只有90天有效期,意味着你每隔几个月就得进行一轮“证书大扫除”。
  3. 人为错误: 证书配置错误、密钥泄露风险、忘记续期等,都可能导致生产事故。
  4. 运维负担: 大量精力被消耗在重复性劳动上,无法专注于更有价值的系统优化工作。
  5. CI/CD集成难: 手动流程难以融入自动化部署管道,形成瓶颈。

Cert-Manager:Kubernetes上的证书自动化专家

Cert-Manager是一个强大的Kubernetes附加组件,它能自动为您的Kubernetes服务颁发和管理X.509证书。它支持多种证书颁发机构(CA),包括Let's Encrypt,并能自动处理证书的生命周期,从申请、验证到续期,全程无需人工干预。

Cert-Manager的核心优势:

  • 全生命周期管理: 自动申请、续期和撤销证书。
  • 多CA支持: 不仅支持Let's Encrypt,还支持Vault、ACME、Venafi等。
  • Kubernetes原生集成: 以CRD(Custom Resource Definitions)的方式与Kubernetes深度融合,使用Kubernetes API来管理证书资源。
  • 多种验证方式: 支持HTTP-01和DNS-01挑战,适应不同场景。
  • 高可靠性: 自动重试机制,确保证书顺利颁发。

Cert-Manager工作原理简述

Cert-Manager通过监控Kubernetes集群中的自定义资源(CRD)来工作,主要涉及以下几个核心概念:

  1. IssuerClusterIssuer 定义证书的颁发机构和验证方式。Issuer 作用于特定命名空间,ClusterIssuer 作用于整个集群。通常,我们为了Let's Encrypt的方便,会使用ClusterIssuer
  2. Certificate 定义你想要获取的证书的细节,比如域名、私钥算法、以及引用的IssuerClusterIssuer
  3. OrderChallengeCertificate被创建后,Cert-Manager会为它创建一个Order资源,并根据Issuer的配置发起一个或多个ACMEChallenge(如HTTP-01或DNS-01),以证明您对域名的所有权。
  4. Secret 证书颁发成功后,Cert-Manager会将私钥和证书链存储在一个Kubernetes Secret中,供Ingress控制器或其他服务引用。

部署和配置Cert-Manager

以下是一个基于Helm的快速部署和配置Cert-Manager的示例。

1. 安装Cert-Manager

首先,确保你的Kubernetes集群版本支持Cert-Manager,并添加其Helm仓库:

helm repo add jetstack https://charts.jetstack.io
helm repo update

然后,安装Cert-Manager:

helm install \
  cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --version v1.13.2 \
  --set installCRDs=true # 关键:确保CRD被安装

等待Pod启动并运行正常。

2. 配置ClusterIssuer(以Let's Encrypt DNS-01为例)

对于大量域名管理,DNS-01挑战是首选,因为它支持通配符证书(*.example.com)且不需要服务暴露在公网。这里以Cloudflare作为DNS提供商为例,您需要先获取Cloudflare API Token。

创建一个名为letsencrypt-prod-dns.yaml的文件:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod-dns
spec:
  acme:
    email: your-email@example.com # 替换为您的邮箱,用于接收通知
    server: https://acme-v02.api.letsencrypt.org/directory # 生产环境
    privateKeySecretRef:
      name: letsencrypt-prod-dns-key
    solvers:
    - dns01:
        cloudflare:
          apiTokenSecretRef:
            name: cloudflare-api-token-secret # 引用包含Cloudflare API Token的Secret
            key: api-token # Secret中存储API Token的key

创建Cloudflare API Token Secret:

kubectl create secret generic cloudflare-api-token-secret \
    --from-literal=api-token='YOUR_CLOUDFLARE_API_TOKEN' \
    --namespace cert-manager # 或您部署Cert-Manager的命名空间

注意: 确保这个Secret存在于Cert-Manager能够访问的命名空间。

应用ClusterIssuer:

kubectl apply -f letsencrypt-prod-dns.yaml

验证ClusterIssuer状态:

kubectl get clusterissuer letsencrypt-prod-dns -o yaml

您应该看到Status.ConditionsReadyTrue

3. 创建Certificate资源并与Ingress集成

现在,您可以通过定义Certificate资源来请求证书。最常见的方式是与Ingress资源结合使用,让Ingress控制器(如Nginx Ingress)自动使用颁发的证书。

假设你有一个名为my-service的微服务,需要为api.example.comwww.example.com这两个域名申请证书。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-service-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod-dns # 引用之前创建的ClusterIssuer
spec:
  tls:
  - hosts:
    - api.example.com
    - www.example.com
    secretName: my-service-tls-secret # 证书颁发后将存储在此Secret中
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-service
            port:
              number: 80
  - host: www.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-service-frontend
            port:
              number: 80
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: my-service-cert
  namespace: default # 证书所属的命名空间
spec:
  secretName: my-service-tls-secret # 必须与Ingress中定义的secretName一致
  dnsNames:
  - api.example.com
  - www.example.com
  issuerRef:
    name: letsencrypt-prod-dns
    kind: ClusterIssuer

当这个IngressCertificate资源被创建后,Cert-Manager会自动:

  1. 检测到新的Certificate资源。
  2. 向Let's Encrypt发起证书请求。
  3. 通过DNS-01挑战验证域名所有权。
  4. 获取证书,并将其存储在my-service-tls-secret这个Secret中。
  5. Nginx Ingress控制器会自动发现并使用这个Secret中的证书。
  6. 在证书即将过期时,Cert-Manager会自动触发续期流程。

4. 与CI/CD流水线集成

将Cert-Manager融入CI/CD非常简单:

  • GitOps实践:ClusterIssuerCertificateIngress等所有Kubernetes资源定义存储在Git仓库中。
  • 自动化部署: 您的CI/CD流水线只需负责将这些YAML文件通过kubectl apply -f或Argo CD/Flux CD等工具部署到Kubernetes集群。Cert-Manager会检测到这些资源并自动处理证书。

这样,证书管理就完全自动化了,不再需要人工干预,大大减轻了运维负担。

总结

Cert-Manager彻底解决了Kubernetes微服务环境下Let's Encrypt证书管理的“噩梦”。通过将证书生命周期管理交给一个专业的自动化工具,我们不仅能够显著提高运维效率,减少人为错误,还能确保服务始终运行在安全、可靠的HTTPS连接上,避免因证书过期导致的任何业务中断。对于部署了上百个微服务的团队而言,拥抱Cert-Manager,是提升生产力、保障系统稳定性的必由之路。

DevOps老王 Kubernetes

评论点评