• Etcd 常用命令与备份恢复


    1. etcd简介

    官方网站:etcd.io
    官方文档:etcd.io/docs/v3.5/op-guide/maintenance
    官方硬件推荐:etcd.io/docs/v3.5/op-guide/hardware
    github地址:github.com/etcd-io/etcd

    1. etcd是CoreOS团队于20136月发起的开源项目,它的目标是构建一个高可用的分布式键值(key-value)数据库。
    2. etcd内部采用raft协议作为一致性算法,etcd基于Go语言实现。

    2. etcd 特点

    1. 1)完全复制: 集群中的每个节点都可以使用完整的存档(就是集群中每个节点的数据都是一模一样的)
    2. 2)高可用性: Etcd可用于避免硬件的单点故障或网络问题(比如3节点集群,一个宕机了,另外两个会进行自动选主)
    3. 3)一致性: 每次读取都会返回跨多主机的最新写入(就是我在A节点写入的数据,在B节点就能立马查到)
    4. 4)简单: 包括一个定义良好、面向用户的API (gRPC)
    5. 5)安全: 实现了带有可选的客户端证书身份验证的自动化TLS(集群内部通信明文,外部通信加密)
    6. 6)快速: 每秒10000次写入的基准速度
    7. 7)可靠: 使用Raft算法实现了存储的合理分布

    3. etcd启动参数介绍

    etcd启动基本就是靠传参的方式

    1. [root@k8s-etcd01 ~]# cat /etc/systemd/system/etcd.service
    2. [Unit]
    3. Description=Etcd Server
    4. After=network.target
    5. After=network-online.target
    6. Wants=network-online.target
    7. Documentation=https://github.com/coreos
    8. [Service]
    9. Type=notify
    10. WorkingDirectory=/data/etcd
    11. ExecStart=/usr/local/bin/etcd \
    12. --name=etcd-10.31.200.105 \ # 节点名称,这个每个节点都必须不同,因为是基于这个节点名称来识别节点的。
    13. # 这里注意,签发给etcd的证书,都是绑定了节点的IP的,如果涉及到etcd节点的替换,那么IP地址一定要和原节点的IP一样才行。
    14. --cert-file=/etc/kubernetes/ssl/etcd.pem \ # 公钥
    15. --key-file=/etc/kubernetes/ssl/etcd-key.pem \ # 私钥
    16. --peer-cert-file=/etc/kubernetes/ssl/etcd.pem \ # 一样
    17. --peer-key-file=/etc/kubernetes/ssl/etcd-key.pem \ # 一样
    18. --trusted-ca-file=/etc/kubernetes/ssl/ca.pem \ # ca公钥,主要作用就是来校验上面的公钥和私钥是不是基于我这个ca签发的
    19. --peer-trusted-ca-file=/etc/kubernetes/ssl/ca.pem \
    20. --initial-advertise-peer-urls=https://10.31.200.105:2380 \ # 通告自己的集群地址和端口,主要用来角色选举、数据同步
    21. --listen-peer-urls=https://10.31.200.105:2380 \ # 本机监听端口
    22. --listen-client-urls=https://10.31.200.105:2379,http://127.0.0.1:2379 \ # 客户端访问地址
    23. --advertise-client-urls=https://10.31.200.105:2379 \
    24. --initial-cluster-token=etcd-cluster-0 \ # 创建集群时使用的token,同一个集群内的节点保持一致
    25. --initial-cluster=etcd-10.31.200.105=https://10.31.200.105:2380,etcd-10.31.200.106=https://10.31.200.106:2380,etcd-10.31.200.107=https://10.31.200.107:2380 \ # 集群所有节点信息。后续集群内的数据传输都在这3个节点之间。这里害得注意,etcd-10.31.200.105这个配置,必须和--name那里的配置是一样的。
    26. --initial-cluster-state=new \ # 新建集群这个值为new,如果是已经存在的集群,为existing。
    27. --data-dir=/data/etcd \ # 数据目录路径
    28. --wal-dir= \
    29. --snapshot-count=50000 \
    30. --auto-compaction-retention=1 \
    31. --auto-compaction-mode=periodic \
    32. --max-request-bytes=10485760 \
    33. --quota-backend-bytes=8589934592
    34. Restart=always
    35. RestartSec=15
    36. LimitNOFILE=65536
    37. OOMScoreAdjust=-999
    38. [Install]
    39. WantedBy=multi-user.target

    4. etcd选举介绍

    4.1 选举使用的算法

    etcd基于Raft算法进行集群角色选举,使用Raft的还有Consul、InfluxDB、kafka(新版用KRaft、旧版还是zk)等。
    

    4.2 etcd集群角色状态

    1. 集群中每个节点只能处于Leader、Follower和Candidate三种状态的一种。
    2. 1)follower: 追随者(相当于Redis Cluster的Slave节点),负责同步主节点的数据(读从,不能写)。
    3. 2)Candidate:候选者,选举过程中才会出现。
    4. 3)Leader:主节点(相当于Redis Cluster的Master节点),负责当前节点的数据写入(写主,不能读)。

    4.3 etcd集群选举过程-简述版

    1. 节点启动后基于termID(任期ID)进行相互投票,termID是一个整数默认值为0,在Raft算法中,一个term代表leader的一段任期周期,
    2. 每当一个节点成为leader时,就会进入一个新的term, 然后每个节点都会在自己的term ID上加1,以便与上一轮选举区分开来。
    3. 假设启动一个3节点etcd集群,当3个节点都在同一时间启动时(启动时间秒级别内就行),会进入Candidate(候选者)状态,然后各节点进行投票,最终诞生1个leader,该leader会向集群内通告自己当前的角色和状态,说自己成为了leader,剩下2个节点就会自动切换为follower,并设置主地址为leader,从这个leader开始同步数据,同时还会对leader进行心跳检测(看leader还正不正常)。

    在这里插入图片描述

    4.4 etcd集群选举过程-详细版

    4.4.1 首次选举
    1. 1)各etcd节点启动后默认为follower角色、默认termID为0、如果发现集群内没有leader,则会变成 candidate角色并进行选举 leader。
    2. 2)candidate(候选节点)向其它候选节点发送投票信息(RequestVote),默认投票给自己。
    3. 3)各候选节点相互收到另外的投票信息(如A收到BC的,B收到AC的,C收到AB 的),然后对比日志是否比自己的更新,如果比自己的更新,则将自己的选票 投给目的候选人,并回复一个包含自己最新日志信息的响应消息,如果C的日 志更新,那么将会得到A、B、C的投票,则C全票当选,如果B挂了,得到A、 C的投票,则C超过半票当选。
    4. 4)C向其它节点发送自己leader心跳信息,以维护自己的身份(heartbeat- interval、默认100毫秒通告一次)。
    5. 5)其它节点将角色切换为Follower并向leader同步数据。
    6. 6)如果选举超时(election-timeout )、则重新选举,如果选出来两个leader, 则超过集群总数半票的生效。
    4.4.2 后期选举
    1. 1)当一个follower节点在规定时间内未收到leader的消息时,它将转换为candidate状态,向其他节点发送投票请求(自己的term ID和日志更新记录时间), 并等待其他节点的响应,如果该candidate的(日志更新记录最新),则会获多数投票,它将成为新的leader。
    2. 2)新的leader将自己的termID +1 并通告至其它节点。
    3. 3)如果旧的leader恢复了,发现已有新的leader,则加入到已有的leader中,并将自己的term ID更新为和leader一致,在同一个任期内所有节点的term ID是一致的。

    5. etcd优化

    5.1 配置优化

    5.1.1 最大请求字节数
    1. --max-request-bytes=10485760 #request size limit(最大请求字节数。默认客户端请求一个key最大只能是1.5Mib,官方推荐最大不要超出10Mib。改的话就是改这个参数)
    2. [root@k8s-etcd01 ~]# etcd --help|grep max-request-bytes
    3. --max-request-bytes '1572864' # 这就是默认配置
    4. # 修改方式
    5. [root@k8s-etcd01 ~]# grep 'max-request-bytes' /etc/systemd/system/etcd.service
    6. --max-request-bytes=10485760 \ # 就是这个参数,没有的话添加一个就行
    5.1.2 磁盘存储空间大小限制
    1. # 因为etcd存储的只是k8s集群的元数据信息,所以不会占用很大的存储空间,只是对IO消耗比较大。
    2. --quota-backend-bytes=8589934592 #storage size limit(磁盘存储空间大小限制,默认为2G,这里配置的8G,超过8G启动会有警告信息)
    3. # 修改方式
    4. [root@k8s-etcd01 ~]# grep 'quota-backend-bytes' /etc/systemd/system/etcd.service
    5. --quota-backend-bytes=8589934592 # 也是在启动配置文件中加个参数就好了

    5.2 磁盘碎片整理

    etcd集群运行时间长了,包括备份这些操作,就会产生一些磁盘碎片,所以需要定期清理一下

    1. # 如果etcd版本较老,则需要声明下api版本,可以使用etcdctl version查看版本
    2. ETCDCTL_API=3
    3. /usr/local/bin/etcdctl defrag --cluster --endpoints=https://10.31.200.105:2379 -- cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/etcd.pem --key=/etc/kubernetes/ssl/etcd-key.pem
    4. # 新版本的话就不用声明api版本
    5. etcdctl defrag --cluster --endpoints=https://10.31.200.105:2379 -- cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/etcd.pem --key=/etc/kubernetes/ssl/etcd-key.pem
    6. # 清理演示.随便一个节点都行
    7. [root@k8s-etcd01 ~]# etcdctl defrag --cluster --endpoints=https://10.31.200.105:2379 --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/etcd.pem --key=/etc/kubernetes/ssl/etcd-key.pem
    8. Finished defragmenting etcd member[https://10.31.200.105:2379]
    9. Finished defragmenting etcd member[https://10.31.200.106:2379]
    10. Finished defragmenting etcd member[https://10.31.200.107:2379]

    6. etcd客户端命令使用

    etcd服务器的权限、安全、备份,一定要弄好,一旦数据被删除,k8s集群里面就啥也没有了。

    1. etcd有多个不同的API访问版本,v1版本已经废弃,etcd v2 和 v3 本质上是共享同一套 raft 协议代码的两个独立的应用,接口不一样,存储不一样,数据互相隔离。
    2. 也就是说如果从 Etcd v2 升级到 Etcd v3,原来v2 的数据还是只能用 v2 的接口访问,v3 的接口创建的数据也只能访问通过v3 的接口访问。
    3. WARNING:
    4. Environment variable ETCDCTL_API is not set; defaults to etcdctl v2. #默认使用V2版本
    5. Set environment variable ETCDCTL_API=3 to use v3 API or ETCDCTL_API=2 to use v2 API. #设置API版本
    6. # 使用下面的命令可以查看api版本
    7. [root@k8s-etcd01 ~]# etcdctl version
    8. etcdctl version: 3.5.5
    9. API version: 3.5

    6.1 查看集群成员列表

    1. [root@k8s-etcd01 ~]# export NODE_IPS="10.31.200.105 10.31.200.106 10.31.200.107" # 声明一个节点变量
    2. [root@k8s-etcd01 ~]# etcdctl --write-out=table member list --endpoints=https://10.31.200.105:2379 --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/etcd.pem --key=/etc/kubernetes/ssl/etcd-key.pem
    3. +------------------+---------+--------------------+----------------------------+----------------------------+------------+
    4. | ID | STATUS | NAME | PEER ADDRS(集群端口) | CLIENT ADDRS(客户端端口) | IS LEARNER(数据同步状态) |
    5. +------------------+---------+--------------------+----------------------------+----------------------------+------------+
    6. | 43c78a8a8ac5fcae | started | etcd-10.31.200.105 | https://10.31.200.105:2380 | https://10.31.200.105:2379 | false |
    7. | 9869c8c8af112f55 | started | etcd-10.31.200.106 | https://10.31.200.106:2380 | https://10.31.200.106:2379 | false |
    8. | a4a3b2754c389591 | started | etcd-10.31.200.107 | https://10.31.200.107:2380 | https://10.31.200.107:2379 | false |
    9. +------------------+---------+--------------------+----------------------------+----------------------------+------------+
    10. # 参数讲解
    11. --write-out=table: 表格形式输出信息
    12. member list:列出当前集群中的成员

    6.2 查看节点心跳信息

    1. [root@k8s-etcd01 ~]# export NODE_IPS="10.31.200.105 10.31.200.106 10.31.200.107"
    2. [root@k8s-etcd01 ~]# for ip in ${NODE_IPS}; do etcdctl --endpoints=https://${ip}:2379 --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/etcd.pem --key=/etc/kubernetes/ssl/etcd-key.pem endpoint health; done
    3. https://10.31.200.105:2379 is healthy: successfully committed proposal: took = 8.50254ms
    4. https://10.31.200.106:2379 is healthy: successfully committed proposal: took = 15.281376ms
    5. https://10.31.200.107:2379 is healthy: successfully committed proposal: took = 14.666677ms

    6.3 查看集群成员详细信息

    1. [root@k8s-etcd01 ~]# export NODE_IPS="10.31.200.105 10.31.200.106 10.31.200.107"
    2. [root@k8s-etcd01 ~]# for ip in ${NODE_IPS}; do etcdctl --write-out=table endpoint status --endpoints=https://${ip}:2379 --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/etcd.pem --key=/etc/kubernetes/ssl/etcd-key.pem; done
    3. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    4. | ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
    5. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    6. | https://10.31.200.105:2379 | 43c78a8a8ac5fcae | 3.5.5 | 2.2 MB | true | false | 4 | 3250690 | 3250690 | |
    7. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    8. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    9. | ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
    10. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    11. | https://10.31.200.106:2379 | 9869c8c8af112f55 | 3.5.5 | 2.2 MB | false | false | 4 | 3250690 | 3250690 | |
    12. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    13. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    14. | ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
    15. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    16. | https://10.31.200.107:2379 | a4a3b2754c389591 | 3.5.5 | 2.2 MB | false | false | 4 | 3250690 | 3250690 | |
    17. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+

    6.4.1 查看所有key
    1. [root@k8s-etcd01 ~]# etcdctl get / --prefix --keys-only|head # 加个head,或者grep过滤想查的key,防止卡死
    2. /calico/ipam/v2/assignment/ipv4/block/10.200.122.128-26
    3. /calico/ipam/v2/assignment/ipv4/block/10.200.135.128-26
    4. /calico/ipam/v2/assignment/ipv4/block/10.200.195.0-26
    5. /calico/ipam/v2/assignment/ipv4/block/10.200.32.128-26
    6. /calico/ipam/v2/assignment/ipv4/block/10.200.58.192-26
    7. [root@k8s-etcd01 ~]# etcdctl get / --prefix --keys-only|grep pods
    8. /registry/pods/default/net-test1
    9. /registry/pods/default/net-test3
    10. /registry/pods/kube-system/calico-kube-controllers-b6445bbf8-6gqx2
    11. /registry/pods/kube-system/calico-node-bcpqf
    12. /registry/pods/kube-system/calico-node-cf7xm
    13. /registry/pods/kube-system/calico-node-gnrlx
    14. /registry/pods/kube-system/calico-node-hsm8c
    15. /registry/pods/kube-system/calico-node-hv9l4
    16. /registry/pods/kube-system/calico-node-smzz9
    17. /registry/pods/kube-system/coredns-5879bb4b8c-g8z8b
    18. /registry/pods/kube-system/coredns-5879bb4b8c-ph4h4
    19. /registry/pods/myserver/myserver-nginx-deployment-5c9d79c56f-zcj7b

    6.4.2 查看某个key的详细信息
    1. [root@k8s-etcd01 ~]# etcdctl get /registry/pods/default/net-test1 # 但是直接这样查看会乱码,需要额外安装一个工具
    2. [root@k8s-etcd01 ~]# chmod u+x auger # 上传并授权
    3. [root@k8s-etcd01 ~]# mv auger /usr/local/bin/
    4. # 再次查看
    5. [root@k8s-etcd01 ~]# etcdctl get /registry/namespaces/myserver |auger decode # 就相当于直接查看yaml文件
    6. apiVersion: v1
    7. kind: Namespace
    8. metadata:
    9. annotations:
    10. kubectl.kubernetes.io/last-applied-configuration: |
    11. {"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"myserver"}}
    12. creationTimestamp: "2023-04-25T08:14:09Z"
    13. labels:
    14. kubernetes.io/metadata.name: myserver
    15. name: myserver
    16. uid: ead8e171-3d5d-4313-8b32-cb1ff02da6b9
    17. spec:
    18. finalizers:
    19. - kubernetes
    20. status:
    21. phase: Active

    6.5.1 添加数据
    1. [root@k8s-etcd01 ~]# etcdctl put /name "tom" # key: name。value: tom
    2. OK
    3. [root@k8s-etcd01 ~]# etcdctl get /name
    4. /name
    5. tom
    6.5.2 修改数据

    直接覆盖就是更新数据

    1. [root@k8s-etcd01 ~]# etcdctl put /name "jac"
    2. OK
    3. [root@k8s-etcd01 ~]# etcdctl get /name
    4. /name
    5. jac
    6.5.3 删除数据
    1. [root@k8s-etcd01 ~]# etcdctl del /name
    2. 1
    3. [root@k8s-etcd01 ~]# etcdctl get /name # 这里因为key已经被删除了,所以返回空
    4. [root@k8s-etcd01 ~]#

    7. etcd watch(监听)机制

    7.1 etcd watch(监听)机制

    1. 基于不断监看数据,发生变化就主动触发通知客户端,Etcd v3 的watch机制支持watch某个固定的key,也支持watch一个范围。详细如下:
    2. etcd的watch机制可以监听etcd中的key或者prefix,当这些key或者prefix发生变化时,可以触发watch事件,并返回变化的内容。watch机制是etcd的一个核心功能,可以用来实现实时更新、通知等功能。具体的watch机制如下:
    3. 1. 客户端创建一个watcher:客户端先通过watcher API创建一个watcher对象,并指定要监听的key或prefix。
    4. 2. 客户端向etcd提交watcher请求:客户端向etcd提交watcher请求,并指定要监听的key或prefix,同时还可以指定其他的参数,如revision等。
    5. 3. etcd接收watcher请求并处理:etcd首先会检查watcher请求中的revision是否有效,如果有效则直接返回watcher的初始值。如果无效则阻塞请求,等待key或prefix发生变化时再返回。
    6. 4. etcd监视key或prefix的变化:etcd开始监视指定的key或prefix,并在其发生变化时触发watch事件。这时etcd会将变化的内容发送给客户端,并更新watcher的revision值。如果客户端在接收变化内容后仍然需要继续监听,则需要再次提交watcher请求。
    7. 5. 客户端接收变化内容并处理:客户端接收到变化内容后可以进行相应的处理,比如更新缓存、通知其他进程等。
    8. 需要注意的是,etcd的watch机制是基于long polling实现的,并不是同步推送。这意味着当etcd监视的key或prefix长时间没有变化时,watcher请求会一直阻塞,直到发生变化才返回。这种机制可以大大减少网络开销,但也会带来一定的延迟。

    7.2 k8s中哪些组件是watch etcd的

    1. 1)kube-apiserver:Kubernetes的控制面板组件,负责暴露API并接收来自用户的请求。kube-apiserver会watch etcd中的特定资源对象,以便能够在发生变化时及时响应客户端请求。
    2. 2)kube-controller-manager:Kubernetes的控制器管理器组件,负责监控系统中的资源,并调节资源状态以符合期望状态。kube-controller-manager会watch etcd中的各种资源对象,以监控资源的创建、更新、删除等事件。
    3. 3)kube-scheduler:Kubernetes的调度器组件,负责将Pod调度到合适的节点上运行。kube-scheduler会watch etcd中的Pod对象(/registry/events),以获取Pod的调度信息,并根据调度策略进行调度。
    4. 4)kubelet:Kubernetes的节点代理组件,负责管理节点上的容器。kubelet会watch etcd中的Pod对象,以获取自己所管理的Pod的信息,并根据Pod的状态进行容器的创建、启动、停止等操作。
    5. 5)kube-proxy: 它会watch etcd中的/registry/ranges/service,来进行网络规则变更。

    7.3 k8s 组件和etcd之间watch过程

    1. 当某个组件或API server向etcd注册一个watch时,etcd会保持一个持久的连接,并在特定的目录下等待事件。当在这个目录下的值被修改、删除或添加时,etcd会发送一个通知给watcher,并返回最新的版本号,watcher可以根据这个版本号获取最新的数据。
    2. 例如,当Kubernetes Scheduler注册一个watch来监听新的Pod的创建时,etcd会在Pod目录下等待事件。当一个新的Pod被创建时,etcd会将此事件通知给Scheduler,并返回最新的版本号。如果Scheduler希望获取最新的Pods列表,它可以使用这个版本号去获取最新的数据。
    3. 在Kubernetes中,watch机制被广泛应用于各种场景,比如监听新的Pods的创建、更新和删除,监听节点状态的变化,监听Service发现的改变等等。这种机制能够帮助各个组件及时感知资源的变化,从而做出相应的调整。

    7.4 watch演示

    1. #在etcd node1上watch一个key,没有此key也可以执行watch,后期可以再创建
    2. [root@k8s-etcd01 ~]# etcdctl watch /data
    3. # 这就已经开始监听了
    4. # 新开一个终端写入数据
    5. [root@k8s-etcd01 ~]# etcdctl put /data "data v1"
    6. OK
    7. # 回到第一个终端检查监听情况
    8. [root@k8s-etcd01 ~]# etcdctl watch /data # 这个命令是之前执行的。下面可以看到刚才写入的数据,这边监听到了
    9. PUT
    10. /data
    11. data v1

    8. V3版 etcd单节点(单机模式)数据备份恢复

    集群模式不能这样恢复数据,不然恢复数据后,会从1个主变成3个主

    1. etcd的数据写入是基于WAL机制,是write ahead log(预写日志)的缩写,顾名思义,也就是在执行真正的写操作之前先写一个日志,预写日志,类似mysql的binlog,最大的作用是记录了整个数据变化的全部历程。
    2. 在etcd中,所有数据的修改在提交前,都要先写入到WAL中。

    8.1 备份数据

    快照备份,只需要在一个节点执行就行

    1. [root@k8s-etcd01 ~]# etcdctl snapshot save /tmp/etcd.db
    2. {"level":"info","ts":"2023-05-08T18:43:39.868+0800","caller":"snapshot/v3_snapshot.go:65","msg":"created temporary db file","path":"/tmp/etcd.db.part"}
    3. {"level":"info","ts":"2023-05-08T18:43:39.870+0800","logger":"client","caller":"v3/maintenance.go:211","msg":"opened snapshot stream; downloading"}
    4. {"level":"info","ts":"2023-05-08T18:43:39.870+0800","caller":"snapshot/v3_snapshot.go:73","msg":"fetching snapshot","endpoint":"127.0.0.1:2379"}
    5. {"level":"info","ts":"2023-05-08T18:43:39.895+0800","logger":"client","caller":"v3/maintenance.go:219","msg":"completed snapshot read; closing"}
    6. {"level":"info","ts":"2023-05-08T18:43:39.970+0800","caller":"snapshot/v3_snapshot.go:88","msg":"fetched snapshot","endpoint":"127.0.0.1:2379","size":"2.2 MB","took":"now"}
    7. {"level":"info","ts":"2023-05-08T18:43:39.970+0800","caller":"snapshot/v3_snapshot.go:97","msg":"saved","path":"/tmp/etcd.db"}
    8. Snapshot saved at /tmp/etcd.db
    9. [root@k8s-etcd01 ~]# ll -rt /tmp/
    10. 总用量 2172
    11. -rw------- 1 root root 2220064 58 18:43 etcd.db

    8.2 恢复数据

    无法恢复备份后被误删的增量数据

    1. [root@k8s-etcd01 ~]# etcdctl snapshot restore /tmp/etcd.db --data-dir=/opt/etcd-testdir # #将数据恢复到一个新
    2. 的不存在的目录中,--data-dir参数必须要加,且必须指定一个不存在的目录,如果存在会报错
    3. Deprecated: Use `etcdutl snapshot restore` instead.
    4. 2023-05-08T18:50:33+08:00 info snapshot/v3_snapshot.go:248 restoring snapshot {"path": "/tmp/etcd.db", "wal-dir": "/opt/etcd-testdir/member/wal", "data-dir": "/opt/etcd-testdir", "snap-dir": "/opt/etcd-testdir/member/snap", "stack": "go.etcd.io/etcd/etcdutl/v3/snapshot.(*v3Manager).Restore\n\t/tmp/etcd-release-3.5.5/etcd/release/etcd/etcdutl/snapshot/v3_snapshot.go:254\ngo.etcd.io/etcd/etcdutl/v3/etcdutl.SnapshotRestoreCommandFunc\n\t/tmp/etcd-release-3.5.5/etcd/release/etcd/etcdutl/etcdutl/snapshot_command.go:147\ngo.etcd.io/etcd/etcdctl/v3/ctlv3/command.snapshotRestoreCommandFunc\n\t/tmp/etcd-release-3.5.5/etcd/release/etcd/etcdctl/ctlv3/command/snapshot_command.go:129\ngithub.com/spf13/cobra.(*Command).execute\n\t/usr/local/google/home/siarkowicz/.gvm/pkgsets/go1.16.15/global/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:856\ngithub.com/spf13/cobra.(*Command).ExecuteC\n\t/usr/local/google/home/siarkowicz/.gvm/pkgsets/go1.16.15/global/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:960\ngithub.com/spf13/cobra.(*Command).Execute\n\t/usr/local/google/home/siarkowicz/.gvm/pkgsets/go1.16.15/global/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:897\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.Start\n\t/tmp/etcd-release-3.5.5/etcd/release/etcd/etcdctl/ctlv3/ctl.go:107\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.MustStart\n\t/tmp/etcd-release-3.5.5/etcd/release/etcd/etcdctl/ctlv3/ctl.go:111\nmain.main\n\t/tmp/etcd-release-3.5.5/etcd/release/etcd/etcdctl/main.go:59\nruntime.main\n\t/usr/local/google/home/siarkowicz/.gvm/gos/go1.16.15/src/runtime/proc.go:225"}
    5. 2023-05-08T18:50:33+08:00 info membership/store.go:141 Trimming membership information from the backend...
    6. 2023-05-08T18:50:33+08:00 info membership/cluster.go:421 added member {"cluster-id": "cdf818194e3a8c32", "local-member-id": "0", "added-peer-id": "8e9e05c52164694d", "added-peer-peer-urls": ["http://localhost:2380"]}
    7. 2023-05-08T18:50:33+08:00 info snapshot/v3_snapshot.go:269 restored snapshot {"path": "/tmp/etcd.db", "wal-dir": "/opt/etcd-testdir/member/wal", "data-dir": "/opt/etcd-testdir", "snap-dir": "/opt/etcd-testdir/member/snap"}
    8. [root@k8s-etcd01 ~]# ll /opt/etcd-testdir/member/ # 恢复的数据都在这里
    9. 总用量 0
    10. drwx------ 2 root root 62 58 18:50 snap
    11. drwx------ 2 root root 51 58 18:50 wal

    8.3 通过脚本自动备份

    1. [root@k8s-etcd01 ~]# mkdir /data/etcd-backup-dir/ -p
    2. [root@k8s-etcd01 ~]# cat etcd-backup.sh
    3. #!/bin/bash
    4. source /etc/profile
    5. DATE=`date +%Y-%m-%d_%H-%M-%S`
    6. ETCDCTL_API=3 /usr/local/bin/etcdctl snapshot save /data/etcd-backup-dir/etcd-snapshot-${DATE}.db
    7. [root@k8s-etcd01 ~]# sh etcd-backup.sh # 测试可用后,加入定时任务就行了
    8. [root@k8s-etcd01 ~]# ll /data/etcd-backup-dir
    9. 总用量 2172
    10. -rw------- 1 root root 2220064 58 19:04 etcd-snapshot-2023-05-08_19-04-40.db

    9. 备份恢复案例演示(集群模式)

    9.1 备份集群数据

    1. [root@k8s-harbor01 kubeasz]# ./ezctl backup k8s-cluster1 # 这个命令其实也是在执行edctctl命令
    2. [root@k8s-harbor01 kubeasz]# ll clusters/k8s-cluster1/backup/ # 备份的数据
    3. 总用量 4344
    4. -rw------- 1 root root 2220064 58 22:00 snapshot_202305082200.db
    5. -rw------- 1 root root 2220064 58 22:00 snapshot.db

    9.2 删除k8s集群中的数据

    1. [root@k8s-harbor01 kubeasz]# kubectl get po
    2. NAME READY STATUS RESTARTS AGE
    3. net-test1 1/1 Running 0 3h41m
    4. net-test3 1/1 Running 0 13d
    5. [root@k8s-harbor01 kubeasz]# kubectl delete po net-test3 # 这里我删除了net-test3这个pod
    6. pod "net-test3" deleted
    7. [root@k8s-harbor01 kubeasz]# kubectl get po
    8. NAME READY STATUS RESTARTS AGE
    9. net-test1 1/1 Running 0 3h42m

    9.3 再次备份集群数据

    模拟有多备份文件,得从中找到我们需要的这个备份数据

    1. [root@k8s-harbor01 kubeasz]# ./ezctl backup k8s-cluster1
    2. [root@k8s-harbor01 kubeasz]# ll clusters/k8s-cluster1/backup/
    3. 总用量 6516
    4. -rw------- 1 root root 2220064 58 22:00 snapshot_202305082200.db
    5. -rw------- 1 root root 2220064 58 22:07 snapshot_202305082207.db # 这里需要注意:snapshot_202305082207.db就是snapshot.db,看文件修改时间能看出来。由于安装k8s的工具脚本里面写死了,恢复的时候一定要用snapshot.db,所以必须要把snapshot_202305082207.db,重命名成snapshot.db。
    6. -rw------- 1 root root 2220064 58 22:07 snapshot.db

    9.4 恢复数据

    ** 注意:在恢复数据期间API server不可用,必须在业务低峰期操作或者是在其它紧急场景。
    生产中的备份,数据量不大的话,一天一备就行,所以直接直接找删除数据前一天的备份就行**

    1. [root@k8s-harbor01 backup]# pwd
    2. /etc/kubeasz/clusters/k8s-cluster1/backup
    3. [root@k8s-harbor01 backup]# ll # 因为这些都是二进制文件,所以没法grep过滤字符
    4. 总用量 6516
    5. -rw------- 1 root root 2220064 58 22:00 snapshot_202305082200.db
    6. -rw------- 1 root root 2220064 58 22:07 snapshot_202305082207.db
    7. -rw------- 1 root root 2220064 58 22:07 snapshot.db
    8. # 重命名备份文件
    9. [root@k8s-harbor01 backup]# cp snapshot_202305082200.db snapshot.db
    10. cp:是否覆盖"snapshot.db"? y
    11. # 恢复数据
    12. [root@k8s-harbor01 kubeasz]# ./ezctl restore k8s-cluster1 # 这里会根据剧本中的集群级别恢复命令,来进行数据恢复。恢复过程中会先关闭k8s所有节点的相关服务,防止新的数据写入
    13. ansible-playbook -i clusters/k8s-cluster1/hosts -e @clusters/k8s-cluster1/config.yml playbooks/95.restore.yml
    14. 2023-05-08 22:16:12 INFO cluster:k8s-cluster1 restore begins in 5s, press any key to abort:
    15. TASK [stopping kube_master services]
    16. TASK [stopping kube_node services]
    17. TASK [cluster-restore : 停止ectd 服务]
    18. TASK [cluster-restore : 清除etcd 数据目录]
    19. TASK [cluster-restore : 清除 etcd 备份目录]
    20. TASK [cluster-restore : etcd 数据恢复]
    21. TASK [cluster-restore : 分发恢复文件到 etcd 各个节点]
    22. TASK [cluster-restore : 重启etcd 服务]
    23. ……省略部分内容

    9.5 查看恢复后的数据

    1. [root@k8s-harbor01 kubeasz]# kubectl get po
    2. NAME READY STATUS RESTARTS AGE
    3. net-test1 1/1 Running 0 3h59m
    4. net-test3 0/1 ContainerCreating 1 13d
    5. [root@k8s-harbor01 kubeasz]# kubectl get po
    6. NAME READY STATUS RESTARTS AGE
    7. net-test1 1/1 Running 0 3h59m
    8. net-test3 1/1 Running 0 13d # 这里可以看到,被删除的net-test3又恢复了
    9. # 被删除的pod是恢复了,但是集群中的其他pod可能会有问题,因为当前版本的kubeasz有个bug,会导致etcd恢复数据后,从集群变成单机,有3个主
    10. [root@k8s-harbor01 kubeasz]# kubectl get po -A|grep '0/1'
    11. default net-test3 0/1 ContainerCreating 1 13d
    12. kube-system coredns-5879bb4b8c-g8z8b 0/1 Running 0 14d
    13. [root@k8s-harbor01 kubeasz]# kubectl get po -A|grep '0/1'
    14. kube-system calico-kube-controllers-b6445bbf8-6gqx2 0/1 Running 1 (17m ago) 14d
    15. kube-system calico-node-cf7xm 0/1 Running 0 14d
    16. kube-system calico-node-hsm8c 0/1 Running 0 14d
    17. kube-system calico-node-smzz9 0/1 Running 0 14d
    18. kube-system coredns-5879bb4b8c-ph4h4 0/1 Running 0 12d
    19. [root@k8s-etcd01 ~]# export NODE_IPS="10.31.200.105 10.31.200.106 10.31.200.107"
    20. [root@k8s-etcd01 ~]# for ip in ${NODE_IPS}; do etcdctl --write-out=table endpoint status --endpoints=https://${ip}:2379 --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/etcd.pem --key=/etc/kubernetes/ssl/etcd-key.pem; done
    21. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    22. | ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
    23. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    24. | https://10.31.200.105:2379 | 8e9e05c52164694d | 3.5.5 | 2.2 MB | true | false | 2 | 19078 | 19078 | |
    25. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    26. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    27. | ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
    28. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    29. | https://10.31.200.106:2379 | 8e9e05c52164694d | 3.5.5 | 2.2 MB | true | false | 2 | 18332 | 18332 | |
    30. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    31. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    32. | ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
    33. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    34. | https://10.31.200.107:2379 | 8e9e05c52164694d | 3.5.5 | 2.2 MB | true | false | 2 | 18191 | 18191 | |
    35. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+

    9.6 恢复etcd多主bug

    当前版本的修复文件:https://github.com/easzlab/kubeasz/blob/3.5.3/roles/cluster-restore/tasks/main.yml

    1. # 旧的备份剧本
    2. [root@k8s-harbor01 kubeasz]# cat roles/cluster-restore/tasks/main.yml
    3. - name: 停止ectd 服务
    4. service: name=etcd state=stopped
    5. - name: 清除etcd 数据目录
    6. file: name={{ ETCD_DATA_DIR }}/member state=absent
    7. - name: 清除 etcd 备份目录
    8. file: name={{ cluster_dir }}/backup/etcd-restore state=absent
    9. delegate_to: 127.0.0.1
    10. run_once: true
    11. - name: etcd 数据恢复 # 就这里,采用了单机etcd的恢复方式,导致集群有了3个主
    12. shell: "cd {{ cluster_dir }}/backup && \
    13. ETCDCTL_API=3 {{ base_dir }}/bin/etcdctl snapshot restore snapshot.db \
    14. --data-dir={{ cluster_dir }}/backup/etcd-restore"
    15. delegate_to: 127.0.0.1
    16. run_once: true
    17. - name: 分发恢复文件到 etcd 各个节点
    18. copy: src={{ cluster_dir }}/backup/etcd-restore/member dest={{ ETCD_DATA_DIR }}
    19. - name: 重启etcd 服务
    20. service: name=etcd state=restarted
    21. - name: 以轮询的方式等待服务同步完成
    22. shell: "systemctl is-active etcd.service"
    23. register: etcd_status
    24. until: '"active" in etcd_status.stdout'
    25. retries: 8
    26. delay: 8
    27. # 用官网的修复文件替换上面的文件
    28. [root@k8s-harbor01 kubeasz]# cat roles/cluster-restore/tasks/main.yml
    29. - name: 停止ectd 服务
    30. service: name=etcd state=stopped
    31. - name: 清除etcd 数据目录
    32. file: name={{ ETCD_DATA_DIR }}/member state=absent
    33. - name: 清理上次备份恢复数据
    34. file: name=/etcd_backup state=absent
    35. - name: 生成备份目录
    36. file: name=/etcd_backup state=directory
    37. - name: 准备指定的备份etcd 数据
    38. copy:
    39. src: "{{ cluster_dir }}/backup/{{ db_to_restore }}"
    40. dest: "/etcd_backup/snapshot.db"
    41. - name: etcd 数据恢复 # 集群级别的恢复方式
    42. shell: "cd /etcd_backup && \
    43. ETCDCTL_API=3 {{ bin_dir }}/etcdctl snapshot restore snapshot.db \
    44. --name etcd-{{ inventory_hostname }} \
    45. --initial-cluster {{ ETCD_NODES }} \
    46. --initial-cluster-token etcd-cluster-0 \
    47. --initial-advertise-peer-urls https://{{ inventory_hostname }}:2380"
    48. - name: 恢复数据至etcd 数据目录
    49. shell: "cp -rf /etcd_backup/etcd-{{ inventory_hostname }}.etcd/member {{ ETCD_DATA_DIR }}/"
    50. - name: 重启etcd 服务
    51. service: name=etcd state=restarted
    52. - name: 以轮询的方式等待服务同步完成
    53. shell: "systemctl is-active etcd.service"
    54. register: etcd_status
    55. until: '"active" in etcd_status.stdout'
    56. retries: 8
    57. delay: 8
    58. # 重新执行一次恢复命令
    59. [root@k8s-harbor01 kubeasz]# ./ezctl restore k8s-cluster1
    60. # 查看etcd集群状态
    61. [root@k8s-etcd01 ~]# export NODE_IPS="10.31.200.105 10.31.200.106 10.31.200.107"
    62. [root@k8s-etcd01 ~]# for ip in ${NODE_IPS}; do etcdctl --write-out=table endpoint status --endpoints=https://${ip}:2379 --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/etcd.pem --key=/etc/kubernetes/ssl/etcd-key.pem; done # 这里就能看到集群恢复正常了
    63. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    64. | ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
    65. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    66. | https://10.31.200.105:2379 | 43c78a8a8ac5fcae | 3.5.5 | 3.0 MB | true | false | 2 | 1303 | 1303 | |
    67. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    68. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    69. | ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
    70. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    71. | https://10.31.200.106:2379 | 9869c8c8af112f55 | 3.5.5 | 3.0 MB | false | false | 2 | 1303 | 1303 | |
    72. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    73. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    74. | ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
    75. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    76. | https://10.31.200.107:2379 | a4a3b2754c389591 | 3.5.5 | 3.0 MB | false | false | 2 | 1303 | 1303 | |
    77. +----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
    78. # 查看pod状态
    79. [root@k8s-harbor01 kubeasz]# kubectl get po -A # 可以看到所有pod都恢复了正常
    80. NAMESPACE NAME READY STATUS RESTARTS AGE
    81. default net-test1 1/1 Running 0 4h27m
    82. default net-test3 1/1 Running 0 13d
    83. kube-system calico-kube-controllers-b6445bbf8-6gqx2 1/1 Running 2 (8m3s ago) 14d
    84. kube-system calico-node-bcpqf 1/1 Running 0 14d
    85. kube-system calico-node-cf7xm 1/1 Running 0 14d
    86. kube-system calico-node-gnrlx 1/1 Running 0 14d
    87. kube-system calico-node-hsm8c 1/1 Running 0 14d
    88. kube-system calico-node-hv9l4 1/1 Running 0 14d
    89. kube-system calico-node-smzz9 1/1 Running 0 14d
    90. kube-system coredns-5879bb4b8c-g8z8b 1/1 Running 0 14d
    91. kube-system coredns-5879bb4b8c-ph4h4 1/1 Running 0 12d
    92. myserver myserver-nginx-deployment-5c9d79c56f-zcj7b 1/1 Running 0 4d1h

    10. etcd数据恢复流程

    当etcd集群宕机数量超过集群总节点数一半以上的时候(如总数为三台宕机两台),就会导致整合集群宕机,后期需要重新恢复数据,则恢复流程如下:

    10.1 如果宕机导致机器没法开机了

    1. 1)停止kube-apiserver/controller-manager/scheduler/kubelet/kube-proxy。
    2. 2)重新找机器部署ETCD集群。
    3. 3)停止运行ETCD集群。
    4. 4)各ETCD节点恢复同一份备份数据。
    5. 5)启动各节点并验证ETCD集群(12从)。
    6. 6)启动kube-apiserver/controller-manager/scheduler/kubelet/kube-proxy。
    7. 7)验证k8s master状态及pod数据。

    10.2 如果意外宕机,能开机,但有数据丢失

    1. 1)停止kube-apiserver/controller-manager/scheduler/kubelet/kube-proxy。
    2. 2)启动宕机的服务器,看etcd集群是否正常运行。
    3. 3)停止运行ETCD集群。
    4. 4)各ETCD节点恢复同一份备份数据。
    5. 5)启动各节点并验证ETCD集群。
    6. 6)启动kube-apiserver/controller-manager/scheduler/kubelet/kube-proxy。
    7. 7)验证k8s master状态及pod数据。

    11. etcd集群节点删除和添加

    工作中更多的还是数据备份恢复,一般不会涉及节点的扩容和缩容

    1. # 具体过程看剧本
    2. add-etcd
    3. del-etcd
  • 相关阅读:
    STM32无硬件随机数发生器时生成随机数的方法
    网易游戏 Flink SQL 平台化实践
    如何实现机器人自动拉微信群
    C++——继承
    企业邮箱认证指南:安全与高效的邮箱认证方法
    linux中权限管理命令chown,chgrp,umask
    JAVA基础 - java.io.IOException:Parent directory of file does not exist
    《Python入门到精通》条件控制 if 语句
    多模态学习(一) 初识
    微信小程序获取openid流程
  • 原文地址:https://blog.csdn.net/qq_19734597/article/details/134239106