Blog

Tutorial: Persistent Volume Claims in Kubernetes als Snapshots sichern

OCT 7, 2019

In diesem Blog zeige ich euch, wie ihr Snapshots von Persistent Volumes in Kubernetes-Clustern erstellt und wiederherstellt – und dafür ausschließlich mit dem API-Server kommuniziert. Das kann sowohl für Backups als auch für die Skalierung zustandsbehafteter Anwendungen nützlich sein, die „Startdaten“ benötigen.

Henrik Hoegh

Henrik is a DevOps Consultant based in Aarhus. He specializes in Docker, Kubernetes and everything Atlassian. Away from the office Henrik designs loudspeakers and takes a keen interest in quantum physics and astrophotography.

Die Snapshot-Funktion wurde in Kubernetes v1.12 als Alpha eingeführt. Damit dies funktioniert, müsst ihr das Feature Gate VolumeSnapshotDataSource auf dem API-Server eures Kubernetes-Clusters aktivieren.

--feature-gates=VolumeSnapshotDataSource=true

Ich werde Rook verwenden, um meinen Storage bereitzustellen, da es Layered Filesystems und den CSI-Treiber unterstützt.

Ich gehe davon aus, dass in eurem Cluster bereits eine Anwendung läuft. In meinem Fall läuft Jira Software im Data-Center-Modus mit einem aktiven Node, der mit ASK bereitgestellt wurde.

Für die horizontale Skalierung benötige ich eine Kopie des Home-Ordners von Node0, bevor ich Node1 starten kann. Deshalb definieren wir zunächst einige Objekte in Kubernetes.

Erstellen der StorageClass

Wenn ihr eure StorageClass für Rook erstellt, müsst ihr imageFeatures hinzufügen und wie unten gezeigt auf layering setzen:

apiVersion: ceph.rook.io/v1kind: CephBlockPoolmetadata:  name: replicapool  namespace: rook-cephspec:  failureDomain: host  replicated:    size: 3---apiVersion: storage.k8s.io/v1kind: StorageClassmetadata:   name: rook-ceph-block# Change "rook-ceph" provisioner prefix to match the operator namespace if neededprovisioner: rook-ceph.rbd.csi.ceph.comparameters:    # clusterID is the namespace where the rook cluster is running    clusterID: rook-ceph    # Ceph pool into which the RBD image shall be created    pool: replicapool    # RBD image format. Defaults to "2".    imageFormat: "2"    # RBD image features. Available for imageFormat: "2". CSI RBD currently supports only `layering` feature.    imageFeatures: layering    # The secrets contain Ceph admin credentials.    csi.storage.k8s.io/provisioner-secret-name: rook-ceph-csi    csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph    csi.storage.k8s.io/node-stage-secret-name: rook-ceph-csi    csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph    # Specify the filesystem type of the volume. If not specified, csi-provisioner    # will set default as `ext4`.    csi.storage.k8s.io/fstype: xfs# Delete the rbd volume when a PVC is deletedreclaimPolicy: Delete

Wenn wir Jira mit ASK bereitstellen, verwenden wir einfach diese StorageClass, und Rook erstellt den Storage bei Bedarf.

Jetzt haben wir also eine PVC für den Home-Ordner und eine für das Data-Center-Volume.

Das Data-Center-Volume ist nicht Teil dieses Blogposts, da es sich dabei nicht um Block Storage, sondern um ein Shared Filesystem (Read Write Many) in Rook handelt.

Erstellen der VolumeSnapshotClass und eures ersten Snapshots

Jetzt definieren wir eine VolumeSnapshotClass, um unsere Snapshots zu verwalten.

apiVersion: snapshot.storage.k8s.io/v1alpha1kind: VolumeSnapshotClassmetadata:  name: csi-rbdplugin-snapclasssnapshotter: rook-ceph.rbd.csi.ceph.comparameters:  # Specify a string that identifies your cluster. Ceph CSI supports any  # unique string. When Ceph CSI is deployed by Rook use the Rook namespace,  # for example "rook-ceph".  clusterID: rook-ceph  csi.storage.k8s.io/snapshotter-secret-name: rook-ceph-csi  csi.storage.k8s.io/snapshotter-secret-namespace: rook-ceph

Anschließend können wir Snapshots der Quell-PVC erstellen, in diesem Fall jira-persistent-storage-jira-0.

apiVersion: snapshot.storage.k8s.io/v1alpha1kind: VolumeSnapshotmetadata:  name: rbd-pvc-snapshotspec:  snapshotClassName: csi-rbdplugin-snapclass  source:    name: jira-persistent-storage-jira-0    kind: PersistentVolumeClaim

Dadurch erhalten wir ein VolumeSnapshot-Objekt, wie hier zu sehen:

kubectl get volumesnapshots -n jira-productionNAME               AGErbd-pvc-snapshot   57m

Erstellen einer neuen PVC aus unserem Snapshot

Wenn wir nun eine neue PVC auf Basis dieses VolumeSnapshots erstellen möchten, definieren wir sie folgendermaßen:

apiVersion: v1kind: PersistentVolumeClaimmetadata:  name: jira-persistent-storage-jira-1spec:  storageClassName: rook-ceph-block  dataSource:    name: rbd-pvc-snapshot    kind: VolumeSnapshot    apiGroup: snapshot.storage.k8s.io  accessModes:    - ReadWriteOnce  resources:    requests:      storage: 5Gi

Jetzt haben wir eine zweite PVC namens jira-persistent-storage-jira-1, die auf der PVC jira-persistent-storage-jira-0 basiert und alle Daten von diesem Zeitpunkt enthält. Damit können wir unser Jira StatefulSet skalieren, und der neue Jira-Node1 verwendet diese PVC, die eine Kopie von Node0 ist.

NAME                             STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGEjira-datacenter-pvc              Bound    pvc-a286df18-f9a3-4c52-b0a0-377a193f04de   5Gi        RWX            atlassian-dc-cephfs   93mjira-persistent-storage-jira-0   Bound    pvc-b73b96d6-c3f7-4448-9f12-d9956efe2989   5Gi        RWO            rook-ceph-block       93mjira-persistent-storage-jira-1   Bound    pvc-1984c9de-d13e-435e-b59c-28731d8f30bc   5Gi        RWO            rook-ceph-block       60m

Überprüfung

Wir können dies überprüfen, indem wir nach dem Start in den Mountpoint innerhalb des Containers schauen. Der Grund für den abweichenden Zeitstempel von cluster.properties ist, dass unser Entrypoint-Skript daran Änderungen vornimmt, bevor Jira gestartet wird.

$ kubectl exec -ti jira-0 -n jira-production -- ls -l /var/atlassian/application-data/jira/total 12drwxrws---. 4 jira jira   46 Aug 22 13:43 caches-rw-rw-r--. 1 jira jira  633 Aug 22 13:42 cluster.properties-rw-rw----. 1 jira jira 1102 Aug 22 13:30 dbconfig.xmldrwxr-s---. 2 jira jira 4096 Aug 22 13:58 localqdrwxrws---. 2 jira jira  132 Aug 22 14:01 logdrwxrws---. 2 jira jira   76 Aug 22 13:32 monitordrwxrws---. 6 jira jira  100 Aug 22 13:31 pluginsdrwxrws---. 3 jira jira   26 Aug 22 13:24 tmp$ kubectl exec -ti jira-1 -n jira-production -- ls -l /var/atlassian/application-data/jira/total 12drwxrws---. 4 jira jira   46 Aug 22 13:43 caches-rw-rw-r--. 1 jira jira  633 Aug 22 13:57 cluster.properties-rw-rw----. 1 jira jira 1102 Aug 22 13:30 dbconfig.xmldrwxr-s---. 2 jira jira 4096 Aug 22 13:58 localqdrwxrws---. 2 jira jira  100 Aug 22 13:32 logdrwxrws---. 2 jira jira   76 Aug 22 13:32 monitordrwxrws---. 6 jira jira  100 Aug 22 13:31 pluginsdrwxrws---. 3 jira jira   26 Aug 22 13:24 tmp

Wir sehen außerdem, dass wir jetzt ein VolumeSnapshotContent-Objekt in unserem Cluster haben.

$ kubectl get VolumeSnapshotContentNAME                                               AGEsnapcontent-05166c28-cdf9-4504-89c8-29c67ee23c11   73m$ kubectl describe VolumeSnapshotContent snapcontent-05166c28-cdf9-4504-89c8-29c67ee23c11Name:         snapcontent-05166c28-cdf9-4504-89c8-29c67ee23c11Namespace:Labels:       <none>Annotations:  <none>API Version:  snapshot.storage.k8s.io/v1alpha1Kind:         VolumeSnapshotContentMetadata:  Creation Timestamp:  2019-08-22T11:56:35Z  Finalizers:    snapshot.storage.kubernetes.io/volumesnapshotcontent-protection  Generation:        1  Resource Version:  176903  Self Link:         /apis/snapshot.storage.k8s.io/v1alpha1/volumesnapshotcontents/snapcontent-05166c28-cdf9-4504-89c8-29c67ee23c11  UID:               0a6afd6d-032d-4bf6-841d-a37146daf799Spec:  Csi Volume Snapshot Source:    Creation Time:    1566474995000000000    Driver:           rook-ceph.rbd.csi.ceph.com    Restore Size:     5368709120    Snapshot Handle:  0001-0009-rook-ceph-0000000000000003-e322e4c4-c4d3-11e9-afc8-0a580a2a0033  Deletion Policy:    Delete  Persistent Volume Ref:    API Version:        v1    Kind:               PersistentVolume    Name:               pvc-b73b96d6-c3f7-4448-9f12-d9956efe2989    Resource Version:   171532    UID:                b8eed866-4e73-4a6a-bf74-d8fba8c9a8f5  Snapshot Class Name:  csi-rbdplugin-snapclass  Volume Snapshot Ref:    API Version:       snapshot.storage.k8s.io/v1alpha1    Kind:              VolumeSnapshot    Name:              rbd-pvc-snapshot    Namespace:         jira-production    Resource Version:  176889    UID:               05166c28-cdf9-4504-89c8-29c67ee23c11Events:                <none>

Kubernetes die Arbeit für euch erledigen lassen

Wofür ist das alles gut, fragt ihr euch? Bisher mussten wir Kubernetes jedes Mal unterstützen, wenn wir unsere Jira-, Confluence- oder Bitbucket-Data-Center-Installation skalieren wollten, da wir die Daten kopieren mussten. Das ließ sich zwar mit Skripten automatisieren, aber jetzt kann Kubernetes diese Arbeit für uns übernehmen.

Diese Funktion befindet sich zwar noch in der Alpha-Phase und wird zum Zeitpunkt dieses Blogposts nur von Block Storage in Rook unterstützt. Die Entwickler haben uns jedoch mitgeteilt, dass sie auch an der Unterstützung für Shared Filesystem arbeiten.

Außerdem können wir jetzt Snapshots als Backups unserer laufenden Anwendungen erstellen. Bei Bedarf können wir dann einen Backup-Pod starten, der diese Backup-PVC einbindet und sie aus dem Cluster an einen Cold-Backup-Speicherort kopiert.

Nützliche Links

  • Cloud

Subscribe to our newsletter