Kubernetes ETCD 集群按资源拆分与 TLS 配置
本文档详细阐述了如何在 Kubernetes 中实现 ETCD 集群按资源拆分,特别是将 events
等特定资源存储到独立的 ETCD 集群,以及在多 ETCD 集群环境下 kube-apiserver
的 TLS 证书配置方案。
1. ETCD 集群按资源拆分
Kubernetes 允许通过 kube-apiserver
的 --etcd-servers-overrides
参数将特定资源的数据存储到独立的 ETCD 集群中,以提高性能和可扩展性,尤其对于写入频繁的 events
资源。
1.1 配置方法
--etcd-servers-overrides
参数的格式为:
1
--etcd-servers-overrides= /<resource-path>#<etcd-server-list>
例如,将 /registry/events
路径下的数据重定向到独立的 events ETCD 集群:
1
--etcd-servers-overrides= /registry/events#https://events-etcd1:2379,https://events-etcd2:2379,https://events-etcd3:2379
注意 :
/registry/events
是 Kubernetes 内部用于存储 events 资源的路径。https://events-etcdX:2379
是独立的 events ETCD 集群的地址列表。1.2 部署架构
典型的部署架构包括:
主 ETCD 集群 :存储除 events
之外的所有 Kubernetes 资源数据(如 Pods, Deployments, Services 等)。Events ETCD 集群 :专门存储 events
资源数据。kube-apiserver
:配置连接主 ETCD 集群和 Events ETCD 集群。2. kube-apiserver
的 TLS 证书配置
当每个 ETCD 集群都配置独立的 TLS 证书时,kube-apiserver
需要正确配置 TLS 证书和密钥才能与这些 ETCD 集群进行安全通信。
2.1 证书架构设计
有两种主要的证书架构设计:
2.1.1 统一 CA 签发所有 ETCD 证书(推荐)
优点 :管理简单,kube-apiserver
只需要信任一个 CA 证书即可与所有 ETCD 集群通信。实现 :使用一个根 CA 签发所有主 ETCD 和 Events ETCD 的服务器证书,以及 kube-apiserver
连接 ETCD 的客户端证书。2.1.2 独立 CA 签发不同 ETCD 集群证书
优点 :安全性更高,不同 ETCD 集群的信任域独立。缺点 :管理复杂,kube-apiserver
需要信任多个 CA 证书。实现 :合并 CA 证书 :将所有 ETCD 集群的 CA 证书合并到一个文件中,作为 kube-apiserver
的 --etcd-cafile
。使用代理 :在 kube-apiserver
和 ETCD 集群之间部署一个代理(如 HAProxy 或 Nginx),由代理处理不同 ETCD 集群的 TLS 证书,kube-apiserver
只需信任代理的证书。2.2 kube-apiserver
TLS 配置参数
kube-apiserver
连接 ETCD 的主要 TLS 配置参数包括:
--etcd-certfile
: 指定 kube-apiserver
用于向 ETCD 进行客户端身份验证的证书文件的路径。--etcd-keyfile
: 指定 kube-apiserver
用于向 ETCD 进行客户端身份验证的私钥文件的路径。--etcd-cafile
: 指定用于验证 ETCD 服务器证书的 CA 证书文件的路径。如果 ETCD 集群使用了由自定义 CA 签发的证书,kube-apiserver
需要这个 CA 证书来信任 ETCD 服务器。2.3 示例配置(统一 CA 推荐)
假设所有 ETCD 集群(包括主 ETCD 和 Events ETCD)的证书都由同一个 CA 签发,并且 kube-apiserver
使用一个客户端证书连接所有 ETCD。
kube-apiserver
启动参数示例 :
1
2
3
4
5
--etcd-servers= https://etcd1:2379,https://etcd2:2379,https://etcd3:2379 \\
--etcd-servers-overrides= /registry/events#https://events-etcd1:2379,https://events-etcd2:2379 \\
--etcd-certfile= /etc/kubernetes/pki/apiserver-etcd-client.crt \\
--etcd-keyfile= /etc/kubernetes/pki/apiserver-etcd-client.key \\
--etcd-cafile= /etc/kubernetes/pki/etcd-ca.crt
说明 :
etcd-servers
:指向主 ETCD 集群的地址。etcd-servers-overrides
:将 /registry/events
重定向到独立的 Events ETCD 集群的地址。apiserver-etcd-client.crt
和 apiserver-etcd-client.key
:kube-apiserver
连接所有 ETCD 集群的客户端证书和私钥。etcd-ca.crt
:包含签发所有 ETCD 服务器证书的 CA 证书。2.4 证书生成脚本示例
以下是一个简化的证书生成脚本示例,用于生成统一 CA 签发的主 ETCD、Events ETCD 和 kube-apiserver
客户端证书:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/bin/bash
# 1. 生成根 CA 证书和私钥
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -subj "/CN=K8s-ETCD-CA" -days 3650 -out ca.crt
# 2. 生成主 ETCD 服务器证书和私钥
openssl genrsa -out etcd-server.key 2048
openssl req -new -key etcd-server.key -subj "/CN=etcd-server" -out etcd-server.csr
openssl x509 -req -in etcd-server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out etcd-server.crt -days 3650
# 3. 生成 Events ETCD 服务器证书和私钥
openssl genrsa -out events-etcd-server.key 2048
openssl req -new -key events-etcd-server.key -subj "/CN=events-etcd-server" -out events-etcd-server.csr
openssl x509 -req -in events-etcd-server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out events-etcd-server.crt -days 3650
# 4. 生成 kube-apiserver 客户端证书和私钥
openssl genrsa -out apiserver-etcd-client.key 2048
openssl req -new -key apiserver-etcd-client.key -subj "/CN=kube-apiserver" -out apiserver-etcd-client.csr
openssl x509 -req -in apiserver-etcd-client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out apiserver-etcd-client.crt -days 3650
# 将证书和私钥分发到相应节点和目录
# 例如:
# cp ca.crt /etc/kubernetes/pki/
# cp apiserver-etcd-client.crt /etc/kubernetes/pki/
# cp apiserver-etcd-client.key /etc/kubernetes/pki/
# cp etcd-server.crt etcd-server.key 到主 ETCD 节点
# cp events-etcd-server.crt events-etcd-server.key 到 Events ETCD 节点
2.5 独立 CA 的解决方案
如果不同的 ETCD 集群使用了不同的 CA 签发证书,有以下几种解决方案:
2.5.1 合并 CA 证书文件
将所有 ETCD 集群的 CA 证书合并到一个文件中:
1
2
3
4
5
# 合并多个 CA 证书
cat main-etcd-ca.crt events-etcd-ca.crt > combined-etcd-ca.crt
# 在 kube-apiserver 中使用合并后的 CA 文件
--etcd-cafile= /etc/kubernetes/pki/combined-etcd-ca.crt
2.5.2 使用代理方案
在 kube-apiserver
和 ETCD 集群之间部署 HAProxy 或 Nginx 代理:
HAProxy 配置示例 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
global
daemon
defaults
mode tcp
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
# 主 ETCD 集群代理
frontend main_etcd_frontend
bind *:12379
default_backend main_etcd_backend
backend main_etcd_backend
balance roundrobin
server etcd1 etcd1:2379 check ssl verify required ca-file /etc/ssl/main-etcd-ca.crt
server etcd2 etcd2:2379 check ssl verify required ca-file /etc/ssl/main-etcd-ca.crt
server etcd3 etcd3:2379 check ssl verify required ca-file /etc/ssl/main-etcd-ca.crt
# Events ETCD 集群代理
frontend events_etcd_frontend
bind *:22379
default_backend events_etcd_backend
backend events_etcd_backend
balance roundrobin
server events-etcd1 events-etcd1:2379 check ssl verify required ca-file /etc/ssl/events-etcd-ca.crt
server events-etcd2 events-etcd2:2379 check ssl verify required ca-file /etc/ssl/events-etcd-ca.crt
对应的 kube-apiserver
配置 :
1
2
3
4
5
--etcd-servers= https://haproxy:12379 \\
--etcd-servers-overrides= /registry/events#https://haproxy:22379 \\
--etcd-certfile= /etc/kubernetes/pki/apiserver-etcd-client.crt \\
--etcd-keyfile= /etc/kubernetes/pki/apiserver-etcd-client.key \\
--etcd-cafile= /etc/kubernetes/pki/haproxy-ca.crt
2.6 最佳实践与注意事项
统一根 CA :强烈建议使用一个统一的根 CA 来签发所有 ETCD 集群和 kube-apiserver
的证书,简化证书管理。证书管理 :定期检查证书有效期,并建立证书轮换机制。权限管理 :确保证书和私钥文件的权限设置正确,防止未授权访问。监控与告警 :监控 ETCD 集群的性能和健康状况,特别是 Events ETCD,因为它可能面临高写入负载。备份与恢复 :为所有 ETCD 集群配置定期备份,并测试恢复流程。网络连通性 :确保 kube-apiserver
与所有配置的 ETCD 集群之间的网络连通性。2.7 证书管理脚本
创建一个证书管理脚本来自动化证书的生成、分发和轮换:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/bin/bash
# cert-manager.sh - ETCD 证书管理脚本
set -e
# 配置变量
CA_KEY = "ca.key"
CA_CERT = "ca.crt"
CERT_VALIDITY_DAYS = 365
KEY_SIZE = 2048
# 生成 CA 证书
generate_ca() {
echo "生成 CA 证书..."
openssl genrsa -out $CA_KEY $KEY_SIZE
openssl req -x509 -new -nodes -key $CA_KEY \
-subj "/CN=K8s-ETCD-CA/O=Kubernetes" \
-days $(( CERT_VALIDITY_DAYS * 10 )) \
-out $CA_CERT
echo "CA 证书生成完成"
}
# 生成服务器证书
generate_server_cert() {
local name = $1
local cn = $2
local san = $3
echo "生成 $name 服务器证书..."
# 生成私钥
openssl genrsa -out " ${ name } .key" $KEY_SIZE
# 生成证书签名请求
openssl req -new -key " ${ name } .key" \
-subj "/CN= ${ cn } /O=Kubernetes" \
-out " ${ name } .csr"
# 创建扩展配置
cat > " ${ name } .ext" <<EOF
authorityKeyIdentifier=keyid,issuer:always
basicConstraints=CA:FALSE
keyUsage=keyEncipherment,dataEncipherment
extendedKeyUsage=serverAuth,clientAuth
subjectAltName=${san}
EOF
# 签发证书
openssl x509 -req -in " ${ name } .csr" \
-CA $CA_CERT -CAkey $CA_KEY \
-CAcreateserial \
-out " ${ name } .crt" \
-days $CERT_VALIDITY_DAYS \
-extensions v3_req \
-extfile " ${ name } .ext"
# 清理临时文件
rm " ${ name } .csr" " ${ name } .ext"
echo " $name 服务器证书生成完成"
}
# 生成客户端证书
generate_client_cert() {
local name = $1
local cn = $2
echo "生成 $name 客户端证书..."
# 生成私钥
openssl genrsa -out " ${ name } .key" $KEY_SIZE
# 生成证书签名请求
openssl req -new -key " ${ name } .key" \
-subj "/CN= ${ cn } /O=system:masters" \
-out " ${ name } .csr"
# 签发证书
openssl x509 -req -in " ${ name } .csr" \
-CA $CA_CERT -CAkey $CA_KEY \
-CAcreateserial \
-out " ${ name } .crt" \
-days $CERT_VALIDITY_DAYS
# 清理临时文件
rm " ${ name } .csr"
echo " $name 客户端证书生成完成"
}
# 检查证书有效期
check_cert_expiry() {
local cert_file = $1
local warning_days = ${ 2 :- 30 }
if [[ -f $cert_file ]] ; then
local expiry_date = $( openssl x509 -in $cert_file -noout -enddate | cut -d= -f2)
local expiry_epoch = $( date -d " $expiry_date " +%s)
local current_epoch = $( date +%s)
local days_left = $(( ( expiry_epoch - current_epoch) / 86400 ))
if [[ $days_left -lt $warning_days ]] ; then
echo "警告: 证书 $cert_file 将在 $days_left 天后过期"
return 1
else
echo "证书 $cert_file 还有 $days_left 天有效期"
return 0
fi
else
echo "错误: 证书文件 $cert_file 不存在"
return 1
fi
}
# 主函数
main() {
case " $1 " in
"generate-all" )
generate_ca
generate_server_cert "etcd-server" "etcd-server" "DNS:etcd1,DNS:etcd2,DNS:etcd3,DNS:localhost,IP:127.0.0.1"
generate_server_cert "events-etcd-server" "events-etcd-server" "DNS:events-etcd1,DNS:events-etcd2,DNS:events-etcd3,DNS:localhost,IP:127.0.0.1"
generate_client_cert "apiserver-etcd-client" "kube-apiserver"
;;
"check-expiry" )
check_cert_expiry "ca.crt" 90
check_cert_expiry "etcd-server.crt"
check_cert_expiry "events-etcd-server.crt"
check_cert_expiry "apiserver-etcd-client.crt"
;;
*)
echo "用法: $0 {generate-all|check-expiry}"
echo " generate-all - 生成所有证书"
echo " check-expiry - 检查证书有效期"
exit 1
;;
esac
}
main " $@ "
2.8 故障排查
2.8.1 常见问题
TLS 握手失败 :
检查 kube-apiserver
和 ETCD 的日志 确认证书、私钥和 CA 文件路径是否正确 验证证书是否过期或被吊销 检查证书的 SAN(Subject Alternative Name)是否包含正确的主机名或 IP 网络连接问题 :
使用 telnet
或 nc
测试端口连通性 检查防火墙规则 验证 DNS 解析 资源路径错误 :
确认 --etcd-servers-overrides
中的资源路径是否正确 检查 Kubernetes 版本兼容性 2.8.2 调试命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 检查证书详细信息
openssl x509 -in certificate.crt -text -noout
# 验证证书链
openssl verify -CAfile ca.crt certificate.crt
# 测试 TLS 连接
openssl s_client -connect etcd-server:2379 -cert client.crt -key client.key -CAfile ca.crt
# 检查 ETCD 集群状态
ETCDCTL_API = 3 etcdctl --endpoints= https://etcd1:2379 \
--cert= client.crt --key= client.key --cacert= ca.crt \
endpoint health
# 查看 kube-apiserver 日志
kubectl logs -n kube-system kube-apiserver-master1
3. 监控与运维
3.1 监控指标
重要的监控指标包括:
ETCD 性能指标 :
延迟(etcd_disk_wal_fsync_duration_seconds) 吞吐量(etcd_server_proposals_applied_total) 存储大小(etcd_mvcc_db_total_size_in_bytes) 证书监控 :
3.2 告警规则
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
groups :
- name : etcd-alerts
rules :
- alert : ETCDCertificateExpiringSoon
expr : (etcd_server_certificate_expiration_timestamp - time()) / 86400 < 30
for : 1h
labels :
severity : warning
annotations :
summary : "ETCD certificate expiring soon"
description : "ETCD certificate will expire in less than 30 days"
- alert : ETCDHighLatency
expr : histogram_quantile(0.99, etcd_disk_wal_fsync_duration_seconds_bucket) > 0.5
for : 5m
labels :
severity : critical
annotations :
summary : "ETCD high disk latency"
description : "ETCD 99th percentile disk latency is {{ $value }}s"
4. 扩展应用
除了 events
,--etcd-servers-overrides
理论上可以用于将其他高写入或特定类型的资源存储到独立的 ETCD 集群,例如:
自定义资源(CRD) :将特定的 CRD 数据存储到专用集群ConfigMaps 和 Secrets :将配置数据分离存储审计日志 :将审计数据存储到独立集群示例配置 :
1
2
3
4
# 将多种资源分别存储到不同集群
--etcd-servers-overrides= /registry/events#https://events-etcd:2379 \\
--etcd-servers-overrides= /registry/configmaps#https://config-etcd:2379 \\
--etcd-servers-overrides= /registry/secrets#https://secrets-etcd:2379
注意 :这种高级配置需要深入理解 Kubernetes 内部机制,建议在测试环境中充分验证后再应用到生产环境。
5. 总结
通过合理配置 ETCD 集群按资源拆分和 TLS 证书,可以显著提升 Kubernetes 集群在处理大量 events
或其他特定资源时的性能和稳定性。关键要点包括:
统一 CA 管理 :推荐使用统一的根 CA 简化证书管理自动化运维 :建立证书生成、分发和轮换的自动化流程监控告警 :实施全面的监控和告警机制故障预案 :制定详细的故障排查和恢复流程测试验证 :在生产环境部署前进行充分的测试验证通过这些最佳实践,可以确保 Kubernetes 集群的高可用性和安全性。