Start

  • 需要提前把前提步骤完成,可以参考集群创建前置
  • 把每个节点进行kubelet,kubeadm,containerd以及一些环境配置好即可,先不需要进行初始化
  • 可以通过克隆加快速度,3master/3work/3etcd模式,资源消耗可能有点多。

创建高可用的ETCD外部集群

节点准备

  • 按照之前,可以把所有环境都准备好备用。
  • 然后保持系统时钟同步

使用chrony进行同步

# 每台ETCD节点安装chrony
apt update && apt install chrony

# 修改 /etc/chrony/chrony.conf,添加或者修改NTP服务器配置,自己可以添加主机或者用公共NTP
server 192.168.154.20 iburst

# 重启
systemctl restart chronyd

# 验证同步
chronyc tracking
chronyc sources -v
root@etcd3:/etc/chrony# chronyc sources -v

.-- Source mode '^' = server, '=' = peer, '#' = local clock.
/ .- Source state '*' = current best, '+' = combined, '-' = not combined,
| / 'x' = may be in error, '~' = too variable, '?' = unusable.
|| .- xxxx [ yyyy ] +/- zzzz
|| Reachability register (octal) -. | xxxx = adjusted offset,
|| Log2(Polling interval) --. | | yyyy = measured offset,
|| \ | | zzzz = estimated error.
|| | | \
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^? 192.168.154.20 0 7 0 - +0ns[ +0ns] +/- 0ns

安装ETCD,整机跑

ps:个人建议可以在每个节点准备Go环境,虽然不需要严格和Kubernetes版本进行对应,但是还是需要注意版本兼容问题。

# golang
apt update && apt search golang
apt info golang
apt install golang
# 注意版本,这里是使用3.12.0,自己斟酌
# ps: https://mirrors.huaweicloud.com/etcd/v3.5.12/ wget 不到这里可以获取。
wget https://github.com/etcd-io/etcd/releases/download/v3.12.0/etcd-v3.12.0-linux-amd64.tar.gz
tar -xvf etcd-v3.12.0-linux-amd64.tar.gz
sudo mv etcd-v3.12.0-linux-amd64/etcd* /usr/local/bin/
创建etcd.conf.yml
# 一般在/etc/etcd/ 下面
mkdir -p /etc/etcd
touch /etc/etcd/etcd.conf.yaml

# 每一个etcd节点都需要进行配置

# etcd 配置文件示例
name: 'etcd1' # 当前节点的名称
data-dir: /var/lib/etcd # 数据存储路径
wal-dir: # 日志文件存储路径,通常省略
snapshot-count: 10000 # 多少事务后进行一次快照

# 与其他 etcd 节点的通信设置
initial-advertise-peer-urls: https://<etcd1-cluster-ip>:2380 # 当前节点的 peer URL
listen-peer-urls: https://<etcd1-cluster-ip>:2380 # 当前节点监听的 peer URL
listen-client-urls: https://<etcd1-cluster-ip>:2379,http://127.0.0.1:2379 # 当前节点监听的 client URL
advertise-client-urls: https://<etcd1-cluster-ip>:2379 # 广播给其他服务的 client URL

# 初始化集群信息
initial-cluster: 'etcd1=https://<etcd1-cluster-ip>:2380,etcd2=https://<etcd2-cluster-ip>:2380,etcd3=https://<etcd3-cluster-ip>:2380'
initial-cluster-state: 'new' # 'new' 用于初始引导,'existing' 用于已有集群加入新节点
initial-cluster-token: 'etcd-cluster-1' # 集群标识

# 安全性设置
client-transport-security:
cert-file: /etc/etcd/etcd-client.crt # 客户端证书路径
key-file: /etc/etcd/etcd-client.key # 客户端密钥路径
client-cert-auth: true # 启用客户端认证
trusted-ca-file: /etc/etcd/ca.crt # 可信 CA 证书路径

peer-transport-security:
cert-file: /etc/etcd/etcd-peer.crt # 节点间通信证书路径
key-file: /etc/etcd/etcd-peer.key # 节点间通信密钥路径
peer-client-cert-auth: true # 启用节点间认证
trusted-ca-file: /etc/etcd/ca.crt # 可信 CA 证书路径

创建etcd.service

[Unit]
Description=etcd key-value store # 描述该服务的用途
Documentation=https://github.com/etcd-io/etcd # 提供服务相关的文档链接
After=network.target # 确保网络服务启动后再启动 etcd

[Service]
Type=notify # 服务类型为 notify,表示 etcd 会在准备好后通知 systemd
ExecStart=/usr/local/bin/etcd \ # 指定 etcd 二进制文件的路径及命令行参数
--name {NODE_NAME} \ # 设置节点名称,需替换为实际节点名称,如 etcd1, etcd2
--data-dir=/var/lib/etcd \ # 数据存储目录,指定 etcd 数据存放的路径
--initial-advertise-peer-urls http://{NODE_IP}:2380 \ # 通告给集群其他节点的 URL,替换 {NODE_IP} 为实际节点 IP
--listen-peer-urls http://{NODE_IP}:2380 \ # 当前节点监听其他节点连接的 URL
--listen-client-urls http://{NODE_IP}:2379,http://127.0.0.1:2379 \ # 客户端访问的 URL,包括本地回环地址
--advertise-client-urls http://{NODE_IP}:2379 \ # 通告给客户端的访问 URL
--initial-cluster-token etcd-cluster-1 \ # 集群标识符,用于区分不同的 etcd 集群
--initial-cluster etcd1=http://192.168.154.16:2380,etcd2=http://192.168.154.17:2380,etcd3=http://192.168.154.18:2380 \ # 定义集群中所有节点及其 IP 地址
--initial-cluster-state new # 集群的初始状态,"new" 表示新建集群,已有集群用 "existing"
Restart=always # 服务退出时自动重启
RestartSec=5 # 重启前等待 5 秒
LimitNOFILE=40000 # 设置服务进程可打开文件的最大数量,通常设为较高值以避免资源限制

[Install]
WantedBy=multi-user.target # 在多用户模式下启动服务

启动etcd.service

systemctl daemon-reload
systemctl restart etcd
systemctl enable etcd
systemctl status etcd

签发证书

# 目录可以任意
mkdir -p /etc/etcd/pki/pki-json
cd /etc/etcd/pki
touch ca-config.json
touch ca-csr.json
touch etcd-csr.json
# ca-config.json

常见问题

  • 有时候进行一些服务变更之后呢,这个etcd的服务可能会进入一个长时间的阻塞,他会不断的进行节点查询和选举过程。这是一直既是正常又是不正常的状态,这个时候你可以:
# 停止etcd服务
systemctl stop etcd
# 清理数据目录
rm -rf /var/lib/etcd/*
# 再次确认配置文件没有问题之后,进行重启服务
systemctl daemon-reload
systemctl start etcd
systemctl status etcd
# 检查集群健康
etcdctl --endpoints=http://192.168.154.11:2379,http://192.168.154.13:2379,http://192.168.154.14:2379 endpoint health
  • 有时候你的集群节点数量在某种场合中很庞大,所以每次查询集群状态时候会显得吃力,所以你可以:

    # 本来你是需要这样子,<endpoints>里面需要填写所有节点的监听地址
    etcdctl --endpoints=<endpoints> member list
    # 你可以使用环境变量进行export
    nano ~/.bashrc
    # 在最后一行你需要添加,需要注意的是ETCDCTL_ENDPOINTS这个字段是必须的,etcd才能够意识到
    export ETCDCTL_ENDPOINTS="http://192.168.154.11:2379,http://192.168.154.13:2379,http://192.168.154.14:2379"
    # 进行配置生效。
    source ~/.bashrc
    # 然后再进行查询
    etcdctl member list
    # 还有另外一种方式就是,能够使用etcd专用的etcdctl.config.yaml
    endpoints:
    - http://192.168.154.11:2379
    - http://192.168.154.13:2379
    - http://192.168.154.14:2379
    # 然后可以进行环境变量的指定
    export ETCDCTL_CONFIG_FILE=~/.etcdctl.config.yml
  • 还有其他的集群情况查询命令(已经设置环境变量的情况,未设置的话请添加–endpoint)

# 查看集群成员信息
etcdctl member list
# 查看集群状况
etcdctl endpoint status --write-out=table
# 查看每个节点的健康情况
etcdctl endpoint health
# 查看当前集群的leader
etcdctl endpoint status --write-out=table | grep true
# 查看集群报警情况
etcdctl alarm list
# 查看当前的节点和角色的投票情况
etcdctl endpoint status --write-out=table | grep -E 'ID|IS LEADER'
# Raft leader
etcdctl endpoint status --write-out=json | jq .
  • etcdctl endpoint status --write-out=table字段解释
ENDPOINT ID VERSION DB SIZE IS LEADER IS LEARNER RAFT TERM RAFT INDEX RAFT APPLIED INDEX ERRORS
http://192.168.154.11:2379 1797a0c135947e8d 3.5.12 20 kB false false 2 20 20
http://192.168.154.13:2379 bbd3763358eec0a1 3.5.12 20 kB true false 2 20 20
http://192.168.154.14:2379 29834402d195db92 3.5.12 20 kB false false 2 20 20
  1. Raft Term:
    • 当前节点所在的 Raft 任期编号。
    • 常见排查:能够通过这个值判断这个ETCD是否稳定。
  2. Raft Index:
    • 表示当前节点上已经应用的日志索引号,Raft日志中最新提交位置,证明有东西写入ETCD中
    • 若是不同节点的这个值相差较大,证明可能存在网络延迟或者节点不健康的情况
  3. Raft Applied Index:
  • 表示当前节点已经应用的日志条目索引号,已经应用于状态机。
  • 如果此值明显小于上一个值证明,应用日志存在延迟问题,会产生一些性能瓶颈。
  1. Errors:
    • 节点存在故障异常

如何让K8S集群使用到这个外部ETCD集群

再补充一些正式的的一些注意事项

  • 需要注意的是,etcd集群的每一个节点都需要一个统一的ca进行签发,不然不统一后面kubernetes集群连接的时候可能会出现问题。其次在所有的pem进行移动到其他节点的操作,可能会存在pem过于暴露的提示,这个时候就需要进行一定的授权。

ps:证书公私钥的拷贝移动个人是觉得比较危险的行为,但是好像我暂时没有发现什么新的办法去解决。

  1. 这里的意思是说,先在一个节点创建一个ca-config和ca-csr的json然后签发统一的cd然后拷贝分发到其他的节点,其他节点再用这个分发来的ca进行etcd的证书创建。

  2. 所以你可以为了方便,在克隆之前先颁发ca.pem,ca-key.pem和定义ca-config.json和ca-csr.json等操作

  3. 理论上在kubernentes使用外部etcd的时候只需要进行用统一ca证书配置的pem即可。

image-20240902103651225

image-20240902103705259

image-20240902103821289

常见问题

证书配置

  • 证书最好由统一的ca根证书颁发,然后用统一的json进行签发。

配置文件格式问题

  • 最好注意service的排版格式以及配置config的排版格式,以及证书的路径位置

  • 这里需要非常注意到是,证书签发后,上面涉及到的环境变量问题需要改成https并且在查看集群情况的时候你需要带上你的证书参书

靠谱的证书签发过程,(个人过程,不要直接黏贴)

# 这里是有准备ansible工具,删除集群信息。
ansible etcd -m shell -a 'rm -rf /var/lib/etcd/member'
# 签发证书,参考下面,其次你需要把之前的环境变量清楚掉改成https,然后把目录上的证书也expost到环境中。然后就可以了。

提供环境变量的名字

export ETCDCTL_ENDPOINTS="https://192.168.154.11:2379,https://192.168.154.13:2379,https://192.168.154.14:2379"
export ETCDCTL_CACERT="/etc/etcd/pki/ca/pem"
export ETCDCTL_CERT="/etc/etcd/pki/etcd-client.pem"
export ETCDCTL_KEY="/etc/etcd/pki/etcd-client-key.pem"
export ETCDCTL_SKIP_TLS_VERIFY=true
# 清除环境变量
unset xxx
# 搜寻环境变量
env | grep ETCDCTL

证书生成

根据你的命令记录,以下是生成 etcd 集群所需证书的完整步骤。这个过程包括创建自签名的 CA 证书,以及为 etcd 服务器、客户端、和 peer 节点生成相关证书。

生产证书的步骤

首先,为 etcd 集群生成一个自签名的 CA 证书,用于签署其他的 etcd 组件证书。

  • 创建 CA 配置文件 ca-config.cnf(可以包含基本配置信息)。

  • 生成 CA 的私钥 ca-key.pem

    openssl genrsa -out ca-key.pem 4096
  • 使用 CA 私钥生成自签名的 CA 证书 ca.pem

    openssl req -x509 -new -nodes -key ca-key.pem -sha256 -days 3650 -out ca.pem -config ca-config.cnf

2. 为 etcd Peer 节点生成证书

Peer 证书用于 etcd 节点之间的通信。

  • 创建 Peer CSR 配置文件 etcd-peer-csr.cnf

  • 生成 Peer 节点的私钥 etcd-peer-key.pem

    openssl genrsa -out etcd-peer-key.pem 2048
  • 创建 Peer 节点的证书签名请求 etcd-peer.csr

    openssl req -new -key etcd-peer-key.pem -out etcd-peer.csr -config etcd-peer-csr.cnf
  • 使用 CA 证书和私钥签署 Peer 证书 etcd-peer.pem

    openssl x509 -req -in etcd-peer.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out etcd-peer.pem -days 365 -extensions req_ext -extfile etcd-peer-csr.cnf

3. 为 etcd 服务器生成证书

服务器证书用于 etcd 节点与客户端的通信。

  • 创建服务器 CSR 配置文件 etcd-server-csr.cnf

  • 生成服务器的私钥 etcd-server-key.pem

    openssl genrsa -out etcd-server-key.pem 2048
  • 创建服务器证书签名请求 etcd-server.csr

    openssl req -new -key etcd-server-key.pem -out etcd-server.csr -config etcd-server-csr.cnf
  • 使用 CA 证书和私钥签署服务器证书 etcd-server.pem

    openssl x509 -req -in etcd-server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out etcd-server.pem -days 365 -extensions req_ext -extfile etcd-server-csr.cnf

4. 为 etcd 客户端生成证书

客户端证书用于 etcdctl 等客户端工具与 etcd 集群的安全通信。

  • 创建客户端 CSR 配置文件 etcd-client-csr.cnf

  • 生成客户端的私钥 etcd-client-key.pem

    openssl genrsa -out etcd-client-key.pem 2048
  • 创建客户端证书签名请求 etcd-client.csr

    openssl req -new -key etcd-client-key.pem -out etcd-client.csr -config etcd-client-csr.cnf
  • 使用 CA 证书和私钥签署客户端证书 etcd-client.pem

    openssl x509 -req -in etcd-client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out etcd-client.pem -days 365 -extensions req_ext -extfile etcd-client-csr.cnf