备份集群
对任何系统来说,备份都必不可少,比如备份数据库,备份文件系统,备份配置文件等。
对于Kubernetes来说,备份也尤为重要。Kubernetes中的所有对象都是存储在Etcd中,我们可以直接对数据库进行备份。当然,Kubernetes中所有对象的配置文件也是可见的,我们也可以直接对这些配置文件进行备份。
在真正使用中,一般会做两手方案,即备份数据库和备份配置清单。如果其中一种方案无法进行恢复,还可以通过另一种来兜底。
这里同时会介绍备份Etcd数据库和备份集群配置清单,以方便各位在实际中酌情处理。
备份数据库
备份
备份数据库比较简单,可以直接用etcdctl进行备份,在上面升级证书章节有简单提到。
(1)安装etcdctl命令,在?https://github.com/etcd-io/etcd/releases上下载对应的etcd安装包
$ wget https://github.com/etcd-io/etcd/releases/download/v3.5.3/etcd-v3.5.3-linux-amd64.tar.gz $ tar xf etcd-v3.5.3-linux-amd64.tar.gz $ mv etcd-v3.5.3-linux-amd64/etcdctl /usr/local/bin/
(2)检验命令
$ etcdctl version etcdctl version: 3.5.3 API version: 3.5
(3)进行备份操作
$ export ETCDCTL_API=3 $ etcdctl --endpoints localhost:2379 snapshot save snapshot.db \ --cacert=/etc/kubernetes/pki/etcd/ca.crt \ --cert=/etc/kubernetes/pki/etcd/server.crt \ --key=/etc/kubernetes/pki/etcd/server.key
备份Ectd需要指定证书,如果执行节点没有,可以从主节点拷贝过来。
执行完成过后,可以在当前目录查看到备份结果。
$ export ETCDCTL_API=3 $ etcdctl --endpoints localhost:2379 snapshot save snapshot.db \ > --cacert=/etc/kubernetes/pki/etcd/ca.crt \ > --cert=/etc/kubernetes/pki/etcd/server.crt \ > --key=/etc/kubernetes/pki/etcd/server.key {"level":"info","ts":"2022-07-04T20:00:17.509+0800","caller":"snapshot/v3_snapshot.go:65","msg":"created temporary db file","path":"snapshot.db.part"} {"level":"info","ts":"2022-07-04T20:00:17.520+0800","logger":"client","caller":"v3/maintenance.go:211","msg":"opened snapshot stream; downloading"} {"level":"info","ts":"2022-07-04T20:00:17.520+0800","caller":"snapshot/v3_snapshot.go:73","msg":"fetching snapshot","endpoint":"localhost:2379"} {"level":"info","ts":"2022-07-04T20:00:17.544+0800","logger":"client","caller":"v3/maintenance.go:219","msg":"completed snapshot read; closing"} {"level":"info","ts":"2022-07-04T20:00:17.556+0800","caller":"snapshot/v3_snapshot.go:88","msg":"fetched snapshot","endpoint":"localhost:2379","size":"3.6 MB","took":"now"} {"level":"info","ts":"2022-07-04T20:00:17.556+0800","caller":"snapshot/v3_snapshot.go:97","msg":"saved","path":"snapshot.db"} Snapshot saved at snapshot.db $ ll total 3472 -rw-------. 1 root root 3551264 Jul 4 20:00 snapshot.db
但是,我们不可能每次都手动来进行备份,所以最好是通过定时任务来执行。为了更好的备份,这里编写了一个简单的shell脚本,然后再加到定时任务中。
#! /bin/bash ETCDCTL_PATH='/usr/local/bin/etcdctl' ENDPOINTS='192.168.205.128:2379' ETCD_DATA_DIR="/var/lib/etcd" BACKUP_DIR="/var/backups/kube_etcd/etcd-$(date +%Y-%m-%d_%H:%M:%S)" ETCDCTL_CERT="/etc/kubernetes/pki/etcd/server.crt" ETCDCTL_KEY="/etc/kubernetes/pki/etcd/server.key" ETCDCTL_CA_FILE="/etc/kubernetes/pki/etcd/ca.crt" [ ! -d $BACKUP_DIR ] && mkdir -p $BACKUP_DIR export ETCDCTL_API=2;$ETCDCTL_PATH backup --data-dir $ETCD_DATA_DIR --backup-dir $BACKUP_DIR sleep 3 { export ETCDCTL_API=3;$ETCDCTL_PATH --endpoints="$ENDPOINTS" snapshot save $BACKUP_DIR/snapshot.db \ --cacert="$ETCDCTL_CA_FILE" \ --cert="$ETCDCTL_CERT" \ --key="$ETCDCTL_KEY" } > /dev/null sleep 3 cd $BACKUP_DIR/../;ls -lt |awk '{if(NR>(5+1)){print "rm -rf "$9}}'|sh
然后加入Linux定时任务,如下:
$ crontab -l */30 * * * * /opt/etcd_back/etcd_backup.sh
恢复
(1)停止kube-apiserver和etcd
我这里直接将所有静态Pod的YAML文件移除。
cd /etc/kubernetes/manifests mv *.yaml ../
(2)移除etcd数据目录
$ mv /var/lib/etcd{,.bak.20220705}
(3)执行恢复
¥ ETCDCTL_API=3 etcdctl snapshot restore snapshot.db --name kk-master --initial-cluster "kk-master=https://192.168.205.128:2380" --initial-cluster-token etcd-cluster --initial-advertise-peer-urls https://192.168.205.128:2380 --data-dir=/var/lib/etcd
(4)重启Kubernetes组件
mv ../*.yaml .
(5)验证集群状态
$ kubectl get nodes NAME STATUS ROLES AGE VERSION kk-master Ready control-plane 7h48m v1.24.2 kk-node01 Ready <none> 7h48m v1.24.2 $ kubectl get po -A NAMESPACE NAME READY STATUS RESTARTS AGE default nginx1-585f98d7bf-45fnk 1/1 Running 0 3h58m kube-system calico-kube-controllers-5d49fc6c56-pq57d 1/1 Running 3 (<invalid> ago) 7h45m kube-system calico-node-rjdqh 1/1 Running 0 7h45m kube-system calico-node-s8475 1/1 Running 0 7h45m kube-system coredns-7f74c56694-qpvmv 1/1 Running 0 7h48m kube-system coredns-7f74c56694-ww8kb 1/1 Running 0 7h48m kube-system etcd-kk-master 1/1 Running 0 7h48m kube-system kube-apiserver-kk-master 1/1 Running 2 (2m1s ago) 7h24m kube-system kube-controller-manager-kk-master 1/1 Running 0 7h24m kube-system kube-proxy-5pf65 1/1 Running 0 7h24m kube-system kube-proxy-mcxlq 1/1 Running 0 7h23m kube-system kube-scheduler-kk-master 1/1 Running 0 7h24m
备份集群清单
在Kubernetes的实际使用中,需要备份的集群清单主要有以下几种:
- Deployment类
- StatfulSet类
- DaemonSet类
- Service类
- ConfigMap类
- Secret类
- CronJob类
- ......
备份整个清单可以用于快速恢复集群。而且由于备份etcd是备份的某一时刻的完整数据,无法选择备份哪些内容,并且其备份的数据除了etcd本身,其他程序不可读。
备份集群的方式有很多 ,简单点的可以按照“备份集群”的步骤使用脚本进行备份,由于上面已经介绍了这种方法,这章节将采用另外的工具——velero进行备份。
velero 是开源方案,项目地址:https://velero.io/
velero的作用:
- 灾备能力:提供备份恢复k8s集群的能力
- 迁移能力:提供拷贝集群资源到其他集群的能力
和 etcd 备份的区别:
- etcd 的备份必须拥有 etcd 运维权限,有些用户无法操作 etcd,如多租户场景。
- etcd 更适合单集群内数据备份,不太适合集群迁移
- etcd 是当前状态备份,velero 可以做到只备份集群内的一部分资源
velero 会在你的 k8s 集群上运行一个 server pod,然后配合 velero 客户端进行操作,安装过程可以参考文档,操作是很简单的。
安装客户端
到https://github.com/vmware-tanzu/velero/releases下载对应的版本并安装
$ wget https://github.com/vmware-tanzu/velero/releases/download/v1.9.0/velero-v1.9.0-linux-amd64.tar.gz $ tar xf velero-v1.9.0-linux-amd64.tar.gz $ mv velero-v1.9.0-linux-amd64/velero /usr/local/bin/ $ velero version Client: Version: v1.9.0 Git commit: 6021f148c4d7721285e815a3e1af761262bff029 <error getting server version: namespaces "velero" not found>
安装服务端
安装服务端的方式有两种:
- 使用velero客户端安装
- 使用helm chart安装
这里使用velero客户端进行安装。velero的后端可以选择很多对象存储,比如阿里云OSS,mino等。由于阿里云OSS需要单独购买,所以这里采用minio作为后端存储。
安装minio
(1)添加helm源
$ helm repo add minio https://helm.min.io/
(2)部署minio。由于这里只是做测试,所以没有做数据持久化等处理。
$ helm install minio \ --namespace velero --create-namespace \ --set accessKey=minio,secretKey=minio123 \ --set mode=standalone \ --set service.type=NodePort \ --set persistence.enabled=false \ minio/minio
(2)使用UI访问查看
$ kubectl get svc -n velero NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE minio NodePort 10.110.75.97 <none> 9000:32000/TCP 92s
登录用户名密码为:minio:minio123
安装velero服务端
(1)在minio上创建buckrt
(2)在velero安装目录中创建credentials-velero,写入以下内容
[default] aws_access_key_id=minio aws_secret_access_key=minio123
(3)安装velero
$ velero install \ --provider aws \ --bucket velero \ --image velero/velero:v1.6.3 \ --plugins velero/velero-plugin-for-aws:v1.2.1 \ --namespace velero \ --secret-file ./credentials-velero \ --use-volume-snapshots=false \ --use-restic \ --backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://minio.velero.svc:9000
(4)检查所有组件是否正常启动
$ kubectl get po -n velero NAME READY STATUS RESTARTS AGE minio-6c9f559d5b-cpc2d 1/1 Running 0 3m3s restic-pq5bm 1/1 Running 0 3m28s velero-887577984-2tmm4 1/1 Running 0 3m28s
执行备份操作
(1)在default的namespace下创建一个nginx Pod
$ kubectl create deployment nginx --image nginx
(2)执行备份操作,备份default下面的资源
$ velero backup create default-backup-20220705 --include-namespaces default --default-volumes-to-restic
(3)在minio上可以查看到备份的目录已经存在
(4)现在删除default命名空间下的nginx Pod
$ kubectl delete deployment nginx
(5)执行恢复操作
$ velero restore create --from-backup default-backup-20220705
(6)可以看到default命名空间下的nginx Pod已经恢复
$ kubectl get po NAME READY STATUS RESTARTS AGE nginx-8f458dc5b-z6fnh 1/1 Running 0 38s
总结
Kubernetes是应用的底座,如果底座出问题了,就谈不上应用的稳定性。在实际的工作中,对基础平台的备份尤为重要,可以在遇到不可描述的事情时有兜底的方案,所以,建议对Kubernetes做好备份操作,最好是定时备份。
最后
上面就是常用的集群相关操作,熟练的掌握它们,并应用于实际,可以为你节约不少的时间成本。
当然除了这些常规操作,还有迁移集群、导入集群等,我认为其本质上还是备份还原的问题,只是会多考虑一点数据完整性和业务连续性,这跟具体的企业情况相关,所以在这里也不在赘述,如有兴趣可以私下交流。