• HAProxy 没监听 6443,端口不通、nc 报 Connection refused;

  • 端口通了以后加入新控制平面节点报错:APIServer 证书 SAN 里没有负载均衡 IP 192.168.31.2,TLS 校验失败;

    后面给出的全套操作,就是修复证书缺少 LB IP 的完整流程,中间又遇到了 kubeadm 执行证书重生成时 CRI 多容器运行时冲突报错。

先看懂抓包 + HAProxy 排查日志(前半段)

1. tcpdump 抓包内容解读

plaintext

IP 192.168.31.6.xxx > aishitou(192.168.31.2).6443 Flags [R.]
  • [R.] = TCP Reset 重置包,收到连接直接断开;

  • 192.168.31.6 是新要加入的 Master 节点,主动发 SYN 去连 31.2:6443;

  • 但 31.2 机器直接回 RST,拒绝所有连 6443 的请求。

2. 你在 192.168.31.2(aishitou,HAProxy LB 节点)排查

plaintext

sudo ss -tulpn | grep 6443
# 输出里只有 6433、8081 是haproxy监听,没有 6443

问题根源:haproxy.cfg 配置写错 / 漏了 6443 监听段,HAProxy 正常运行但根本没绑定 6443 端口。

  • nc -zv 192.168.31.2 6443 → Connection refused:端口无程序监听,内核直接回 RST,对应抓包大量 [R.] 包;

  • 你执行启停 haproxy、确认进程,最终修正配置后 ss 能看到 0.0.0.0:6443 LISTEN,nc 连通正常。

二、端口通了,但 kubeadm join 新 Master 报错核心原因

报错原文关键:

plaintext

tls: failed to verify certificate: x509: certificate is valid for 10.96.0.1, 192.168.31.19, not 192.168.31.2
  1. 原始集群初始化 kubeadm init 时,只把原 Master 物理 IP 192.168.31.19、ServiceIP 10.96.0.1 写入 APIServer 证书的 Subject Alternative Name(SAN);

  2. 现在你通过 LB 地址 192.168.31.2 访问 apiserver;

  3. TLS 握手时客户端(新节点 kubeadm)校验服务端证书:证书里没写 192.168.31.2,判定证书无效,直接拒绝加入集群。

简单类比:证书好比门牌号,只登记了 19 号房,现在你从 2 号门进来,系统不认这个地址,不让进门。

三、给出的整套修复操作分步解释

步骤 1:备份 + 删除旧 apiserver 证书

plaintext

sudo mkdir -p /etc/kubernetes/pki/backup
sudo cp apiserver.* 备份目录
sudo rm apiserver.crt apiserver.key
  • 备份:防止改错证书集群彻底瘫痪;

  • 删除旧公私钥:让 kubeadm 可以重新生成全新证书。

步骤 2:创建临时 kubeadm 配置,追加 LB IP 到 certSANs

yaml

apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: stable-1.28
apiServer:
  certSANs:
    - "127.0.0.1"
    - "10.96.0.1"
    - "192.168.31.19"
    - "192.168.31.2"  # 关键:把负载均衡IP加入证书信任列表

certSANs 就是证书里允许访问 apiserver 的 IP / 域名清单,新增 LB 地址后,新证书会带上这个 IP。

步骤 3:执行命令重新生成 apiserver 证书(这里抛出新报错)

plaintext

sudo kubeadm init phase certs apiserver --config /tmp/apiserver-san.yaml

报错:

plaintext

Found multiple CRI endpoints on the host. Please define which one do you wish to use by setting the 'criSocket' field
unix:///var/run/containerd/containerd.sock, unix:///var/run/cri-dockerd.sock
  • 你的 Master 机器同时装了 containerd + cri-dockerd 两套容器运行时;

  • kubeadm 不知道该连哪个 CRI,缺少 criSocket 配置字段,命令执行中断;

  • 解决办法:临时 yaml 里补充 criSocket: unix:///var/run/containerd/containerd.sock。

步骤 4:重启 kube-apiserver 容器加载新证书

apiserver 是静态 Pod,证书文件变更后不会自动重载,必须重启容器:

  1. crictl 列出正在运行的 kube-apiserver 容器;

  2. crictl restart 重启容器;

  3. openssl 命令校验证书内容,确认输出包含 192.168.31.2,证明修复成功。

步骤 5:重新生成集群加入凭证

  1. kubeadm init phase upload-certs --upload-certs:把控制平面证书加密上传到集群 secret,新增 Master 节点需要这个密钥同步全部证书;

  2. kubeadm token create --print-join-command:生成新的集群加入命令(token 会过期,旧 token 失效要重建)。

步骤 6:新节点重新执行 join 命令

携带 4 个关键参数:

  1. LB 地址 192.168.31.2:6443(统一接入入口);

  2. 集群临时 token;

  3. CA 证书 hash,校验根证书合法性;

  4. --control-plane:代表这台节点也要成为 Master 控制平面;

  5. --certificate-key:同步集群所有控制平面证书。

四、核心原理通俗翻译

  1. K8s APIServer TLS 证书校验机制

    kubeadm 初始化集群时,会生成 apiserver 专用 TLS 证书,证书里会记录所有合法访问地址(SAN 列表)。客户端无论 kubectl、kubeadm、节点,连接 apiserver 时都会校验:你访问的 IP / 域名必须出现在证书 SAN 里,否则判定中间人攻击,直接断开连接。

    搭建高可用集群引入 LB 后,LB IP 不在原始 SAN 列表,就会出现你遇到的 x509 证书校验失败。

  2. kubeadm 证书管理逻辑

    kubeadm 提供 init phase certs apiserver 子命令,支持单独重建 apiserver 证书,无需重新初始化整个集群;通过自定义 ClusterConfiguration 配置修改 certSANs,就能给证书追加新增负载均衡 IP。

  3. 多 Master 集群证书同步逻辑

    加入新控制平面节点和普通 worker 节点不同:Master 需要完整一套集群 CA、etcd、apiserver 证书。--certificate-key 参数就是用来解密集群内加密存储的证书 secret,让新 Master 同步全部证书文件。

  4. HAProxy 6443 端口作用

    多 Master 场景下每个节点都跑 apiserver,HAProxy 监听 6443 做四层 TCP 转发,对外提供统一接入点,所有节点、kubectl、新 Master 都只连 LB 地址,不用区分单个 MasterIP,实现故障自动切换。