第九章 Kubernetes集群维护
1、Etcd数据库备份与恢复
所有 Kubernetes 对象都存储在 etcd 上。 定期备份 etcd 集群数据对于在灾难场景(例如丢失所有控制平面节点)下恢复 Kubernetes 集群非常重要。 快照文件包含所有 Kubernetes 状态和关键信息。为了保证敏感的 Kubernetes 数据的安全,可以对快照文件进行加密。备份 etcd 集群可以通过两种方式完成:etcd 内置快照和卷快照。
1)内置快照
etcd 支持内置快照。快照可以从使用 etcdctl snapshot save 命令的活动成员中获取, 也可以通过从 etcd 数据目录 复制 member/snap/db 文件,该 etcd 数据目录目前没有被 etcd 进程使用。获取快照不会影响成员的性能。
下面是一个示例,用于获取 $ENDPOINT 所提供的键空间的快照到文件 snapshotdb:
ETCDCTL_API=3 etcdctl --endpoints $ENDPOINT snapshot save snapshotdb
验证快照:
ETCDCTL_API=3 etcdctl --write-out=table snapshot status snapshotdb
+----------+----------+------------+------------+
| HASH | REVISION | TOTAL KEYS | TOTAL SIZE |
+----------+----------+------------+------------+
| fe01cf57 | 10 | 7 | 2.1 MB |
+----------+----------+------------+------------+
2)卷快照
如果 etcd 运行在支持备份的存储卷(如 Amazon Elastic Block 存储)上,则可以通过获取存储卷的快照来备份 etcd 数据。
补充:
1)Etcd数据库的Pod的启动方式为静态Pod
2)在Etcd数据库的 /etc/kubernetes/manifests/etcd.yaml 中映射了共享宿主机2个目录
-
/etc/kubernetes/pki/etcd 存放etcd相关crt证书
-
/var/lib/etcd 存放数据目录
3)Etcd开启了 hostNetwork 功能,即共享宿主机网络
bash
[root@k8s-master-1-71 ~]# ss -nlptu | grep 2379
tcp LISTEN 0 128 192.168.1.71:2379 *:* users:(("etcd",pid=2151,fd=9))
tcp LISTEN 0 128 127.0.0.1:2379 *:* users:(("etcd",pid=2151,fd=8))
2、使用 etcdctl 选项的快照
使用 etcdctl 提供的各种选项来制作快照。例如:
需要使用etcdctl工具,需提前安装
bash
yum -y install etcd ETCDCTL_API=3 etcdctl -h
2.1 备份 etcd 集群
通过指定端点、证书等来制作快照(备份),如下所示:
bash
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \ # 指定连接etcd的端口,且是https方式
--cacert=<trusted-ca-file> \ # etcd的根证书
--cert=<cert-file> \ # 客户端的数字证书
--key=<key-file> \ # 客户端的数字证书密钥
snapshot save <backup-file-location> # 指定保存的备份文件
备注:可以从 etcd Pod 的描述中获得 trusted-ca-file、cert-file 和 key-file。
补充:备份只能在线备份
2.2 恢复 etcd 集群
etcd 支持从 major.minor 或其他不同 patch 版本的 etcd 进程中获取的快照进行恢复。 还原操作用于恢复失败的集群的数据。在启动还原操作之前,必须有一个快照文件。它可以是来自以前备份操作的快照文件, 也可以是来自剩余数据目录的快照文件。 例如:
bash
ETCDCTL_API=3 etcdctl --endpoints 127.0.0.1:2379 \
snapshot restore snapshotdb
恢复时也可以指定操作选项,例如:
bash
ETCDCTL_API=3 etcdctl snapshot restore \
--data-dir <data-dir-location> snapshotdb
另一个例子是先导出环境变量:
bash
export ETCDCTL_API=3 //声明环境变量
etcdctl snapshot restore \
--data-dir <data-dir-location> snapshotdb
有关从快照文件还原集群的详细信息和示例,请参阅 etcd 灾难恢复文档。
2.3 etcdctl 备份 / 恢复示例:
1)备份:
javascript
[root@k8s-master-1-71 ~]# ETCDCTL_API=3 etcdctl \
--endpoints=https://127.0.0.1:2379 \ # 指定连接etcd的端口,且是https方式
--cacert=/etc/kubernetes/pki/etcd/ca.crt \ # etcd的根证书
--cert=/etc/kubernetes/pki/etcd/server.crt \ # 客户端的数字证书
--key=/etc/kubernetes/pki/etcd/server.key \ # 客户端的数字证书密钥
snapshot save snap.db
2)尝试删除Pod测试:
javascript
[root@k8s-master-1-71 ~]# kubectl delete pods bs web
3)恢复:
javascript
# 1、先暂停kube-apiserver和etcd容器,通过备份/etc/kubernetes/manifests实现
[root@k8s-master-1-71 ~]# mv /etc/kubernetes/manifests /etc/kubernetes/manifests.bak
# 备份etcd数据库数据文件目录
[root@k8s-master-1-71 ~]# mv /var/lib/etcd/ /var/lib/etcd.bak
# 2、恢复
[root@k8s-master-1-71 ~]# ETCDCTL_API=3 etcdctl \
> snapshot restore snap.db \
> --data-dir=/var/lib/etcd
# 3、启动kube-apiserver和etcd容器
[root@k8s-master-1-71 ~]# mv /etc/kubernetes/manifests.bak/ /etc/kubernetes/manifests
# 4、查看被删除的容器是否被恢复
[root@k8s-master-1-71 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
bs 1/1 Running 1 (11h ago) 16h
web 1/1 Running 1 (11h ago) 16h
2.4 二进制备份恢复方式示例:
1)二进制部署etcd:
javascript
## 1、解压二进制包
[root@k8s-node2-1-73 ~]# tar -zxvf etcd-v3.5.1-linux-amd64.tar.gz
[root@k8s-node2-1-73 ~]# cd etcd-v3.5.1-linux-amd64
[root@k8s-node2-1-73 etcd-v3.5.1-linux-amd64]# cp etcd etcdctl /usr/bin/
## 2、准备配置文件
[root@k8s-node2-1-73 ~]# vi /etc/etcd.conf
ETCD_NAME="etcd"
ETCD_DATA_DIR="/var/lib/etcd"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
ETCD_ADVERTISE_CLIENT_URLS="http://0.0.0.0:2379" //通告地址,声明让其他连接我的IP地址和端口
## 3、准备systemd服务文件
[root@k8s-node2-1-73 ~]# vi /usr/lib/systemd/system/etcd.service
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
EnvironmentFile=/etc/etcd.conf
ExecStart=/usr/bin/etcd
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
## 4、启动服务并设置开机启动
[root@k8s-node2-1-73 ~]# systemctl daemon-reload
[root@k8s-node2-1-73 ~]# systemctl enable etcd --now
## 5、查看etcd状态
[root@k8s-node2-1-73 ~]# etcdctl endpoint status --write-out=table
+----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| 127.0.0.1:2379 | 8e9e05c52164694d | 3.5.1 | 25 kB | true | false | 3 | 6 | 6 | |
+----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
2)备份:
javascript
[root@k8s-node2-1-73 ~]# ETCDCTL_API=3 etcdctl --endpoints=http://127.0.0.1:2379 snapshot save snap1.db
3)恢复:
javascript
# 1、先暂停etcd服务
[root@k8s-node2-1-73 ~]# systemctl stop etcd
[root@k8s-node2-1-73 ~]# mv /var/lib/etcd/ /var/lib/etcd.bak //备份数据目录
# 2、恢复
[root@k8s-node2-1-73 ~]# ETCDCTL_API=3 etcdctl \
snapshot restore snap1.db \
--data-dir=/var/lib/etcd
# 3、启动服务
[root@k8s-node2-1-73 ~]# systemctl start etcd
2.5 多ETCD集群恢复方式示例:
在多ETCD集群环境下,备份只需要备份1个节点即可,但恢复时需要每个节点逐个进行恢复
1)备份:
javascript
ETCDCTL_API=3 etcdctl \
snapshot save snap.db \
--endpoints=https://192.168.1.71:2379 \
--cacert=/opt/etcd/ssl/ca.pem \
--cert=/opt/etcd/ssl/server.pem \
--key=/opt/etcd/ssl/server-key.pem
2)恢复:
javascript
# 1、先暂停kube-apiserver和etcd
systemctl stop kube-apiserver
systemctl stop etcd
mv /var/lib/etcd/ /var/lib/etcd.bak
# 2、在每个节点上恢复
ETCDCTL_API=3 etcdctl snapshot restore snap.db \
--name etcd-1 \
--initial-cluster="etcd-1=https://192.168.1.71:2380,etcd-
2=https://192.168.1.72:2380,etcd-3=https://192.168.1.73:2380" \
--initial-cluster-token=etcd-cluster \
--initial-advertise-peer-urls=https://192.168.1.71:2380 \ //区分每个节点的HOST IP
--data-dir=/var/lib/etcd/
# 3、启动kube-apiserver和etcd
systemctl start kube-apiserver
systemctl start etcd
补充:2380是etcd的集群端口
3、K8s集群版本升级
注意事项:
-
升级前必须备份所有组件及数据,例如etcd
-
千万不要跨多个小版本进行升级,例如从1.16升级到1.19
-
在测试环境经过多次演练,实操,才能上生产环境
3.1 升级管理节点
步骤1:查找和升级最新版本 kubeadm 工具
因为是 kubeadm工具方式 部署集群,每个工具版本和部署集群版本都是一一对应
查看yum仓库相关工具当前和可升级的版本
javascript
[root@k8s-master-1-71 ~]# yum list --showduplicates kubeadm
[root@k8s-master-1-71 ~]# kubectl get node //查看当前kubelete版本
NAME STATUS ROLES AGE VERSION
k8s-master-1-71 Ready control-plane 36d v1.26.0
k8s-node1-1-72 Ready <none> 36d v1.26.0
k8s-node2-1-73 Ready <none> 36d v1.26.0
[root@k8s-master-1-71 ~]# yum -y install kubeadm-1.26.3-0
步骤2:驱逐node上的pod,且不可调度
升级管理节点及工作节点,为规避存在升级带来的风险,建议驱逐node上的pod
- 命令: kubectl drain --ignore-daemonsets
注意:无法驱逐 daemonsets 控制器部署的Pod,需要使用参数--ignore-daemonsets忽略
javascript
[root@k8s-master-1-71 ~]# kubectl drain k8s-master-1-71 --ignore-daemonsets
[root@k8s-master-1-71 ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master-1-71 Ready,SchedulingDisabled control-plane 36d v1.26.0
k8s-node1-1-72 Ready <none> 36d v1.26.0
k8s-node2-1-73 Ready <none> 36d v1.26.0
注意:STATUS中 有SchedulingDisabled 表示该机器在集群中不可调度
步骤3:升级集群的 MASTER 管理节点组件
检查集群是否可以升级,并获取可以升级的版本命令
javascript
[root@k8s-master-1-71 ~]# kubeadm upgrade plan
执行升级命令
javascript
[root@k8s-master-1-71 ~]# kubeadm upgrade apply v1.26.3
检查结果如图所示:
-
红框表示 从当前版本升级到目标版本,所需要升级的组件
-
蓝框表示 升级新版本命令
步骤4:升级 kubelet 和 kubectl
javascript
[root@k8s-master-1-71 ~]# yum -y install kubelet-1.26.3-0 kubectl-1.26.3-0
[root@k8s-master-1-71 ~]# systemctl daemon-reload
[root@k8s-master-1-71 ~]# systemctl restart kubelet
[root@k8s-master-1-71 ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master-1-71 Ready,SchedulingDisabled control-plane 36d v1.26.3 //当前节点已升级
k8s-node1-1-72 Ready <none> 36d v1.26.0
k8s-node2-1-73 Ready <none> 36d v1.26.0
步骤5:取消不可调度,重新上线
javascript
[root@k8s-master-1-71 ~]# kubectl uncordon k8s-master-1-71
[root@k8s-master-1-71 ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master-1-71 Ready control-plane 36d v1.26.3
k8s-node1-1-72 Ready <none> 36d v1.26.0
k8s-node2-1-73 Ready <none> 36d v1.26.0
3.2 升级工作节点
步骤1:升级 kubeadm 工具
javascript
yum install -y kubeadm-1.26.3-0
步骤2:驱逐node上的pod,且不可调度
javascript
kubectl drain k8s-node1-1-72 --ignore-daemonsets --force
kubectl drain k8s-node2-1-73 --ignore-daemonsets --force
注意:
--ignore-daemonsets 是因为节点上有 daemonsets 部署的Pod需要忽略
--force 是因为节点上有 独立Pod
步骤3:升级 kubelet 配置
javascript
# 从master上检查kubelet最新配置
kubeadm upgrade node
# 升级 kubelet
yum install -y kubelet-1.26.3-0 kubectl-1.26.3-0
# 重启kubelet
systemctl daemon-reload
systemctl restart kubelet
步骤4:取消不可调度,重新上线
javascript
kubectl uncordon k8s-node1-1-72
kubectl uncordon k8s-node2-1-73
最终验证:
javascript
[root@k8s-master-1-71 ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master-1-71 Ready control-plane 36d v1.26.3
k8s-node1-1-72 Ready <none> 36d v1.26.3
k8s-node2-1-73 Ready <none> 36d v1.26.3
4、K8s集群节点正确下线流程
如果你想维护某个节点或者删除节点,正确流程如下
javascript
# 1、获取节点列表
kubectl get node
# 2、驱逐节点上的Pod并设置不可调度(cordon)
kubectl drain <node_name> --ignore-daemonsets
# 3、设置可调度或者移除节点
kubectl uncordon <node_name>
kubectl delete node <node_name>
5、K8s集群故障排查
应急处理流程:
排查思路:
--- K8s 故障排查:案例1
**故障现象:**kubectl get node 节点处于 NotReady 状态
排查思路:
-
查看 kubelet 和 docker 服务是否正常
-
分析kubelet日志,jouranlctl -u kubelet -f
-
重启服务,查看日志信息# systemctl restart kubelet ; jouranlctl -u kubelet -f
--- K8s 故障排查:案例2
**故障现象:**Pod运行不正常
排查思路:
-
根据Pod状态假设:Pod 的生命周期 | Kubernetes
-
查看资源详情:kubectl describe TYPE/NAME,主要查看Events事件
-
查看容器日志:kubectl logs TYPE/NAME [-c CONTAINER]
Pod处于Pending状态的可能性:调度器组件问题、资源不足、存在污点等
--- K8s 故障排查:案例3
**故障现象:**互联网用户无法访问应用(Ingress 或者 Service无法访问)
排查思路:
-
K8S层面正常,用户网络到K8S之间的通信问题
-
Pod是否正常工作吗?(running状态 和 Restart次数、是否能通过Pod IP访问Pod)
-
Service是否关联Pod?(kubectl get ep、Service标签是否指向Deployment标签)
-
Service指定target-port端口是否正确?(镜像服务端口是否正确)
-
如果用名称访问,DNS是否正常工作?(coredns是否正常)
-
kube-proxy正常工作吗?是否正常写iptables规则?
-
CNI网络插件是否正常工作?(Calico网络组件异常,导致Pod之间网络无法正常访问)
小结
本篇为 【Kubernetes CKA认证 Day9】的学习笔记,希望这篇笔记可以让您初步了解到 如何进行etcd数据的备份与恢复、使用二进制备份恢复的方法,以及对您的K8S集群进行版本升级和故障排查思路分享
Tip:毕竟两个人的智慧大于一个人的智慧,如果你不理解本章节的内容或需要相关笔记、视频,可私信小安,请不要害羞和回避,可以向他人请教,花点时间直到你真正的理解。