• 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,实现故障自动切换。