☰
Kubernetes高可用集群二进制部署:CFSSL证书与三节点etcd实践
2026/10/11 11:59:15 网站建设 项目流程

做Kubernetes高可用集群的二进制部署,我向来主张一个顺序:先把证书体系想透,再把etcd集群立起来,最后才轮到kube-apiserver、kube-controller-manager这些控制面组件。原因很简单,etcd是整条控制面的数据底座,而PKI证书又是etcd能安全对外提供服务的前提。这个系列前面铺垫完基础概念之后,到了真正动手的环节,绝大多数人会卡在两条线上:一是CFSSL签发证书时的SAN、profile到底怎么填,二是三个etcd节点起来之后互相之间握手失败、集群状态异常。这篇文章就把这两块完整拆开,把证书生成、分发、etcd三节点部署、验证和常见故障排查一次性讲透,适合正在自己动手搭HA集群、或者已经被kubeadm封装习惯导致对底层生疏的读者。

1. 方案设计:为什么二进制部署先啃PKI和etcd

1.1 二进制部署与kubeadm的核心差异

用kubeadm初始化集群,证书和etcd都是“开箱即用”的,kubeadm init会自动生成一套自签CA,会在第一个控制面节点拉起一个单实例etcd,一切看起来都很顺。但我在实际生产环境里遇到过一个典型的尴尬场景:集群跑了一年,kube-apiserver要扩一个实例出来做负载均衡,结果发现现有证书的SAN里压根没包含新实例的IP和域名,只能重新签证书,然后控制面所有组件逐个滚动重启。这种折腾次数多了,你就会意识到kubeadm帮你做的那些“默认动作”并不适合所有场景。

二进制部署的核心优势是每个组件的运行方式、证书路径、监听地址、数据目录都掌握在自己手里。特别是etcd,用kubeadm装出来的etcd是static pod方式跑在容器里的,日志排查、数据快照、参数调优都要绕一层容器封装,而二进制方式直接交给systemd托管,一切透明,排障路径最短。

如果只是搭一套测试环境,kubeadm确实省事。但如果目标是长期维护一套生产级HA集群,或者需要对控制面做深度定制(比如多租户隔离、审计策略、etcd独立部署到专用机器),二进制部署几乎是必经之路。

1.2 etcd在HA集群里的地位与节点布局

etcd在Kubernetes里的角色相当于整个集群的“记忆中枢”。所有API对象——Pod、Service、ConfigMap、Secret、Deployment、Node状态——都以键值对的形式存放在etcd里。kube-apiserver是无状态服务,多个实例可以并行处理请求,但它们读写的最终一致性完全由etcd保证。

所以etcd的高可用设计是整个集群高可用的前提。生产环境一般用3个或5个节点组成raft组,3节点允许挂1个,5节点允许挂2个。节点数量一定取奇数,这是raft多数派投票机制决定的:写入必须得到超过半数的节点确认才会返回成功。

节点布局上有一个容易被忽视的点:etcd最好部署在独立的机器上,或者至少和kube-apiserver、kubelet做资源隔离。etcd对磁盘IO延迟极其敏感,一次写入需要fsync持久化到WAL日志,如果系统盘和应用日志打在同一个繁忙磁盘上,写延迟飙升会直接反映为API请求延迟甚至超时。

1.3 证书系统的整体规划思路

Kubernetes控制面组件之间全是TLS通信,证书系统设计的核心原则是“最小权限、最小信任”。根CA只有一个,由它签发不同类型的子证书,每个证书只服务于特定身份:

  • 节点身份证书:每个节点一个,用于kubelet与apiserver双向认证
  • 组件客户端证书:kube-apiserver访问etcd时使用的etcd client证书
  • 服务端证书:kube-apiserver对外提供HTTPS服务的证书,etcd对外提供服务的证书
  • 管理用户证书:管理员通过kubectl访问集群时的客户端证书

证书签发不是随手openssl req -x509一把梭,生产环境需要统一用CA中心集中签发,原因在于信任链管理。所有组件校验对方身份时,都回溯到同一个根CA:根CA签发中间CA,中间CA签发具体证书。这样轮换某个组件证书时,只需要重新签发那一张,不影响整个信任链。

实际操作中,我习惯把根CA私钥放在独立的安全目录,甚至离线保存,日常签发使用它的签发型配置文件。这样即使某个节点的证书私钥泄露,也可以用CA吊销并重新签发,根私钥仍然安全。

2. 证书生成实操:CFSSL签发全套PKI证书

2.1 证书体系角色划分

CFSSL是CloudFlare开源的PKI工具集,相比直接用openssl命令,它的优势是配置文件驱动,适合批量生成一致的证书。

先规划三台etcd节点的假设信息(实际部署请替换为自己的内网规划):

节点角色主机名内网IP
etcd-1k8s-etcd-01192.168.1.11
etcd-2k8s-etcd-02192.168.1.12
etcd-3k8s-etcd-03192.168.1.13

这一阶段要生成的证书分三类:

  • etcd server证书:etcd节点对外提供客户端访问时使用的服务端证书,需要包含三个节点的IP和域名作为SAN
  • etcd peer证书:etcd节点之间raft通信使用的双向认证证书,同样需要包含三个节点的IP和域名
  • etcd client证书:供kube-apiserver访问etcd使用的客户端证书

注意:etcd的server证书和peer证书不能共用同一个CSR随意签。虽然它们的信任链相同,但用途不同,peer证书要求所有节点都能验证对端身份,SAN必须覆盖全部集群成员;server证书只要能被客户端通过其访问地址验证。生产我建议分开签,后续独立轮换互不影响。

2.2 使用CFSSL生成CA与etcd证书

CFSSL的安装方式很直接,下载对应平台的二进制放到/usr/local/bin即可。这里在专门生成证书的机器上操作(可以是独立管理机,也可以是其中一台etcd节点)。

先准备CA配置文件。CA配置决定证书的签名策略和有效期:

{ "signing": { "default": { "expiry": "87600h" }, "profiles": { "server": { "expiry": "87600h", "usages": ["signing", "key encipherment", "server auth"] }, "peer": { "expiry": "87600h", "usages": ["signing", "key encipherment", "server auth", "client auth"] }, "client": { "expiry": "87600h", "usages": ["signing", "key encipherment", "client auth"] } } } }

这里的expiry设置的是10年,生产可以按安全策略调整。usages字段决定了证书的扩展用途,etcd peer证书需要同时包含server auth和client auth,因为peer通信是双向TLS认证。

接着生成CA根证书:

cat > ca-csr.json << 'EOF' { "CN": "kubernetes-ca", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "ST": "BJ", "L": "BJ", "O": "kubernetes", "OU": "kubernetes-cluster" } ] } EOF cfssl gencert -initca ca-csr.json | cfssljson -bare ca

执行完会得到ca.pem、ca-key.pem、ca.csr三个文件。ca-key.pem就是根CA私钥,务必妥善保管。O字段是组织名,后面组件校验时可能按组织区分权限角色,填一个统一标识即可。

生成etcd server证书:

cat > etcd-server-csr.json << 'EOF' { "CN": "etcd-server", "hosts": [ "192.168.1.11", "192.168.1.12", "192.168.1.13", "127.0.0.1", "etcd-01", "etcd-02", "etcd-03", "kubernetes.default.svc.cluster.local" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "ST": "BJ", "L": "BJ", "O": "kubernetes", "OU": "etcd-server" } ] } EOF cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server etcd-server-csr.json | cfssljson -bare etcd-server

关键点是hosts字段。这里声明的每个IP和域名都会被写进证书的SAN(Subject Alternative Name)扩展。etcd启动时如果用https://192.168.1.11:2379对外服务,客户端连接校验服务端证书时,会检查访问地址是否匹配SAN,不匹配直接握手失败。

生成etcd peer证书,注意CN要用node名字,profile换成peer:

cat > etcd-peer-csr.json << 'EOF' { "CN": "etcd-peer", "hosts": [ "192.168.1.11", "192.168.1.12", "192.168.1.13", "127.0.0.1", "etcd-01", "etcd-02", "etcd-03" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "ST": "BJ", "L": "BJ", "O": "kubernetes", "OU": "etcd-peer" } ] } EOF cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=peer etcd-peer-csr.json | cfssljson -bare etcd-peer

生成etcd client证书:

cat > etcd-client-csr.json << 'EOF' { "CN": "etcd-client", "hosts": [], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "ST": "BJ", "L": "BJ", "O": "kubernetes", "OU": "etcd-client" } ] } EOF cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client etcd-client-csr.json | cfssljson -bare etcd-client

client证书的hosts留空是正确的,因为它是客户端身份凭证,不依赖访问地址,只需要CN标识身份。

2.3 核对证书清单与分发

签发完成后,/etc/etcd/pki目录下应该有这些文件:

文件用途分发范围
ca.pemCA根证书所有etcd节点
etcd-server.pemetcd对外服务证书对应节点
etcd-server-key.pem服务证书私钥对应节点
etcd-peer.pemraft通信证书所有etcd节点
etcd-peer-key.pempeer私钥对应节点
etcd-client.pem客户端访问证书kube-apiserver所在节点
etcd-client-key.pem客户端私钥kube-apiserver所在节点

分发时用scp或配置管理工具推到节点上,设置权限600。私钥文件如果权限过宽,etcd启动时会直接拒绝加载。

验证证书内容有一个实用命令,线上排查必备:

openssl x509 -in etcd-server.pem -noout -text | grep -A 3 "Subject Alternative Name"

这会列出证书实际包含的SAN,当出现“证书校验失败”时,第一件事就是对比证书SAN和访问地址。

3. 实战部署:三节点etcd集群二进制安装

3.1 安装包准备与目录规划

到etcd官方GitHub Release页面下载对应架构的二进制压缩包,比如etcd-v3.5.x-linux-amd64.tar.gz。解压后里面包含etcd和etcdctl两个程序,前者是服务进程,后者是命令行客户端。

三台节点都按同一套目录规划执行:

mkdir -p /opt/etcd/bin mkdir -p /etc/etcd/pki mkdir -p /var/lib/etcd

二进制放到/opt/etcd/bin/etcd,证书放到/etc/etcd/pki/,数据目录在/var/lib/etcd。目录规划的考虑是数据目录单独分区,便于后续做磁盘容量管理,证书目录独立便于权限控制和备份。

3.2 节点配置与systemd托管

etcd的配置方式有两种:命令行参数和YAML配置文件。命令行参数写起来冗长,容易出错,我推荐用YAML配置文件,清晰且便于版本管理。

以etcd-1节点为例,配置文件/etc/etcd/etcd.yml:

name: etcd-01>[Unit] Description=etcd service After=network.target After=network-online.target Wants=network-online.target [Service] Type=notify ExecStart=/opt/etcd/bin/etcd --config-file=/etc/etcd/etcd.yml Restart=always RestartSec=5 LimitNOFILE=65536 User=etcd Group=etcd [Install] WantedBy=multi-user.target

Type=notify是etcd推荐的启动类型,etcd启动完成后会主动通知systemd,避免误判启动失败。LimitNOFILE调高文件句柄数上限,线上etcd连接数高时,默认1024远远不够。

这里建议创建一个专用系统用户:

useradd --system --home /var/lib/etcd --shell /bin/false etcd chown -R etcd:etcd /var/lib/etcd

让etcd以非root身份运行,数据目录归属etcd用户,这是基本的安全加固。如果用root启动,后面想加安全策略会很被动。

3.3 集群启动、验证与数据读写测试

三台节点全部配置就绪后,启动顺序建议从第一台开始,等它成功加入集群并成为leader后,再启动其余节点。虽然etcd支持同时启动,但顺序启动更容易定位问题。

systemctl daemon-reload systemctl enable --now etcd systemctl status etcd -l

在任意一台节点上查看集群成员:

etcdctl --endpoints=https://192.168.1.11:2379,https://192.168.1.12:2379,https://192.168.1.13:2379 \ --cacert=/etc/etcd/pki/ca.pem \ --cert=/etc/etcd/pki/etcd-client.pem \ --key=/etc/etcd/pki/etcd-client-key.pem \ member list

注意etcdctl连接https端点时必须携带CA证书和客户端证书,否则会报证书校验失败。输出结果应该列出三个成员,状态均为started。

检查整个集群的健康状态:

etcdctl --endpoints=https://192.168.1.11:2379,https://192.168.1.12:2379,https://192.168.1.13:2379 \ --cacert=/etc/etcd/pki/ca.pem \ --cert=/etc/etcd/pki/etcd-client.pem \ --key=/etc/etcd/pki/etcd-client-key.pem \ endpoint health --cluster

三条endpoint都返回healthy才算通过。如果有一个节点unhealthy,不要急着继续搭上层组件,先把etcd集群恢复到健康状态再往下走,否则后面kube-apiserver起来会间歇性报错。

做一个基本的读写验证:

etcdctl --endpoints=https://192.168.1.11:2379 \ --cacert=/etc/etcd/pki/ca.pem \ --cert=/etc/etcd/pki/etcd-client.pem \ --key=/etc/etcd/pki/etcd-client-key.pem \ put /test/hello "world" etcdctl --endpoints=https://192.168.1.11:2379 \ --cacert=/etc/etcd/pki/ca.pem \ --cert=/etc/etcd/pki/etcd-client.pem \ --key=/etc/etcd/pki/etcd-client-key.pem \ get /test/hello

能正常写入和读取,说明客户端认证链路、证书信任链、集群数据同步都正常。

4. 排查实录:证书与etcd常见故障处理

4.1 证书类故障

证书问题在etcd部署阶段出现频率最高,以下是我实测中最常见的几种:

“x509: cannot validate certificate for 192.168.1.12 because it doesn't contain any IP SANs”

这个报错原因很直接:证书的SAN里没有包含访问时使用的IP。比如你访问etcd-02时用了https://192.168.1.12:2379,但那份证书签发时hosts字段只写了etcd-02主机名,没有写IP,TLS校验就失败。生产环境几乎都是IP直连,因此签发证书时一定要把集群所有成员IP都写进hosts。

“remote error: tls: bad certificate”

通常是客户端使用了自己不信任的CA签发的证书,或者客户端证书类型不对。检查一下客户端访问是否带了正确的--cacert,以及证书的usages是否包含client auth。

证书过期

etcd运行很久后证书到期,表现为客户端间歇性报错certificate has expired or is not yet valid。排查命令:

openssl x509 -in /etc/etcd/pki/etcd-server.pem -noout -dates

如果发现即将过期,需要重新签发给到节点并重启etcd。我在实际运维中会写一个证书到期检查脚本,每周定时巡检,输出90天内即将过期的证书列表,避免故障发生在半夜。

4.2 etcd集群类故障

“etcdserver: request timed out”与leader选举异常

这个报错常见于磁盘性能差或网络抖动。etcd对写入延时的要求很高,leader节点必须把每一次写请求同步到多数节点并持久化后才能返回,如果某个节点磁盘fsync慢,整个集群写入都会被拖垮。

检查思路:先看各个节点的etcd日志,再观察etcdctl endpoint status返回的Raft Term和Leader是否一致。磁盘性能可以用iostat确认%util是否长期接近100%,网络可以用ping看节点间延迟和丢包。

成员加入失败:data-dir有残留

如果重新初始化集群,但data-dir里保留了上一次的成员数据,节点可能以旧身份加入新集群,导致member ID冲突。处理方法是清空data-dir后重新启动。实际操作中我发现很多人忘了这个坑,明明是全新部署,却不小心把之前测试留下的数据目录当生产数据保留了下来。

日志过量增长

etcd默认把WAL和快照写在data-dir下,长时间运行后磁盘占用会持续增长,但不会无限制增长——etcd会定期压缩历史版本并触发快照。如果数据Key数量巨大,压缩不及时,磁盘可能会被打满。这时考虑使用etcd --auto-compaction-retention=1开启自动压缩,同时关注data-dir的磁盘水位。

4.3 运维侧建议:快照、日志与健康检查

etcd的数据安全直接影响整个Kubernetes集群,备份策略必须在部署阶段就考虑好。最简单的做法是用etcdctl做定时快照:

etcdctl --endpoints=https://192.168.1.11:2379 \ --cacert=/etc/etcd/pki/ca.pem \ --cert=/etc/etcd/pki/etcd-client.pem \ --key=/etc/etcd/pki/etcd-client-key.pem \ snapshot save /backup/etcd-snapshot-$(date +%Y%m%d).db

配合crontab每天执行,保留最近7天。快照恢复时,用etcdctl snapshot restore恢复到指定目录,再以initial-cluster-state=existing启动。

注意:快照备份最好在集群健康状态下执行。如果集群已经处于leader丢失状态,快照可能不完整;恢复时也要先停掉所有etcd节点,避免旧数据回写覆盖恢复结果。

日志方面,etcd默认打印到标准输出,由systemd的journal收集。长时间运行后journal可能占用较大空间,建议配置/etc/systemd/journald.conf里的SystemMaxUse限制日志上限,或者给etcd单元增加StandardOutput=append:/var/log/etcd.log把日志重定向到文件,便于用logrotate统一处理。

另外一个实践心得:把etcd的健康检查纳入监控,命令就用上面写过的endpoint health --cluster。不要只监控进程是否存在,进程活着不代表集群healthy。我经历过一次etcd进程正常、但集群因网络分区失去leader半小时的情况,如果只看进程状态完全发现不了。

最后说点操作体会

三套etcd节点第一次搭的时候,我犯过一个印象很深的错:三台机器配置都写好之后,我图省事同时启动,结果状态一直反复横跳,日志刷出一堆“leader changed”,排查了半天发现是节点间时钟不同步加证书SAN漏了一个IP。从那之后我就坚持顺序启动,每启动一台就先看成员列表、看日志、确认健康,再启动下一台。这个习惯看着慢,但能帮你把每一步的问题都限制在小范围内,不至于最后三台一起“炸”了才回头找原因。

证书签名和etcd初始化这两关走通,后面的kube-apiserver、kube-controller-manager、kube-scheduler部署就顺理成章了。只是提醒一句:kube-apiserver访问etcd用的那份client证书,CN和O字段后面可能会被用于RBAC权限映射,签发时命名规范一些,省得将来为证书身份问题返工。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询