Geschmeidige Datenmigration zwischen MinIO-Services mithilfe des MinIO-Clients

In der Kubernetes-Landschaft unseres Kunden Contargo kommen mehrere Object-Storage-Services in Form von MinIO-Clustern zum Einsatz. Diese dienen u.a. als Storage für Datenbankbackups, aber auch für Assets. Aufgrund eines größeren Landschaftsumbaus müssen diese Services migriert werden. Das Vorgehen wiederholt sich, sodass sich eine Teilautomatisierung lohnt.

Synchronisation der Daten

Im Laufe der Migration erfolgt eine Umkonfiguration der Domain, die auf das MinIO-Cluster zeigt. Da diese Umkonfiguration durch DNS-Caches nicht garantiert zeitgleich bei allen Clients ankommt können geschriebene Daten sowohl im alten als auch im neuen Cluster landen. Eine dauerhafte Synchronisation hilft, die Daten in beiden Clustern synchron zu halten, bis bei allen Clients die DNS-Umstellung angekommen ist.

MinIO-Client als Helfer

MinIO-Client (kurz mc) bietet das Kommando mirror an, welches im Stil von rsync Daten von beispielsweise einem MinIO-Cluster in ein anderes synchronisieren kann.

Eine dauerhafte Synchronisation der Daten ermöglicht die mc mirror-Option --watch.

Kubernetes als Umgebung

Kubernetes bietet die Möglichkeit, sehr einfach einen Pod mit MinIO-Client zu deployen, der das Synchronisieren übernehmen kann. Ein Kubernetes-Deployment bietet sich an, um sicherzugehen, dass der minio-client-Pod bei Terminierung wieder erstellt wird.

Die betroffenen MinIO-Cluster werden in Kubernetes betrieben. Das Deployment wird im Namespace des alten MinIO-Clusters konfiguriert, also der Quelle. Das ermöglicht bereits den Zugriff auf die in einem Secret abgelegten root-Zugangsdaten, die für die globale Synchronisation gebraucht werden.

Einfache Darstellung zweier Kubernetes-Cluster und jeweils einem MinIO-Service pro Cluster. Außerdem ein MinIO-Client und seine Verbindungen zu den jeweiligen Services.

Kubernetes-Konfigurationen für die Migration der Daten

Das minio-client-Image von Bitnami bietet die passende Umgebung für die Synchronisation und ist die Grundlage für das Deployment.

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: minio-client
[...]
    spec:
      containers:
      - name: minio-client
        image: bitnami/minio-client

Der Entrypoints des Images muss überschrieben werden, da das Image darauf ausgelegt ist genau ein mc-Kommando auszuführen.

        entrypoint:
        command:
        - /bin/bash
        - -c

Um Aliasse für das Quell- und das Ziel-Cluster zu hinterlegen und danach die Synchronisation zu starten müssen allerdings mehrere Kommandos hintereinander ausgeführt werden.

Die Zugangsdaten der MinIO-Services werden vom Deployment als Umgebungsvariable erwartet. Die Werte können sich aus Secrets oder ConfigMaps speisen.

        env:
        - name: SOURCE_SERVER
          valueFrom:
            configMapKeyRef:
              name: minio-clusters
              key: SOURCE_SERVER
        - name: SOURCE_ROOT_USER
          valueFrom:
            secretKeyRef:
              name: minio-source-admin
              key: root-user

Der Quellservice ist auf Basis des Bitnami MinIO-Helm-Charts deployed und die root-Zugangsdaten bereits in einem Secret hinterlegt. Die root-Zugangsdaten des Zielservices werden ebenfalls in einem Secret konfiguriert.

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: minio-clusters
data:
  SOURCE_ALIAS: # Add the alias here, like `minio-cluster-old`
  SOURCE_SERVER: # Add the server here, make sure to use an appropriate schema like https://minio.cluster.cloud:9000
  DESTINATION_ALIAS: # Add the alias here, like `minio-cluster-new`
  DESTINATION_SERVER: # Add the server here, make sure to use an appropriate schema like https://minio.cluster.cloud:9000

Nun kann mit mc mirror --fake geprüft werden, ob die Verbindung steht und Daten übertragen werden würden.

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: minio-client
[...]
        args:
        - |
          mc alias set $SOURCE_ALIAS $SOURCE_SERVER $SOURCE_ROOT_USER $SOURCE_ROOT_PASSWORD
          mc alias set $DESTINATION_ALIAS $DESTINATION_SERVER $DESTINATION_ROOT_USER $DESTINATION_ROOT_PASSWORD
          mc mirror --fake $SOURCE_ALIAS $DESTINATION_ALIAS

Kommt die Verbindung erfolgreich zustande, kann --fake durch --watch ersetzt werden. Nachdem die Konfiguration deployed wurde, sollte die eigentliche Synchronisation starten. Im Log des minio-client-Pods sollten Logs erscheinen, die den folgenden ähneln:

minio-client Remove `new-cluster/backups/tDuPcC6GTACxtpZVBzJZFw/1/index-1207`.                                                                             
minio-client `old-cluster/backups/tDuPcC6GTACxtpZVBzJZFw/1/pending-index-1208` -> `new-cluster/backups/tDuPcC6GTACxtpZVBzJZFw/1/pending-index-1208`

Contargo/k8s-mc-mirror

Alle angesprochenen Konfigurationen sind auf GitHub im Projekt Contargo/k8s-mc-mirror verfügbar und dokumentiert. MinIO-Client unterstützt übrigens nicht nur MinIO-Services, sondern ist auch zu Amazon S3 Cloud-Storages kompatibel, sodass der Anwendungsfall dahingehend erweitert werden kann.