暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Velero备份实战 - 基于Ceph的CSI快照

Velero中文社区 2021-05-19
925

更多velero相关技术讨论,敬请关注velero中文社区官方网站:

https://velero.cn/



景知识

卷快照(Volume Snapshot)

继CSI之后,卷快照在Kubernetes v1.12发布了alpha版,引入了以下几个关键的API对象:

  • VolumeSnapshot

    与PVC类似,当用户想创建或删除一个卷快照时,可以选择创建或删除一个VolumeSnapshot。

  • VolumeSnapshotContent

    同PV类似,VolumeSnapshotContent代表集群中被分配的一个快照资源。当一个VolumeSnapshot被创建时,CSI驱动会创建一个VolumeSnapshotContent对象。VolumeSnapshotContent同VolumeSnapshot互相引用,是1对1的关系。

    VolumeSnapshotContent建立了同底层存储的快照的映射关系,VolumeSnapshotContent中的SnapshotHandle是一个指向存储快照的UID。

  • VolumeSnapshotClass

    VolumeSnapshotClass同StorageClass类似,指定了卷快照的一些参数,如驱动的信息,DeletionPolicy,访问快照的Secret等。

值得注意的是,上面3个API对象并不是Kubernetes的核心API对象,而是CRD。一般来说,CSI驱动会自动安装所需的CRD。

CSI Snapshotter

CSI Snapshotter是Kubernetes CSI实现的一部分,主要包括以下几个部分:

  • Kubernetes卷快照的CRD

  • 卷快照控制器(Volume snapshot controller)

  • CSI Snapshotter sidecar

    一般来说,这个sidecar同CSI驱动是一起部署的。

  • 快照验证webhook

其中,卷快照控制器和CSI Snapshotter sidecar是核心部分。卷快照控制器监听VolumeSnapshot和VolumeSnapshotContent的创建、更新、删除事件。而CSI Snapshotter sidecar只监听VolumeSnapshotContent的创建、更新、删除。

例如,在动态预配(dynamic provision)情况下,当一个VolumeSnapshot被创建后,卷快照控制器监听到这个事件,在条件满足的情况下会创建一个VolumeSnapshotContent。之后,CSI Snapshotter sidecar监听到VolumeSnapshotContent创建的事件,在条件满足的情况下会调用CSI驱动的API去创建底层存储的快照。

Ceph RBD

RBD是Ceph的块设备接口实现,是Ceph最常用的存储类型。RBD块设备类似磁盘可以被挂载,一个实例化的RBD设备被称为RBD镜像(image)。RBD块设备具有快照、多副本、克隆和一致性等特性,数据以条带化的方式存储在Ceph集群的多个OSD中。

  • RBD快照(snapshot)

    RBD快照是是某一RBD镜像在特定时间点的一个只读副本。RBD的快照实现机制是COW(copy on write)写时复制。

  • RBD克隆(clone)

    RBD克隆是对某个快照的状态进行复制变成另一个镜像,从而可以实现写操作。

在Ceph CSI驱动的设计文档中,可以看到对一个PVC做一个快照大概分为如下几步:

  1. 创建一个临时的快照

  2. 从上面的快照克隆一个镜像,参数为--rbd-default-clone-format 2 --image-feature layering,deep-flatten

  3. 删除临时创建的快照

由此可见,当一个CSI的卷快照被创建时,Ceph实际创建的是一个可读可写的克隆。


环境准备

  • K8s 1.19安装

    这里略过,请参考使用kubeadm安装kubernetes_v1.19.x。

  • Rook-Ceph 1.4安装

  1. 获取rook的代码仓库,并切换到release-1.4:

      git clone https://github.com/rook/rook.git
    git checkout release-1.4

  2. 进入ceph的example目录,编辑cluster.yaml

      cd rook/cluster/examples/kubernetes/ceph
    vi cluster.yaml

    resources:
    部分,按照机器的配置来指定Ceph的CPU和内存资源,以下是一个参考:

        resources:
    mgr:
    limits:
    cpu: "500m"
    memory: "1024Mi"
    requests:
    cpu: "500m"
    memory: "1024Mi"
    mon:
    limits:
    cpu: "500m"
    memory: "1024Mi"
    mds:
    limits:
    cpu: "500m"
    memory: "1024Mi"
    crashcollector:
    limits:
    cpu: "500m"
    memory: "1024Mi"
    osd:
    limits:
    cpu: "1"
    memory: "2048Mi"
    requests:
    cpu: "1"
    memory: "2048Mi"

    storage:
    部分,根据集群节点以及挂载的块设备来填写这部分信息,以下是一个单节点集群,单个块设备的例子:

        storage: # cluster level storage configuration and selection
    useAllNodes: false
    useAllDevices: false
    nodes:
    - name: "dev-host1"
    devices: # specific devices to use for storage can be specified for each node
    - name: "sdb"
    config:
    osdsPerDevice: "2"
    storType: bluestore

  3. Ceph安装,依次执行下面的命令:

      kubectl create -f common.yaml
    kubectl create -f operator.yaml
    kubectl create -f cluster.yaml

    这里安装过程大概会有15分钟左右,取决于集群节点的数量以及提供给Ceph的块设备的数量。如果需要rook的toolbox,可以等ceph安装完成后执行:

      kubectl create -f toolbox.yaml

    如果出现问题,请参考文章尾部的Ceph teardown部分,尝试卸载,调整参数之后,重新安装。

  4. 创建ceph storageclass, snapshot class

      cd csi/rbd

    注意:如果是单节点的集群,要将storageclass里的failureDomain
    去掉,并且把replicated: size
    改成2

    执行:

       kubectl create -f storageclass.yaml

    注意:snapshotclass的deletionPolicy
    必须是Retain
    ,并且加上label:

      labels:
    velero.io/csi-volumesnapshot-class: "true"

    执行:

      kubectl create -f snapshotclass.yaml
  • Volumesnapshot CRD

    1. 获取external-snapshotter的代码仓库:

        git clone https://github.com/kubernetes-csi/external-snapshotter.git
    2. 进入external-snapshotter
      目录,执行以下命令来创建CRD:

        kubectl create -f config/crd
    3. 执行以下命令来创建snapshot controller:

        kubectl create -f deploy/kubernetes/snapshot-controller/
  • minio安装

    minio是一个开源的对象存储,并且与AWS的S3兼容,它的特点是容易安装上手。minio有多种安装模式,具体可以参考minio quickstart guide。本文用一个最简便的安装方式,就在velero的下载包中,有一个example/minio/
    的目录,进去执行:

      kubectl create -f 00-minio-deployment.yaml

    这个yaml文件里,有几个地方需要注意:

          spec:
    volumes:
    - name: storage
    emptyDir: {}
    ...
    env:
    - name: MINIO_ACCESS_KEY
    value: "minio"
    - name: MINIO_SECRET_KEY
    value: "minio123"
    ---
    apiVersion: v1
    kind: Service
    spec:
    type: ClusterIP
    ports:
    - port: 9000
    targetPort: 9000
    protocol: TCP

    这里的env实际上指定了minio的key/secret,用这个可以访问minio的GUI。

    下面Service的port可以根据自己的实际需要改成其他的端口号,比如31605。service是ClusterIP,可以根据需要改成NodePort。

    另外,这里的volume是emptydir形式,作为学习问题不大,如果需要用其他形式的存储,可以参考例如minio NFS backend。

    最后,登陆minio的GUI并创建一个bucket,比如test1
    ,为velero的安装做准备。

  • Velero 1.4.3安装

    1. 下载velero v1.4.3的安装包,解压。

    2. 准备好credential file:

        [root~ ]# cat credentials-velero
      [default]
      aws_access_key_id=minio
      aws_secret_access_key=minio123

    3. 在velero的下载目录执行:

        velero install --provider aws --bucket test1 --secret-file credentials-velero --use-volume-snapshots=true --use-restic --backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://ip:port,publicUrl=http://ip:port --plugins=velero/velero-plugin-for-aws:v1.1.0,velero/velero-plugin-for-csi:v0.1.1 --namespace=velero --snapshot-location-config region=default --features=EnableCSI

      上面命令的ip就是minio安装所在的机器ip,port是minio开放的port。

      执行完后,可以用kubectl logs -n velero velero-xxxx-xxx
      命令来查看velero的log来观察velero是否安装成功:

        time="2021-04-22T07:10:21Z" level=info msg="setting log-level to INFO" logSource="pkg/cmd/server/server.go:177"
      time="2021-04-22T07:10:21Z" level=info msg="Starting Velero server v1.4.3 (4fc1c700282d6ece5b3ffc03cf296c435ccc903e)" logSource="pkg/cmd/server/server.go:179"
      time="2021-04-22T07:10:21Z" level=info msg="1 feature flags enabled [EnableCSI]" logSource="pkg/cmd/server/server.go:181"

  • Wordpress + MySQL

    最后用Ceph的storageclass来为MySQL和Wordpress创建PVC,具体可以参考rook wordpress example和rook mysql example。安装完Wordpress后,可以发布一篇文章,作为后面恢复的验证。

    <img src="https://oss-emcsprod-public.modb.pro/wechatSpider/modb_20211111_0f67d99a-4302-11ec-8dc2-fa163eb4f6be.png" style="zoom:50%;" />

    同时可以进入MySQL的Pod查看wordpress
    的database,表wp_posts

      |  4 |           1 | 2021-04-20 13:47:35 | 2021-04-20 05:47:35 |    | bakcup1    |     | publish     |
  • 备份

    1. 执行备份命令

    [root~ ]# velero backup create wp-backup --include-namespaces wordpress
    Backup request "wp-backup" submitted successfully.
    Run `velero backup describe wp-backup` or `velero backup logs wp-backup` for more details.

    1. 查看备份状态

    [root~ ]# kubectl get backups.velero.io -n v elero
    NAME AGE
    wp-backup 32s
    [root~ ]# kubectl get backups.velero.io -n velero wp-backup -o yaml
    ...
    ...
    spec:
    hooks: {}
    includedNamespaces:

    - wordpress
    storageLocation: default
    ttl: 720h0m0s
    volumeSnapshotLocations:
    - default
    status:
    expiration: "2021-05-22T12:15:11Z"
    formatVersion: 1.1.0
    phase: InProgress
    progress:
    totalItems: 19
    startTimestamp: "2021-04-22T12:15:11Z"
    version: 1

    1. 查看volumesnapshot状态

    [root~ ]# kubectl get volumesnapshot -n wordpress
    NAME AGE
    velero-mysql-pv-claim-kkxwx 3m2s
    velero-wp-pv-claim-587dp 3m47s

    [root~ ]# k get volumesnapshotcontent
    NAME AGE

    snapcontent-549679d6-a5cf-41fb-aaa4-fc11fe09e9ab 2m52s
    snapcontent-984839a0-55a8-41de-8bd6-5d0bfaba6e2c 3m37s

    这里如果去查看snapcontent-549679d6-a5cf-41fb-aaa4-fc11fe09e9ab
    的信息,可以看到:

    Spec:
    Deletion Policy: Retain
    Driver: rook-ceph.rbd.csi.ceph.com
    Source:
    Volume Handle: 0001-0009-rook-ceph-0000000000000002-05b2f2d6-a19b-11eb-baf1-7a576c7e3674
    Volume Snapshot Class Name: csi-rbdplugin-snapclass
    Volume Snapshot Ref:
    API Version: snapshot.storage.k8s.io/v1beta1
    Kind: VolumeSnapshot
    Name: velero-mysql-pv-claim-kkxwx
    Namespace: wordpress
    Resource Version: 43496419
    UID: 549679d6-a5cf-41fb-aaa4-fc11fe09e9ab
    Status:
    Creation Time: 1619093815974957075
    Ready To Use: true
    Restore Size: 10737418240
    Snapshot Handle: 0001-0009-rook-ceph-0000000000000002-a0a1af05-a364-11eb-baf1-7a576c7e3674
    Events: <none>

    其中,Deletion Policy
    被我们之前设置成了Retain
    ,这样的话,即使刚创建的Volumesnapshot
    的CR被删掉,VolumesnapShotContent
    也不会被删掉,VolumeSnapshotContent
    指向的Ceph的快照也不会被删掉。

    1. 查看RBD快照

    查看并进入Ceph的tools Pod:

    rook-ceph-tools-5949d6759-2kwzm                    1/1     Running     2          33d

    [root]# kubectl exec -it -n rook-ceph rook-ceph-tools-5949d6759-2kwzm -- bash
    [root@rook-ceph-tools-5949d6759-2kwzm /]#

    用上面VolumesnapShotContent
    Snapshot Handle
    的后半部分a0a1af05-a364-11eb-baf1-7a576c7e3674
    来找到rbd的快照:

    [root@rook-ceph-tools-5949d6759-2kwzm /]# rbd ls replicapool | grep a0a1af05-a364-11eb-baf1-7a576c7e3674
    csi-snap-a0a1af05-a364-11eb-baf1-7a576c7e3674

    上面replicapool
    其实是安装Ceph时的默认存储池的名字,然后可以用rbd info
    命令去看这个快照的属性:

    [root@rook-ceph-tools-5949d6759-2kwzm /]# rbd info replicapool/csi-snap-a0a1af05-a364-11eb-baf1-7a576c7e3674
    rbd image 'csi-snap-a0a1af05-a364-11eb-baf1-7a576c7e3674':
    size 10 GiB in 2560 objects
    order 22 (4 MiB objects)
    snapshot_count: 1
    id: 455cd100fcb2d
    block_name_prefix: rbd_data.455cd100fcb2d
    format: 2
    features: layering, deep-flatten, operations
    op_features: clone-child
    flags:
    create_timestamp: Thu Apr 22 12:16:55 2021
    access_timestamp: Fri Apr 23 06:36:18 2021
    modify_timestamp: Thu Apr 22 12:16:55 2021
    parent: replicapool/csi-vol-05b2f2d6-a19b-11eb-baf1-7a576c7e3674@7ad163d8-0c3c-49ef-a58e-43b95423beee
    overlap: 10 GiB

    可以看到这个rbd image的属性其实跟前面讲Ceph CSI驱动创建快照时候的参数是一致的,format: 2
    layering, deep-flatten
    应该表示了这个image是一个rbd克隆。

    1. 备份完成

    status:
    completionTimestamp: "2021-04-22T12:16:58Z"
    expiration: "2021-05-22T12:15:11Z"
    formatVersion: 1.1.0
    phase: Completed
    progress:
    itemsBackedUp: 26
    totalItems: 26
    startTimestamp: "2021-04-22T12:15:11Z"
    version: 1

    这里还是对前面backups.velero.io
    的查看,这里状态已经变成了Completed
    ,表示成功完成。

    不同场景的恢复

    • 删除PVC

      删除PVC之前,可以新写一篇文章,用来表示当前应用的最新版本的数据,然后再执行PVC的删除:

        [root~ ]# kubectl delete pvc -n wordpress mysql-pv-claim
      persistentvolumeclaim "mysql-pv-claim" deleted
      [root~ ]# kubectl delete pvc -n wordpress wp-pv-claim
      persistentvolumeclaim "wp-pv-claim" deleted
      [root~ ]#

      恢复:

        [root~ ]# velero create restore --from-backup wp-backup
      Restore request "wp-backup-20210422204956" submitted successfully.
      Run `velero restore describe wp-backup-20210422204956` or `velero restore logs wp-backup-20210422204956` for more details.

      这时候如果去看restores.velero.io
      的状态,会发现很快就恢复完成了:

        [root~ ]# kubectl describe restores.velero.io -n velero wp-backup-20210422204956

      ...

      Spec:
      Backup Name: wp-backup
      Excluded Resources:
      nodes
      events
      events.events.k8s.io
      backups.velero.io
      restores.velero.io
      resticrepositories.velero.io
      Included Namespaces:
      *
      Status:
      Phase: Completed
      Warnings: 6
      Events: <none>

      查看PV,PVC:

        [root~ ]# kubectl get pv
      NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
      pvc-179efdd1-4d91-4b4f-a2dd-2ecfccedfb28 10Gi RWO Delete Bound wordpress/wp-pv-claim rook-ceph-block 76s
      pvc-a444c477-d2f9-481e-8db6-85b9d893ecad 10Gi RWO Delete Released wordpress/mysql-pv-claim rook-ceph-block 2d7h
      pvc-ad1c99d3-1f7f-486f-9924-0c997ad503cb 10Gi RWO Delete Bound wordpress/mysql-pv-claim rook-ceph-block 76s
      pvc-bc45621b-50a3-4056-8f1b-43038b6e0174 10Gi RWO Delete Released wordpress/wp-pv-claim rook-ceph-block 2d7h
      [root~ ]# kubectl get pvc -n wordpress
      NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
      mysql-pv-claim Bound pvc-ad1c99d3-1f7f-486f-9924-0c997ad503cb 10Gi RWO rook-ceph-block 79s
      wp-pv-claim Bound pvc-179efdd1-4d91-4b4f-a2dd-2ecfccedfb28 10Gi RWO rook-ceph-block 79s

      这里可以看到前面删除的两个PV处于Released
      的状态,恢复回来的PV是另外的名字。

      恢复完成之后,需要注意一点,要把MySQL的Pod删掉来造成Pod重启一下(deployment会自动创建新的Pod)。这个重启十分重要,会让Pod把PV重新挂载一遍,否则的话,Pod里面的数据还是最新的,并不是想要恢复的那个版本。

      再去看Wordpress的文章,没有问题,这里读者可以自行验证,这里就不展示了。

    • 损坏PV的数据

      这里可以直接把Wordpress里面的文章删掉,或者修改当前文章,然后再尝试恢复。这里跟上面场景主要的区别在于数据是应用随着时间正常更新了(比如修改或新增文章),还是恶意被破坏了(比如删掉文章)。但是从步骤来说,是一样的,记得恢复完要把MySQL的Pod重启一下。

    • 删除namespace

        [root~ ]# kubectl delete ns wordpress
      namespace "wordpress" deleted
      [root~ ]#

      再执行恢复,也很快成功了,再去看MySQL的数据:

        |  4 |           1 | 2021-04-20 13:47:35 | 2021-04-20 05:47:35 |    | bakcup1    |     | publish     | open           | open        |       | bakcup1       |         |        | 2021-04-20 13:47:35 | 2021-04-20 05:47:35 |      |           0 | https://foo.bar.com:30165/?p=4       |          0 | post      |

      没有问题,数据恢复成功。

    总结

    以上介绍了怎么用velero通过Ceph的快照方式来备份恢复有状态的应用,可以看到,不论是删掉PV,删掉命名空间,还是损坏原始PV的数据,都可以通过velero把原始数据恢复回来。但是,这里需要注意的是,velero备份的只是VolumeSnapshot和VolumeSnapshotContent的CR,并没有把PV的数据进行导出,一旦Ceph集群出现问题,比如集群遇到错误起不来,那备份到对象存储的资源是没法恢复丢失的数据的。






    更多velero相关技术讨论,敬请关注velero中文社区官方网站:

    https://velero.cn/

    文章转载自Velero中文社区,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

    评论