etcd是k8s的核心组件之一,主要用于存储k8s集群的所有数据,包括集群的配置信息、集群状态、集群资源等。etcd是一个分布式的、高可用的、一致性的、高性能的键值存储系统,是k8s集群的数据存储中心。
ETCD命令行工具
拷贝etcdctl命令行工具(附加启动etcd命令):
二进制方式
ETCD_VER=v3.4.27
# 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
/tmp/etcd-download-test/etcd --version
/tmp/etcd-download-test/etcdctl version
ln -s /tmp/etcd-download-test/etcdctl /usr/local/bin/
启动etcd命令(对之后的说明没有影响):
# start a local etcd server
/tmp/etcd-download-test/etcd
# write,read to etcd
/tmp/etcd-download-test/etcdctl --endpoints=localhost:2379 put foo bar
/tmp/etcd-download-test/etcdctl --endpoints=localhost:2379 get foo
docker 方式
docker pull gcr.io/etcd-development/etcd:v3.4.27
docker run --rm --name etcd -d gcr.io/etcd-development/etcd:v3.4.27 /usr/local/bin/etcd
docker cp etcd:/usr/local/bin/etcdctl /usr/local/bin/
启动etcd命令(对之后的说明没有影响):
rm -rf /tmp/etcd-data.tmp && mkdir -p /tmp/etcd-data.tmp && \
docker rmi gcr.io/etcd-development/etcd:v3.4.27 || true && \
docker run \
-p 2379:2379 \
-p 2380:2380 \
--mount type=bind,source=/tmp/etcd-data.tmp,destination=/etcd-data \
--name etcd-gcr-v3.4.27 \
gcr.io/etcd-development/etcd:v3.4.27 \
/usr/local/bin/etcd \
--name s1 \
--data-dir /etcd-data \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://0.0.0.0:2379 \
--listen-peer-urls http://0.0.0.0:2380 \
--initial-advertise-peer-urls http://0.0.0.0:2380 \
--initial-cluster s1=http://0.0.0.0:2380 \
--initial-cluster-token tkn \
--initial-cluster-state new \
--log-level info \
--logger zap \
--log-outputs stderr
docker exec etcd-gcr-v3.4.27 /usr/local/bin/etcd --version
docker exec etcd-gcr-v3.4.27 /usr/local/bin/etcdctl version
docker exec etcd-gcr-v3.4.27 /usr/local/bin/etcdctl endpoint health
docker exec etcd-gcr-v3.4.27 /usr/local/bin/etcdctl put foo bar
docker exec etcd-gcr-v3.4.27 /usr/local/bin/etcdctl get foo
ETCD常用操作
查看etcd集群的成员节点
$ export ETCDCTL_API=3
$ etcdctl --endpoints=https://[127.0.0.1]:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key member list -w table
$ alias etcdctl='etcdctl --endpoints=https://[127.0.0.1]:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key'
$ etcdctl member list -w table
查看etcd集群节点状态
$ etcdctl endpoint status -w table
$ etcdctl endpoint health -w table
设置key值
$ etcdctl put test 1
$ etcdctl get test
查看所有key值
$ etcdctl get / --prefix --keys-only
查看具体的key对应的数据
$ etcdctl get /registry/pods/test/myblog-84985b5b66-jp9gg
list-watch
$ etcdctl watch /test/ --prefix
# 另一个终端输入,之前的终端会有输出
$ etcdctl put /test/key1 val1
快照与恢复(重要!)
添加定时任务做数据快照
$ etcdctl snapshot save `hostname`-etcd_`date +%Y%m%d%H%M`.db
恢复快照:
- 停止etcd和apiserver(防止新数据写入)
- 移走当前数据目录
$ mv /var/lib/etcd/ /tmp
- 恢复快照
$ etcdctl snapshot restore `hostname`-etcd_`date +%Y%m%d%H%M`.db --data-dir=/var/lib/etcd/
namespace删除问题
很多情况下,会出现namespace删除卡住的问题,此时可以通过操作etcd来删除数据:
# 查看namespace相关的数据
$ etcdctl get / --prefix --keys-only | grep namespace | grep delete-ns
/registry/namespaces/delete-ns
# 删除namespace相关的数据
$ etcdctl del /registry/namespaces/delete-ns
故障恢复
etcd集群故障恢复
因为etcd中存储着最重要的数据,所以etcd集群的故障恢复是最重要的。如果节点故障,无法正常启动则需要添加新节点进行恢复。
- 将etcd备份数据拷贝到新节点
$ scp /backup/etcd-202109031100.db root@new-etcd:/tmp/
- 将数据恢复到新节点
$ etcdctl snapshot restore /tmp/etcd-202109031100.db --data-dir=/var/lib/etcd/
- 新节点启动etcd
$ name="etcd-new"
$ host="etcd-new-ip"
$ cluster="etcd1=http://etcd-new-ip:2380"
$ docker run -d --privileged=true \
-p 2379:2379 \
-p 2380:2380 \
-v /var/lib/etcd:/data/etcd \
--restart=always \
--name ${name} \
--net=host \
-v /etc/kubernetes/pki/etcd:/etc/kubernetes/pki/etcd \
gcr.io/coreos/etcd:v3.5.0 \
/usr/local/bin/etcd \
--name ${name} \
--data-dir /data/etcd \
--listen-client-urls http://${host}:2379 \
--advertise-client-urls http://${host}:2379 \
--listen-peer-urls http://${host}:2380 \
--initial-advertise-peer-urls http://${host}:2380 \
--initial-cluster ${cluster} \
--initial-cluster-token tkn \
--initial-cluster-state new \
--force-new-cluster \
--log-level info \
--logger zap \
--log-outputs stderr
虽然已经导入了数据,但是还是需要重新初始化集群,重新建立连接,所以需要加上--force-new-cluster参数。
4. 验证集群状态
$ export ETCDCTL_API=3
$ export ETCD_ENDPOINTS="http://etcd-new-ip:2379"
$ etcdctl --endpoints=${ETCD_ENDPOINTS} -w table member list
$ etcdctl --endpoints=${ETCD_ENDPOINTS} -w table endpoint status
$ etcdctl --endpoints=${ETCD_ENDPOINTS} get / --prefix --keys-only
etcd集群增量恢复
如果etcd集群中的数据丢失了一部分,可以通过增量恢复的方式来恢复数据。比如有备份数据etcd-backup1.db和备份数据etc-backup2.db,两次备份数据相差1天,我们丢失了数据,可以只恢复这1天的数据。
- etcdhelper源码下载
etcdhelper不提供二进制文件,需要自己编译,所以需要下载源码:
$ git clone https://github.com/openshift/origin.git
- 编译etcdhelper
$ docker run -d --name go-builder golang:1.17 sleep 3600
$ docker cp origin-master go-builder:/go
$ docker exec -ti go-builder bash
# cd /go/orign-master
# go env -w GOPROXY=https://goproxy.cn,direct
# CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build tools/etcdhelper/etcdhelper.go
# exit
$ docker cp go-builder:/go/origin-master/etcdhelper .
$ cp etcdhelper /usr/local/bin/
- etcdhelper使用
etcdhelper使用方式和etcdctl类似,只是etcdhelper是对etcdctl的封装,可以批量操作,比如批量删除等。获取到的数据是json格式,可以直接查看。
$ export ETCDCTL_API=3
$ export ETCD_ENDPOINTS="http://etcd-new-ip:2379"
$ etcdhelper -endpoints=${ETCD_ENDPOINTS} ls
$ etcdhelper -endpoints=${ETCD_ENDPOINTS} get /registry/pods/test/myblog-84985b5b66-jp9gg
- 增量恢复
比如我们丢失了etcd-backup1.db和etcd-backup2.db之间的数据,我们可以通过etcdhelper获取到这段时间的数据,然后再导入到etcd集群中。这里我们举例误删除了namespace为test下的所有资源情况。
首先我们找一台新机器,恢复etcd-backup1.db的数据,因为etcd-backup1.db是完整的数据,包含被删除的数据。恢复方法参考上面的故障恢复。 - 批量操作获取yaml文件
kubectl没有办法直接使用json格式的文件,因此需要将json格式的文件转换为yaml格式的文件,然后再使用kubectl apply命令。
$ export ETCDCTL_API=3
$ export ETCD_ENDPOINTS="http://etcd-new-ip:2379"
$ etcdctl --endpoints=${ETCD_ENDPOINTS} get / --prefix --keys-only | grep test > keys.txt
# 使用脚本利用etcdhelper将key转换成为json文件
cat key_to_json.sh
#!/bin/bash
i=0
export ETCDCTL_API=3
export ETCD_ENDPOINTS=etcd-new-ip:2379
for line in `cat keys.txt`
do
etcdhelper -endpoint $ETCD_ENDPOINTS get $line > $i.json
# 第一行是资源类型和版本,不是json格式,需要删除
sed -i '1d' $i.json
let 'i+=1'
done
运行脚本,将key转换成为json文件:
$ ./key_to_json.sh
将json文件转换成为yaml文件:
# json to yaml,具体方法就不写了,内容还比较简单
$ python3 json_to_yaml.py
- 批量导入操作
$ cat apply.sh
#!/bin/bash
i=0
for line in `cat keys.txt`
do
kubectl apply -f $i.yaml
let 'i+=1'
done
$ ./apply.sh