Kubernetes集群证书管理:从“node not found”到高可用运维实战

凌晨三点,手机突然响起刺耳的告警声。屏幕上跳动着熟悉的红色警告:“kubelet.go:2461] Error getting node err=node "k8s-master" not found”。你揉了揉惺忪的睡眼,心里一沉——生产环境的Kubernetes集群出问题了。这已经不是第一次遇到证书过期导致的故障,但每次处理都像是在和时间赛跑,稍有不慎就会导致服务中断。

Kubernetes集群的证书管理,对于很多运维工程师来说,就像房间里的大象——大家都知道它很重要,但往往等到问题爆发时才匆忙应对。证书过期导致的节点失联、API Server拒绝连接、Pod调度失败等问题,已经成为生产环境中最常见的“定时炸弹”。今天,我们就来深入探讨如何系统化地管理Kubernetes证书,从被动救火转向主动预防。

1. Kubernetes证书体系深度解析

要真正掌握证书管理,首先得理解Kubernetes的证书架构。很多人只知道kubeadm certs renew all这个命令,却不清楚背后到底发生了什么。实际上,一个标准的Kubernetes集群包含多种类型的证书,每种都有其特定的生命周期和作用域。

1.1 证书类型与作用域

Kubernetes集群中的证书主要分为以下几类:

证书类型默认有效期主要用途影响范围
CA证书10年根证书,签发其他所有证书整个集群
API Server证书1年API Server的TLS服务端证书控制平面通信
etcd证书1年etcd集群内部通信数据存储层
kubelet客户端证书1年kubelet向API Server认证节点注册与心跳
front-proxy证书1年聚合层代理通信API扩展功能
Service Account令牌无期限Pod内服务账户认证应用权限控制

这里有个常见的误解:很多人认为只要更新了API Server证书就万事大吉。实际上,证书链的完整性才是关键。如果CA证书过期,所有由其签发的证书都会失效;如果某个中间证书过期,依赖它的组件也会出现问题。

1.2 证书存储位置与访问权限

不同组件的证书存储在不同的位置,了解这些位置对于故障排查至关重要:

# 查看集群证书存储位置
ls -la /etc/kubernetes/pki/

# 典型目录结构
/etc/kubernetes/pki/
├── apiserver.crt              # API Server服务端证书
├── apiserver.key
├── apiserver-etcd-client.crt  # API Server访问etcd的客户端证书
├── apiserver-etcd-client.key
├── apiserver-kubelet-client.crt  # API Server访问kubelet的客户端证书
├── apiserver-kubelet-client.key
├── ca.crt                     # 集群根CA证书
├── ca.key                     # CA私钥(需严格保护)
├── etcd/
│   ├── ca.crt                 # etcd集群CA证书
│   ├── healthcheck-client.crt
│   ├── peer.crt               # etcd节点间通信证书
│   └── server.crt             # etcd服务端证书
└── front-proxy-ca.crt         # 前端代理CA证书

注意ca.key是集群的根私钥,一旦泄露或丢失,整个集群的证书体系都需要重建。务必将其备份到安全的位置,并设置严格的访问权限。

2. 证书过期故障的精准诊断

当出现"node not found"错误时,证书过期只是众多可能原因之一。我们需要一套系统化的诊断流程,而不是盲目地执行证书更新命令。

2.1 症状分析与初步定位

首先,通过几个关键命令快速判断问题范围:

# 检查kubelet服务状态
systemctl status kubelet -l

# 查看kubelet日志中的关键错误
journalctl -u kubelet --since "1 hour ago" | grep -E "(certificate|expired|not found|refused)"

# 测试API Server连通性
curl -k https://<API_SERVER_IP>:6443/healthz
# 或者使用kubectl测试
kubectl cluster-info --request-timeout=5s

如果看到类似下面的错误,很可能是证书问题:

x509: certificate has expired or is not yet valid
Unable to connect to the server: x509: certificate has expired

2.2 证书状态检查工具

手动检查每个证书的过期时间既繁琐又容易遗漏。我通常使用一个自制的检查脚本:

#!/bin/bash
# check-k8s-certs.sh - Kubernetes证书过期检查工具

CERT_DIR="/etc/kubernetes/pki"
KUBECONFIG_DIR="/etc/kubernetes"

echo "=== Kubernetes证书过期检查报告 ==="
echo "检查时间: $(date)"
echo ""

# 检查PKI目录下的所有证书
echo "1. PKI证书检查:"
for cert in $(find $CERT_DIR -name "*.crt"); do
    echo "证书: $(basename $cert)"
    openssl x509 -in $cert -noout -dates | grep notAfter
    echo "剩余天数: $(( ($(date -d "$(openssl x509 -in $cert -noout -dates | grep notAfter | cut -d= -f2)" +%s) - $(date +%s)) / 86400 ))"
    echo "---"
done

# 检查kubeconfig中的证书
echo ""
echo "2. Kubeconfig证书检查:"
for config in $KUBECONFIG_DIR/*.conf; do
    if [ -f "$config" ]; then
        echo "配置文件: $(basename $config)"
        # 提取并检查嵌入的证书
        kubectl --kubeconfig=$config config view --raw -o jsonpath='{.users[*].user.client-certificate-data}' | \
            base64 -d | openssl x509 -noout -dates 2>/dev/null || echo "无嵌入证书"
        echo "---"
    fi
done

# 检查Service Account令牌
echo ""
echo "3. Service Account令牌检查:"
for token in $(find /var/run/secrets/kubernetes.io/serviceaccount -name "*.crt" 2>/dev/null); do
    echo "令牌: $(basename $token)"
    openssl x509 -in $token -noout -dates 2>/dev/null || echo "非x509格式"
    echo "---"
done

这个脚本会输出每个证书的过期时间和剩余天数,让你对集群的证书健康状况一目了然。

2.3 网络与配置排查

证书问题有时会与网络配置问题混淆。在确认证书状态前,先排除网络因素:

# 检查网络连通性
ping -c 3 <API_SERVER_IP>
nc -zv <API_SERVER_IP> 6443

# 检查防火墙规则
iptables -L -n | grep 6443
firewall-cmd --list-all  # 对于firewalld

# 检查kubelet配置
cat /etc/kubernetes/kubelet.conf | grep server

如果网络连通性正常,但API Server端口拒绝连接,很可能是API Server本身没有正常启动——这又可能回到证书问题,因为API Server需要有效的证书才能启动。

3. 证书更新操作实战指南

确定了证书问题后,我们需要谨慎地执行更新操作。这里的关键是顺序验证

3.1 标准更新流程

对于使用kubeadm部署的集群,证书更新相对简单,但需要注意执行顺序:

# 1. 备份当前证书(安全第一!)
sudo cp -r /etc/kubernetes/pki /etc/kubernetes/pki.backup.$(date +%Y%m%d)

# 2. 更新所有证书
sudo kubeadm certs renew all

# 3. 查看更新结果
sudo kubeadm certs check-expiration

# 4. 更新kubeconfig文件中的证书
sudo kubeadm init phase kubeconfig all --config /etc/kubernetes/kubeadm-config.yaml

# 5. 分发新的kubeconfig到所有节点
# 对于控制平面节点
sudo cp /etc/kubernetes/admin.conf ~/.kube/config
# 对于工作节点,需要手动更新或重新join

更新后,你会看到类似这样的输出:

Certificate expiration dates:
        Certificate Name                Expiration Date                Residual Time
        admin.conf                     Dec 30 12:00:00 2025 GMT       364d
        apiserver                      Dec 30 12:00:00 2025 GMT       364d
        apiserver-etcd-client          Dec 30 12:00:00 2025 GMT       364d
        apiserver-kubelet-client       Dec 30 12:00:00 2025 GMT       364d
        ...

3.2 组件重启顺序与注意事项

证书更新后,相关组件需要重启才能使用新证书。错误的重启顺序可能导致集群短暂不可用

  1. 首先重启静态Pod控制器

    # 移动静态Pod manifests让kubelet重新拉取
    sudo mv /etc/kubernetes/manifests /etc/kubernetes/manifests.backup
    sudo mkdir /etc/kubernetes/manifests
    # 等待几秒让kubelet检测到变化
    sleep 10
    # 恢复manifests
    sudo mv /etc/kubernetes/manifests.backup/* /etc/kubernetes/manifests/
    
  2. 重启kubelet服务

    sudo systemctl daemon-reload
    sudo systemctl restart kubelet
    
  3. 验证组件状态

    # 等待所有组件就绪
    sleep 30
    
    # 检查组件状态
    kubectl get pods -n kube-system
    kubectl get nodes
    
    # 检查证书是否生效
    kubectl cluster-info
    

重要提示:在生产环境中,建议逐个节点进行证书更新和重启,避免同时影响多个控制平面节点。对于高可用集群,可以先更新备用节点,验证无误后再更新主节点。

3.3 特殊情况处理

场景一:CA证书即将过期

如果CA证书即将过期(剩余时间少于90天),简单的renew命令可能不够:

# 检查CA证书过期时间
sudo kubeadm certs check-expiration | grep ca

# 如果CA证书即将过期,需要重新生成
# 注意:这会重新签发所有证书,需要更复杂的操作
sudo kubeadm init phase certs all --config /etc/kubernetes/kubeadm-config.yaml

场景二:etcd证书问题

etcd证书问题比较隐蔽,因为etcd通常运行在控制平面内部。如果遇到etcd相关错误:

# 检查etcd集群健康状态
kubectl exec -n kube-system etcd-<node-name> -- etcdctl \
  --cert /etc/kubernetes/pki/etcd/peer.crt \
  --key /etc/kubernetes/pki/etcd/peer.key \
  --cacert /etc/kubernetes/pki/etcd/ca.crt \
  --endpoints https://127.0.0.1:2379 endpoint health

# 更新etcd证书
sudo kubeadm certs renew etcd-peer
sudo kubeadm certs renew etcd-server
sudo kubeadm certs renew etcd-healthcheck-client

4. 自动化证书管理与预防策略

手动管理证书终究不是长久之计。在生产环境中,我们需要建立自动化的证书管理机制。

4.1 使用cert-manager实现自动续期

cert-manager是Kubernetes原生的证书管理工具,可以自动处理证书的颁发和续期:

# cert-manager安装(使用helm)
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --version v1.13.0 \
  --set installCRDs=true

# 创建ClusterIssuer(使用自签名CA)
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: selfsigned-issuer
spec:
  selfSigned: {}

为Kubernetes API Server配置自动续期:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: kube-apiserver
  namespace: kube-system
spec:
  secretName: kube-apiserver-cert
  duration: 8760h # 1年
  renewBefore: 720h # 提前30天续期
  issuerRef:
    name: selfsigned-issuer
    kind: ClusterIssuer
  commonName: kube-apiserver
  dnsNames:
  - kubernetes
  - kubernetes.default
  - kubernetes.default.svc
  - kubernetes.default.svc.cluster.local
  - <API_SERVER_IP>
  ipAddresses:
  - 127.0.0.1
  - <API_SERVER_IP>
  usages:
  - server auth
  - client auth

4.2 监控与告警配置

预防胜于治疗。建立完善的监控体系可以在证书过期前及时发现问题:

# Prometheus规则示例 - 证书过期告警
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: k8s-certificate-expiry
  namespace: monitoring
spec:
  groups:
  - name: certificate-expiry
    rules:
    - alert: K8SCertificateExpiringSoon
      expr: kubelet_certificate_manager_client_ttl_seconds < 2592000  # 30天
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "Kubernetes证书即将过期"
        description: "证书 {{ $labels.name }} 将在 {{ $value | humanizeDuration }} 后过期"
    
    - alert: K8SCertificateExpired
      expr: kubelet_certificate_manager_client_ttl_seconds < 0
      for: 1m
      labels:
        severity: critical
      annotations:
        summary: "Kubernetes证书已过期"
        description: "证书 {{ $labels.name }} 已过期 {{ $value | humanizeDuration }}"

4.3 定期维护检查清单

建立定期检查机制,我通常会在每个月的第一个周一执行以下检查:

  1. 证书状态检查

    # 使用之前的检查脚本
    ./check-k8s-certs.sh > /var/log/k8s-cert-check-$(date +%Y%m%d).log
    
    # 检查kubeadm管理的证书
    kubeadm certs check-expiration
    
  2. 集群健康状态验证

    # 检查所有节点状态
    kubectl get nodes -o wide
    
    # 检查核心组件状态
    kubectl get pods -n kube-system
    
    # 检查事件中的异常
    kubectl get events --sort-by='.lastTimestamp' | tail -20
    
  3. 备份验证

    # 验证etcd备份
    etcdctl snapshot status /backup/etcd-snapshot.db
    
    # 验证证书备份
    ls -la /backup/certificates/
    

4.4 灾难恢复演练

证书问题最坏的情况是CA私钥丢失或损坏。这时需要完整的灾难恢复:

# 灾难恢复流程示例
# 1. 从备份恢复CA证书和密钥
sudo cp /backup/certificates/ca.* /etc/kubernetes/pki/

# 2. 重新生成所有证书
sudo kubeadm init phase certs all --config /etc/kubernetes/kubeadm-config.yaml

# 3. 重新生成kubeconfig文件
sudo kubeadm init phase kubeconfig all --config /etc/kubernetes/kubeadm-config.yaml

# 4. 重启所有组件
sudo systemctl restart kubelet

在实际操作中,我发现很多团队忽略了证书管理的系统性。证书过期问题往往在深夜或周末爆发,就是因为缺乏预警机制。建立自动化的证书管理流程,不仅能减少运维负担,更能提高集群的稳定性。

记得有一次,客户的集群在凌晨两点证书过期,导致所有服务中断。我们花了四个小时才完全恢复。从那以后,我坚持在每个集群部署cert-manager,并设置多层告警。现在,证书过期前30天就会收到邮件提醒,前7天会触发电话告警,真正做到了防患于未然。

证书管理看似琐碎,却是Kubernetes运维的基石。掌握这些技巧,你就能从容应对各种证书相关的问题,让集群运行更加稳定可靠。

更多推荐