ETCD 部署与维护 ¶
什么是 ETCD ¶
etcd 是一个分布式、可靠的键值存储系统,专门用于存储分布式系统中的关键数据。它通过 Raft 算法来实现分布式一致性和高可用性。
etcd 的主要特点 ¶
-
分布式一致性: etcd 使用 Raft 算法在集群中实现一致性。Raft 算法会选举一个领导者(Leader),由领导者负责处理所有的写请求并将数据同步到其他节点(Follower)。
-
高可用性: 当领导者节点(Leader)出现故障时,系统会自动选举新的领导者,继续处理数据的同步和分发。 etcd 的高可用性基于 Quorum 机制:只有当集群中超过半数的节点可用时(可用节点数量 > 总节点数量 / 2),集群才能继续提供服务。
使用场景 ¶
-
服务发现: 存储服务注册信息和状态信息,帮助服务实例之间进行通信。
-
配置管理: 存储分布式系统的配置数据,确保配置变更时所有相关服务能够立即感知并更新。
-
分布式锁: 提供基于租约和事务的分布式锁功能,确保在分布式环境中的独占访问控制。
-
元数据存储: 在容器编排系统(如 Kubernetes)中,存储集群的元数据,包括节点状态、Pod 信息、服务定义等。
etcd 的工作机制 ¶
- Raft 算法:确保数据在集群中的一致性,通过领导者节点处理写请求并同步数据到其他节点。
- Quorum 机制:确保集群在超过半数节点可用时能够正常提供服务。
- 自动故障恢复:当领导者节点故障时,自动选举新的领导者并恢复数据同步。
etcd 数据存储格式 ¶
etcd 中的存储路径格式可以表示为:
prefix + "/" + 资源类型 + "/" + namespace + "/" + 资源名
具体示例
-
Service Account: 存储路径:/registry/serviceaccounts/kube-system/coredns 解释:在 kube-system 命名空间下的名为 coredns 的 Service Account。
-
Pod: 存储路径:/registry/pods/default/nginx 解释:在 default 命名空间下的名为 nginx 的 Pod。
-
Service: 存储路径:/registry/services/specs/default/my-service 解释:在 default 命名空间下的名为 my-service 的 Service 定义信息。
-
存储路径:/registry/services/endpoints/default/my-service 解释:在 default 命名空间下的名为 my-service 的 Service 端点信息。
-
ConfigMap: 存储路径:/registry/configmaps/default/app-config 解释:在 default 命名空间下的名为 app-config 的 ConfigMap。
-
Secret: 存储路径:/registry/secrets/default/db-secret 解释:在 default 命名空间下的名为 db-secret 的 Secret。
ETCD 证书获取 ¶
1. cfssl 工具下载
cfssl 是使用 go 编写,由 CloudFlare 开源的一款 PKI/TLS 工具。主要程序有:
-
cfssl 是 CFSSL 的命令行工具
-
cfssljson 用来从 cfssl 程序获取 JSON 输出,并将证书,密钥,CSR 和 bundle 写入文件中
mkdir -p /data/k8s-worker/ca
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.4/cfssl_1.6.4_linux_amd64
chmod +x cfssl_1.6.4_linux_amd64
mv cfssl_1.6.4_linux_amd64 /usr/local/bin/cfssl
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.4/cfssljson_1.6.4_linux_amd64
chmod +x cfssljson_1.6.4_linux_amd64
mv cfssljson_1.6.4_linux_amd64 /usr/local/bin/cfssljson
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.4/cfssl-certinfo_1.6.4_linux_amd64
chmod +x cfssl-certinfo_1.6.4_linux_amd64
mv cfssl-certinfo_1.6.4_linux_amd64 /usr/local/bin/cfssl-certinfo
2. 创建 CA 证书
cat > ca/ca-csr.json <<"EOF"
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Beijing",
"L": "Beijing",
"O": "deployment",
"OU": "CN"
}
],
"ca": {
"expiry": "87600h"
}
}
EOF
cfssl gencert -initca ca-csr.json | cfssljson -bare ca/ca
cat > ca/ca-config.json <<"EOF"
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"kubernetes": {
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
],
"expiry": "87600h"
}
}
}
}
EOF
注意
-
server auth 表示client可以对使用该ca对server提供的证书进行验证
-
client auth 表示server可以使用该ca对client提供的证书进行验证
3. 创建 etcd 证书
mkdir etcd
cat > etcd/etcd-csr.json <<"EOF"
{
"CN": "etcd",
"hosts": [
"127.0.0.1",
"192.168.3.40",
"192.168.3.41",
"192.168.3.42",
"192.168.3.43",
"192.168.3.44",
"192.168.3.45",
"192.168.3.46",
"192.168.3.47",
"192.168.3.48",
"192.168.3.49",
"192.168.3.50",
"192.168.3.51",
"192.168.3.52",
"192.168.3.53",
"192.168.3.54",
"192.168.3.55",
"192.168.3.56",
"192.168.3.57",
"192.168.3.58",
"192.168.3.59",
"192.168.3.60",
"192.168.3.61",
"192.168.3.62",
"192.168.3.63",
"192.168.3.64",
"192.168.3.65",
"192.168.3.66",
"192.168.3.67",
"192.168.3.68",
"192.168.3.69",
"192.168.3.70",
"192.168.3.200"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [{
"C": "CN",
"ST": "Beijing",
"L": "Beijing",
"O": "deployment",
"OU": "CN"
}]
}
EOF
cfssl gencert -ca=ca/ca.pem -ca-key=ca/ca-key.pem -config=ca/ca-config.json -profile=kubernetes etcd/etcd-csr.json | cfssljson -bare etcd/etcd
ETCD 部署 ¶
下载 etcd 软件包 ¶
所有 etcd 节点上都需要。
cat > etcd-install.sh <<"EOF"
ETCD_VER=v3.5.13
# choose either URL
GOOGLE_URL=https://storage.googleapis.com/etcd
GITHUB_URL=https://github.com/etcd-io/etcd/releases/download
DOWNLOAD_URL=${GOOGLE_URL}
rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
rm -rf /tmp/etcd-download-test && mkdir -p /tmp/etcd-download-test
curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /tmp/etcd-download-test --strip-components=1
rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
mkdir /var/lib/etcd/
/tmp/etcd-download-test/etcd --version
/tmp/etcd-download-test/etcdctl version
/tmp/etcd-download-test/etcdutl version
# 将 etcd, etcdctl 和 etcdutl 复制到 /usr/local/bin
cp /tmp/etcd-download-test/etcd /usr/local/bin/
cp /tmp/etcd-download-test/etcdctl /usr/local/bin/
cp /tmp/etcd-download-test/etcdutl /usr/local/bin/
EOF
创建 etcd 配置文件 ¶
cat > etcd/k8s-master01-etcd.conf << "EOF"
#[Member]
ETCD_NAME="etcd-1"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.3.40:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.3.40:2379,http://192.168.3.40:2390"
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.3.40:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.3.40:2379"
ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.3.40:2380,etcd-2=https://192.168.3.41:2380,etcd-3=https://192.168.3.42:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
EOF
cat > etcd/k8s-master02-etcd.conf << "EOF"
#[Member]
ETCD_NAME="etcd-2"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.3.41:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.3.41:2379,http://192.168.3.41:2390"
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.3.41:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.3.41:2379"
ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.3.40:2380,etcd-2=https://192.168.3.41:2380,etcd-3=https://192.168.3.42:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
EOF
cat > etcd/k8s-master03-etcd.conf << "EOF"
#[Member]
ETCD_NAME="etcd-3"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.3.42:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.3.42:2379,http://192.168.3.42:2390"
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.3.42:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.3.42:2379"
ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.3.40:2380,etcd-2=https://192.168.3.41:2380,etcd-3=https://192.168.3.42:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
EOF
cat > etcd/etcd.service <<"EOF"
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
EnvironmentFile=-/etc/etcd/etcd.conf
WorkingDirectory=/var/lib/etcd/
ExecStart=/usr/local/bin/etcd \
--cert-file=/etc/etcd/ssl/etcd.pem \
--key-file=/etc/etcd/ssl/etcd-key.pem \
--trusted-ca-file=/etc/etcd/ssl/ca.pem \
--peer-cert-file=/etc/etcd/ssl/etcd.pem \
--peer-key-file=/etc/etcd/ssl/etcd-key.pem \
--peer-trusted-ca-file=/etc/etcd/ssl/ca.pem \
--peer-client-cert-auth \
--client-cert-auth
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
分发 etcd ssl 与 配置文件 ¶
#!/bin/bash
TARGET_HOSTS=("etcd-1" "etcd-2" "etcd-3" "k8s-master01" "k8s-master02" "k8s-master03")
ETCD_HOSTS=("etcd-1" "etcd-2" "etcd-3")
DIRECTORY=etcd/
CA_DIRECTORY=ca/
# 通过循环执行 scp 命令
for host in "${TARGET_HOSTS[@]}"; do
echo "正在复制文件到 $host..."
# 所有 etcd 节点创建工作目录
ssh -t $host 'mkdir -p /etc/etcd/ssl'
# 复制 ca 到 /etc/kubernetes/ssl 目录
scp ${CA_DIRECTORY}ca*.pem $host:/etc/etcd/ssl/
# 复制 ca 到 /etc/kubernetes/ssl 目录
scp ${DIRECTORY}etcd*.pem $host:/etc/etcd/ssl/
# 复制 systemd 服务文件到 /usr/lib/systemd/system/ 目录
scp ${DIRECTORY}etcd.service $host:/usr/lib/systemd/system/
# 复制对应主机的配置文件到 /etc/kubernetes/ 目录
case $host in
"etcd-1")
# 所有 etcd 节点创建工作目录
scp ${DIRECTORY}k8s-master01-etcd.conf $host:/etc/etcd/etcd.conf
;;
"etcd-2")
# 所有 etcd 节点创建工作目录
scp ${DIRECTORY}k8s-master02-etcd.conf $host:/etc/etcd/etcd.conf
;;
"etcd-3")
# 所有 etcd 节点创建工作目录
scp ${DIRECTORY}k8s-master03-etcd.conf $host:/etc/etcd/etcd.conf
;;
*)
echo "未识别的主机名: $host"
;;
esac
done
# 在 etcd 节点上执行 systemctl 命令
for host in "${ETCD_HOSTS[@]}"; do
echo "在 $host 上执行 systemctl 命令..."
ssh -t $host 'sudo systemctl daemon-reload'
ssh -t $host 'sudo systemctl restart etcd'
ssh -t $host 'sudo systemctl status etcd'
done
验证 etcd 集群状态 ¶
[root@k8s-master01 ~]# ETCDCTL_API=3 /usr/local/bin/etcdctl --write-out=table --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints=https://192.168.3.40:2379,https://192.168.3.41:2379,https://192.168.3.42:2379 endpoint status --write-out=table
+---------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+---------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| https://192.168.3.40:2379 | acaa7314b910a606 | 3.5.13 | 20 kB | false | false | 3 | 15 | 15 | |
| https://192.168.3.41:2379 | 2e349b91c4bea476 | 3.5.13 | 20 kB | false | false | 3 | 15 | 15 | |
| https://192.168.3.42:2379 | a33139d3a34b9bc4 | 3.5.13 | 20 kB | true | false | 3 | 15 | 15 | |
+---------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
[root@k8s-master01 ~]# ETCDCTL_API=3 /usr/local/bin/etcdctl --write-out=table --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints=https://192.168.3.40:2379,https://192.168.3.41:2379,https://192.168.3.42:2379 endpoint health
+---------------------------+--------+-------------+-------+
| ENDPOINT | HEALTH | TOOK | ERROR |
+---------------------------+--------+-------------+-------+
| https://192.168.3.41:2379 | true | 11.885376ms | |
| https://192.168.3.42:2379 | true | 11.975733ms | |
| https://192.168.3.40:2379 | true | 11.960122ms | |
+---------------------------+--------+-------------+-------+
ETCD 维护 ¶
备份 ETCD 集群 ¶
ETCDCTL_API=3 /usr/local/bin/etcdctl --endpoints=https://192.168.3.42:2379 --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem snapshot save ./`date +%Y-%m-%d-%H:%M`-etcdbackup.db
ETCDCTL_API=3 /usr/local/bin/etcdctl --endpoints=https://192.168.3.42:2379 --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --write-out=table snapshot status ./2024-07-12-13\:08-etcdbackup.db
ETCDCTL_API=3 /usr/local/bin/etcdctl --endpoints=https://192.168.3.42:2379 --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem snapshot restore ./2024-07-12-13\:08-etcdbackup.db
#!/bin/bash
# 定义备份文件路径
BACKUP_DIR="/path/to/backup/dir"
BACKUP_FILE="$BACKUP_DIR/etcd-$(date +%Y%m%d%H%M%S).db"
# 创建备份目录(如果不存在)
mkdir -p $BACKUP_DIR
# 执行数据快照
ETCDCTL_API=3 etcdctl snapshot save $BACKUP_FILE
# 验证快照文件
ETCDCTL_API=3 etcdctl snapshot status $BACKUP_FILE
echo "Backup completed: $BACKUP_FILE"
ETCD 集群节点故障怎么办 ¶
ETCDCTL_API=3 etcdctl --endpoints=https://192.168.3.41:2379,https://192.168.3.42:2379 --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem member list
ETCDCTL_API=3 etcdctl --endpoints=https://192.168.3.41:2379,https://192.168.3.42:2379 --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem member remove acaa7314b910a606
systemctl stop etcd
# 如果故障节点的数据目录已损坏,可以选择清理数据目录。请注意,这会删除该节点上的所有数据,因此需要从其他节点重新同步数据:
rm -rf /var/lib/etcd/default.etcd/*
ETCDCTL_API=3 etcdctl --endpoints=https://192.168.3.41:2379,https://192.168.3.42:2379 --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem \
snapshot restore /opt/etcd/backup/etcdbackup.db --name etcd-1 --data-dir /var/lib/etcd/--initial-cluster etcd-1=https://192.168.3.40:2379 --initial-advertise-peer-urls https://192.168.3.40:2379
#----------------------------------------------------------------------------------------------------------
etcdctl snapshot restore 命令用于从 etcd 的快照文件中恢复数据。在你给出的命令中,有一些参数需要被替换为具体的值来匹配你的 etcd 集群配置。以下是每个参数的解释和应该替换为什么:
ETCDCTL_API=3
#这个环境变量告诉 etcdctl 使用 etcd API 的第 3 版本。通常,你可以直接在命令行前设置这个环境变量,或者在你的 shell 配置文件中设置它。
etcdctl snapshot restore /opt/etcd/backup/etcdbackup.db
#/opt/etcd/backup/etcdbackup.db 是你要从中恢复数据的 etcd 快照文件的路径。确保这个路径是正确的,并且文件是可读的。
--name etcd-master01
#--name 参数定义了 etcd 实例的名称。在你的例子中,它被设置为 etcd-master01。这通常与集群中的特定节点相关联。
--data-dir /var/lib/etcd/
#--data-dir 参数指定了 etcd 存储其数据的目录。在恢复过程中,这个目录将被用于存储恢复的数据。确保这个目录是可写的,并且没有重要的数据,因为恢复过程可能会覆盖它。
--initial-cluster etcd-1=https://192.168.3.40:2379
#--initial-cluster 参数定义了 etcd 集群的初始成员列表。在恢复过程中,你需要指定集群中所有节点的名称和它们的客户端 URL。
--initial-cluster-token etcd-cluster-token
#--initial-cluster-token 参数用于 etcd 集群中的节点在初次启动时相互发现。它应该是一个唯一的字符串,用于你的 etcd 集群。确保所有节点在启动时都使用相同的集群令牌。
--initial-advertise-peer-urls https://192.168.3.40:2379
#--initial-advertise-peer-urls 参数指定了 etcd 节点在集群中用于通信的 URL。这通常是节点的对等体(peer)URL。
existing
ETCDCTL_API=3 etcdctl --endpoints=https://192.168.3.41:2379,https://192.168.3.42:2379 --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem member add etcd-1 --peer-urls=https://192.168.3.40:2380
etcd 集群如何防止 oom ¶
配置优化 ¶
设置 --quota-backend-bytes
限制 etcd 后端数据库的大小,以防止内存过度使用。
etcd --quota-backend-bytes=8589934592 # 8GB
--snapshot-count 调整快照间隔
控制在写操作之后触发快照的间隔。
etcd --snapshot-count=50000
调整压缩策略
通过设置自动压缩策略,定期压缩数据库以释放磁盘空间和内存资源。
etcd --auto-compaction-retention=1 # 每小时进行一次自动压缩
调整缓存大小
适度调整缓存大小,以控制内存使用。
etcd --cache-size=1000
资源管理 ¶
限制系统级别资源
在系统级别限制 etcd 进程的内存使用。可以使用 ulimit 命令来限制进程的资源。
ulimit -m 2097152 # 设置最大虚拟内存为 2GB
ulimit -v 2097152 # 设置最大物理内存为 2GB
使用 cgroups
在 Linux 系统中,可以使用 cgroups 来限制 etcd 进程的资源使用。
cgcreate -g memory:/etcd
echo 2G > /sys/fs/cgroup/memory/etcd/memory.limit_in_bytes
cgexec -g memory:etcd etcd
数据管理 ¶
定期压缩
定期进行 etcd 数据库的压缩操作,以减少数据文件的大小。
ETCDCTL_API=3 etcdctl compact <revision>
清理过期数据
定期清理不再需要的键值对,减少 etcd 数据库的大小。
ETCDCTL_API=3 etcdctl del <key>
监控和报警 ¶
使用 Prometheus、Grafana 等监控工具来监控 etcd 的内存使用情况,并设置报警规则。
配置监控指标
etcd 提供了多种监控指标,可以通过这些指标来检测潜在的内存问题。确保你监控以下关键指标:
- etcd_debugging_mvcc_db_total_size_in_bytes
- etcd_debugging_mvcc_keys_total
- etcd_debugging_mvcc_writes_total
运维需要考虑的问题点 ¶
- etcd 部署方式 考虑不同部署方式的优缺点
- 监控 etcd 数据不一致及节点状态 监控集群分裂、数据不一致等问题
- 监控及告警 etcd 的潜在隐患 监控 db 大小、配额等潜在隐患并及时告警
- 定时及跨区域备份 etcd 数据 实现定时备份和跨区域备份策略
- 模拟磁盘 IO 等异常 复现 Bug 和故障,测试系统的健壮性和恢复能力