用 Kasten 备份 kubernates etcd 数据库

前言

etcd 是一个典型的健值库(Key Vaule),用于共享配置和服务发现的分布式、一致性的数据库系统。etcd 本身是 CoreOS 公司发起的一个开源项目,和大部分开源软件一样。etcd 存储了 Kubernetes 集群的大部分数据信息,是极为重要的服务之一。如果发生灾难或者 etcd 的数据丢失,将对集群数据的恢复产生非常严重的影响,本文重点讲如何备份和恢复数据。

1. etcd 与 Kubernetes

etcd 是一个典型的健值库(Key Vaule),用于共享配置和服务发现的分布式、一致性的数据库系统。etcd 本身是 CoreOS 公司发起的一个开源项目,和大部分开源软件一样。etcd 存储了 Kubernetes 集群的大部分数据信息,是极为重要的服务之一。如果发生灾难或者 etcd 的数据丢失,将对集群数据的恢复产生非常严重的影响,本文重点讲如何备份和恢复数据。

etcd 开源软件协议
https://github.com/etcd-io/etcd/blob/main/LICENSE

2. Kubernetes 集群的日常运维工作 etcd 的备份

2.1 准备工作 etcdctl 的下载与安装

etcdctl 是我们日常要备份、恢复 etcd 所使用的工具,工欲善其事,必先利其器。我们首先要进行 etcdctl 下载与安装。etcdctl 与 etcd 的软件包在一起,我们可以通过以下链接找到。

https://github.com/etcd-io/etcd/releases

$ wget https://github.com/etcd-io/etcd/releases/download/v3.5.0/etcd-v3.5.0-linux-amd64.tar.gz
$ tar zxvf etcd-v3.5.0-linux-amd64.tar.gz 
$ sudo cp etcd-v3.5.0-linux-amd64/etcdctl /usr/bin/

2.2 验证 etcdctl 可用

etcdctl --help

2.3 手动备份与恢复 etcd

$ kubectl describe node |grep ip
   flannel.alpha.coreos.com/public-ip: 192.168.182.180

2.4 etcd 备份所需要的参数

$ kubectl describe po -n etcd-ubuntu -n kube-system > etcd.txt

$ cat etcd.txt |grep 2379
Annotations:          kubeadm.kubernetes.io/etcd.advertise-client-urls: https://192.168.182.180:2379
      --advertise-client-urls=https://192.168.182.180:2379
      --listen-client-urls=https://127.0.0.1:2379,https://192.168.182.180:2379
      --etcd-servers=https://127.0.0.1:2379

$ cat etcd.txt |grep ca.crt
      --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
      --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
      --client-ca-file=/etc/kubernetes/pki/ca.crt
      --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
      --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
      --client-ca-file=/etc/kubernetes/pki/ca.crt
      --cluster-signing-cert-file=/etc/kubernetes/pki/ca.crt
      --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
      --root-ca-file=/etc/kubernetes/pki/ca.crt

$ cat etcd.txt |grep server.crt
      --cert-file=/etc/kubernetes/pki/etcd/server.crt
      --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
$ cat etcd.txt |grep server.key
      --key-file=/etc/kubernetes/pki/etcd/server.key
      --tls-private-key-file=/etc/kubernetes/pki/apiserver.key

2.5 etcd Backup

# 为 etcd 备份文件建立备份目录
sudo mkdir -p $HOME/etcd-backup-file

# 执行备份操作
$ sudo ECTD_API=3 etcdctl --endpoints=https://192.168.182.180:2379 \
   --cacert=/etc/kubernetes/pki/etcd/ca.crt \
   --cert=/etc/kubernetes/pki/etcd/server.crt \
   --key=/etc/kubernetes/pki/etcd/server.key \
   snapshot save $HOME/etcd-backup-file/etcd-snapshot-`date +%Y%m%d`.db
{"level":"info","ts":1632917737.5671601,"caller":"snapshot/v3_snapshot.go:68","msg":"created temporary db file","path":"/home/mars/etcd-backup-file/etcd-snapshot-20210929.db.part"}
{"level":"info","ts":1632917737.5744143,"logger":"client","caller":"v3/maintenance.go:211","msg":"opened snapshot stream; downloading"}
{"level":"info","ts":1632917737.5744812,"caller":"snapshot/v3_snapshot.go:76","msg":"fetching snapshot","endpoint":"https://192.168.182.180:2379"}
{"level":"info","ts":1632917737.7435777,"logger":"client","caller":"v3/maintenance.go:219","msg":"completed snapshot read; closing"}
{"level":"info","ts":1632917737.7507617,"caller":"snapshot/v3_snapshot.go:91","msg":"fetched snapshot","endpoint":"https://192.168.182.180:2379","size":"4.6 MB","took":"now"}
{"level":"info","ts":1632917737.751167,"caller":"snapshot/v3_snapshot.go:100","msg":"saved","path":"/home/mars/etcd-backup-file/etcd-snapshot-20210929.db"}
Snapshot saved at /home/mars/etcd-backup-file/etcd-snapshot-20210929.db

# 查看备份文件情况

$ ls /home/mars/etcd-backup-file/
etcd-snapshot-20210929.db

3. 用 Kasten 进行 etcd 的备份

如上述文档,将 etcd 的备份进行了描述,但我们不难发现一个问题,如果备份集就是在本地保留,那么如果本地的数据中心出现灾难,则 K8S 及其内的应用都无法恢复。针对这种情况,我们可以使用 Kasten 进行 etcd 的备份。前提是 Kubernetes 集群是通过 Kubeadm 设置的,etcd pod 在 kube-system 命名空间中运行。托管的 Kubernetes 的备份与万利详见 Mars 的 Kasten 实战系列文章。

3.1 获取 etcd 信息

在备份 etcd 集群之前,需要在临时的新名称空间或现有名称空间中创建一个 Secret,其中包含有关 etcd 使用的身份验证机制的详细信息 。在的情况下 kubeadm,很可能已经使用基于 TLS 的身份验证部署了 etcd。可以通过运行以下命令来创建临时命名空间和访问 etcd 的 Secret:

$ kubectl get po -n kube-system

如果服务器密钥和证书的路径提供的不正确,备份将失败。这些路径可以通过在 在之前文档所描述的信息中获取

$ kubectl get po -n kube-system
NAME                             READY   STATUS    RESTARTS   AGE
coredns-74ff55c5b-mgxnw          1/1     Running   0          14m
coredns-74ff55c5b-plq7k          1/1     Running   0          14m
etcd-ubuntu                      1/1     Running   0          14m  # <--这就是我们需要备份的 etcd 数据库
kube-apiserver-ubuntu            1/1     Running   0          14m
kube-controller-manager-ubuntu   1/1     Running   0          14m
kube-flannel-ds-h6gs5            1/1     Running   0          12m
kube-proxy-2vl6g                 1/1     Running   0          14m
kube-scheduler-ubuntu            1/1     Running   0          14m

3.2 安装 Kasten K10

关于 Kasten 的安装在这里只是给出一个示例,详细的文档,请参考 Mars 的 Kasten 实战系列文章


# 建立命名空间
$ kubectl create ns kasten-io

# helm repo add kasten https://charts.kasten.io/
"kasten" has been added to your repositories

$ helm fetch kasten/k10 --version=4.0.12

# 安装 Kasten K10
$ helm install k10 k10-4.0.12.tgz --namespace kasten-io --set global.airgapped.repository=ccr.ccs.tencentyun.com/kasten \
  --set auth.basicAuth.enabled=true \
  --set injectKanisterSidecar.enabled=true \
  --set auth.basicAuth.htpasswd='admin:$apr1$Cgu1sGVZ$w/8aLHZkVT73OqYZ06C0v.' \
  --set metering.mode=airgap \
  --set global.persistence.storageClass=ceph-csi-rbd

# 查看安装情况
$ kubectl get po -n kasten-io
NAME                                 READY   STATUS    RESTARTS   AGE
aggregatedapis-svc-7b6788d55-cfwp5   1/1     Running   0          5m16s
auth-svc-5f79658bd-xjnt5             1/1     Running   0          5m16s
catalog-svc-6db6f6cc69-ghknx         2/2     Running   0          5m16s
config-svc-5cb9f6696f-r9w2g          1/1     Running   0          5m16s
crypto-svc-6c77f4f498-xdq7g          2/2     Running   0          5m17s
dashboardbff-svc-76d56754cd-f7k67    1/1     Running   0          5m16s
executor-svc-78679647fd-6wq8d        2/2     Running   0          5m16s
executor-svc-78679647fd-8g5f6        2/2     Running   0          5m16s
executor-svc-78679647fd-pqc8s        2/2     Running   0          5m16s
frontend-svc-69bbc56d6b-4h24r        1/1     Running   0          5m15s
gateway-b8bb9bb44-hczdx              1/1     Running   0          5m17s
jobs-svc-85545bc5df-p5b8v            1/1     Running   0          5m16s
k10-grafana-589cddff75-6mxzb         1/1     Running   0          5m17s
kanister-svc-68cbcd5d55-mzlxt        1/1     Running   0          5m17s
logging-svc-5cc8675cc8-nzng8         1/1     Running   0          5m16s
metering-svc-56b885f455-59rt5        1/1     Running   0          5m17s
prometheus-server-fc8fb9bb7-hgvtm    2/2     Running   0          5m17s
state-svc-77bb58d6c8-859vf           1/1     Running   0          5m15s

# 暴露 Web UI 服务

$ kubectl expose service gateway -n kasten-io --type=NodePort --name=gateway-nodeport
service/gateway-nodeport exposed

$ kubectl get svc -n  kasten-io gateway-nodeport
NAME               TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
gateway-nodeport   NodePort   10.108.54.108   <none>        8000:32057/TCP   11s

$ kubectl describe node |grep ip
                    flannel.alpha.coreos.com/public-ip: 192.168.182.180

访问如下地址 http://192.168.182.180:32057/k10/#/dashboard

3.3 etcd-backup 准备工作


# 建立 etcd-backup 命名空间
$ kubectl create ns etcd-backup
namespace/etcd-backup created

# 建立关键信息链接
$ kubectl create secret generic etcd-details \
     --from-literal=cacert=/etc/kubernetes/pki/etcd/ca.crt \
     --from-literal=cert=/etc/kubernetes/pki/etcd/server.crt \
     --from-literal=endpoints=https://192.168.182.180:2379 \
     --from-literal=key=/etc/kubernetes/pki/etcd/server.key \
     --from-literal=etcdns=kube-system \
     --from-literal=labels=component=etcd,tier=control-plane \
     --namespace etcd-backup

为避免备份来自命名空间的任何其他工作负载,可以标记 Secret 以确保仅此 Secret 包含在备份中。可以执行以下命令来标记 Secret:etcd-backupetcd-details

$ kubectl get secret -n etcd-backup
NAME                  TYPE                                  DATA   AGE
default-token-bg42p   kubernetes.io/service-account-token   3      92s
etcd-details          Opaque                                6      47s

$ kubectl label secret -n etcd-backup etcd-details include=true
secret/etcd-details labeled

$ kubectl get secrets --show-labels -n etcd-backup
NAME                  TYPE                                  DATA   AGE    LABELS
default-token-bg42p   kubernetes.io/service-account-token   3      113m   <none>
etcd-details          Opaque                                6      113m   include=true

3.4 用 Kasten 备份 etcd

要创建 K10 将用于备份 etcd 的蓝图资源 ,请运行以下命令:

kubectl --namespace kasten-io apply -f \
    https://raw.githubusercontent.com/kanisterio/kanister/0.65.0/examples/etcd/etcd-in-cluster/k8s/etcd-incluster-blueprint.yaml
blueprint.cr.kanister.io/etcd-blueprint created

$ kubectl get blueprint -n kasten-io
NAME                                 AGE
etcd-blueprint                       30s
k10-namespace-generic-volume-2.0.7   88s

创建蓝图后,需要对上面创建的 Secret 进行注释,以指示 K10 使用蓝图在 etcd pod 上执行备份。以下命令演示了如何使用之前创建的蓝图的名称来注释 Secret。

$ kubectl annotate secret -n etcd-backup etcd-details kanister.kasten.io/blueprint='etcd-blueprint'
secret/etcd-details annotated

$ kubectl describe secret etcd-details -n etcd-backup
Name:         etcd-details
Namespace:    etcd-backup
Labels:       include=true
Annotations:  kanister.kasten.io/blueprint: etcd-blueprint

Type:  Opaque

Data
====
endpoints:  26 bytes
etcdns:     11 bytes
key:        35 bytes
labels:     33 bytes
cacert:     31 bytes
cert:       35 bytes

创建 S3 桶

20210929203645

注释 Secret 后,使用 K10 使用新命名空间备份 etcd。如果如前面的步骤之一所述,对 Secret 进行了标记,则在创建策略时,可以通过添加如下所示的资源过滤器将该 Secret 包含在备份中:

20210822165631

可以通过查看创建的还原点的 Kanister 工件找到etcd的备份位置。

20210929203830

4. 恢复 etcd

要恢复 etcd 备份,请登录到运行 etcd pod 的主机(很可能是 Kubernetes control plane)。通过在 K10 仪表板上查看备份操作的详细信息来获取恢复路径,并将快照下载到 etcd pod 主机上的特定位置(例如,/tmp/etcd-snapshot.db)。例如,如果使用 AWS S3 作为对象存储,则需要 AWS CLI 来获取备份。

从备份目标下载快照后,使用 CLI 工具将该快照恢复到特定位置,例如在 K8S Master Node 主机上。以下命令可用于恢复etcd备份:

etcdctl /var/lib/etcd-from-backup

 etcdCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \
      --cacert=/etc/kubernetes/pki/etcd/ca.crt \
      --cert=/etc/kubernetes/pki/etcd/server.crt \
      --key=/etc/kubernetes/pki/etcd/server.key \
      --data-dir="/var/lib/etcd-from-backup" \
      --initial-cluster="master=https://127.0.0.1:2380" \
      --name="master" \
      --initial-advertise-peer-urls="https://127.0.0.1:2380" \
      --initial-cluster-token="etcd-cluster-1" \
      snapshot restore /tmp/snapshot-pre-boot.db

可以从 etcd pod 清单(静态 pod)中发现为上述标志提供的所有值 。两个重要的标志是 --data-dir和--initial-cluster-token。--data-dir是etcd将其数据存储到的目录,并且--initial-cluster-token 是定义新成员加入该 etcd 集群的令牌的标志。注意:一旦备份恢复到新目录,则需要更新 etcd 清单(静态 pod)以将其数据目录指向这个新目录,并且需要在 etcd 命令参数中指定。除此之外, 和字段也应该更改为指向 我们将备份恢复到的新字段。

5. 结论

在本篇文章中我们通过说明了如何进行 etcd 的备份, 这对于日常运维 K8S 集群的人员来说是非常有效的,欢迎与我们讨论您在日常运维过程中的经验,谢谢!

参考文献

https://github.com/etcd-io/etcd/tree/main/etcdctl

etcdctl download
https://github.com/etcd-io/etcd/releases

How etcd works with and without Kubernetes
https://learnk8s.io/etcd-kubernetes

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注