Wie wir vielleicht schon mitgekriegt haben, liegen die meisten Resourcen in Kubernetes in YAML-Files vor, Damit wurden zumindest die meisten Sachen erzeugt - sei es als HELM Chart oder einfaches Deployment-File - local oder uebers Netz, einerlei. Schmutzig, klein, genial ist Kube-Backup, ein handliches Backup-Tool fuer Kubernetes. Voraussetzungen sei wieder unser laufender Minikube, es funktioniert aber mit jedem anderen Kubernetes. Zielbild ist es, unsere Cluster-Konfiguration auf Github zu sichern. Immer und immer wieder. Wie machen wir das? Mit einem Cronjob! Also automatisch. Als erstes erstellen wir ein SSH-Schluesselpaar auf unserem, Minikuberechner:
ssh-keygen -f ./id_rsa
ssh-keyscan github.com > known_hosts
Dann erstellen wir ein neues Github-Repository. Gerne auch private, denn das ist neuerdings erlaubt. Unter Deploykeys fuegen wir den frisch erstellten SSH-Public-Key unseres Minikuberechners id_rsa.pub hinzu.
Vom SSH-Private-Key und die known_hosts erstellen wir eine Secret im Kubernetes:
kubectl create secret generic kube-backup-ssh -n kube-system --from-file=id_rsa --from-file=known_hosts
Wenn wir schon dabei sind, erstellen wir noch mit gpg --generate-key
den GPG-Key und auch daraus ein Secret:
gpg --export-secret-key -a root@minikube > gpg-private.key
kubectl create secret generic kube-backup-gpg -n default --from-file=gpg-private.key
Das Git-Repo mit unserer Kubernetes ist mit git-crypt entsprechend zu preparieren:
cd git/minikube
git-crypt init
cat <EOF> .gitattributes
*.secret.yaml filter=git-crypt diff=git-crypt
.gitattributes !filter !diff
EOF
git-crypt add-gpg-user eumel@eumel.gnuu.de
Den GPG-Public-Key vom Minikube-Rechner muss ich erstmal von seinem GPG-Schluesselbund exportieren:
gpg --armor --output minikube.asc --export root@minikube
und in meinem persoenlichen GPG-Schluesselbund importieren:
gpg --import minikube.asc
Um den Schluessel wie oben mit git-crypt add-gpg-user root@minikube
hinzufuegen zu koennen, muss ich diesem noch vertrauen:
gpg --edit-key root@minikube
>trust
5
y
Zurueck zum Kubernetes-Cluster. Dort gibts erstmal ein ClusterRoleBinding zu deployen:
rbac.yaml
kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: kube-backup-reader rules: - apiGroups: - '*' resources: - '*' verbs: ["get", "list"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: kube-backup namespace: default subjects: - kind: ServiceAccount name: kube-backup namespace: kube-system roleRef: kind: ClusterRole name: kube-backup-reader apiGroup: rbac.authorization.k8s.io
kubectl apply -f rbac.yaml
Nun das Herzstueck, der CronJob:
cronjob-ssh.yaml
apiVersion: v1 kind: ServiceAccount metadata: name: kube-backup namespace: kube-system --- apiVersion: batch/v1beta1 kind: CronJob metadata: name: kube-state-backup namespace: kube-system labels: app: kube-backup spec: schedule: "*/5 * * * *" concurrencyPolicy: Replace successfulJobsHistoryLimit: 3 failedJobsHistoryLimit: 3 jobTemplate: spec: template: metadata: labels: app: kube-backup name: kube-backup spec: containers: # - image: quay.io/plange/kube-backup:1.12.0-1 - image: eumel8/kube-backup:latest imagePullPolicy: Always name: backup resources: {} securityContext: runAsUser: 1000 env: - name: GIT_REPO value: "git@github.com:eumel8/minikube.git" - name: GITCRYPT_ENABLE value: "true" - name: RESOURCETYPES value: "ingress deployment configmap secret pvc svc rc ds thirdpartyresource networkpolicy statefulset storageclass cronjob" volumeMounts: - mountPath: /backup/ name: cache - mountPath: /backup/.ssh name: sshkey - mountPath: /secrets name: gpgkey dnsPolicy: ClusterFirst terminationGracePeriodSeconds: 30 serviceAccountName: kube-backup volumes: - name: sshkey secret: defaultMode: 420 secretName: kube-backup-ssh - name: gpgkey secret: defaultMode: 420 secretName: kube-backup-gpg - name: cache emptyDir: {} restartPolicy: OnFailure
Ein kurzer Blick auf das File, bevor wir es deployen. Ich habe das Repo geforked und ein eigenes Image gebaut und auf Dockerhub gepusht. Das geht mit ein paar Klicks, wenn man einen Gihub- und einen Dockerhub-Account hat. Im Dockerfile kann man schauen, was im Image alles drin ist. Ich habe Alpine und git-crypt aktualisiert. Auch eine neuere Version von kubectl ist drin. Ob es das richtige File aus dem Internet ist, wird mit einer sha256 Pruefsumme ueberprueft. So kann uns niemand Schadsoftware unterschieben.
Das entrypoint.sh ist die Arbeitslogik. Dort habe ich mal ein paar Debug-Marker gesetzt, als es auf den ersten Versuch nicht funktionierte. Sollte aber wieder alles wie im Original sein und veranschaulichen, wie so ein Dockerfile bzw. Docker-Image fuer Kubernetes funktioniert.
Jetzt aber los:
kubectl apply -f cronjob-ssh.yaml
Wenn alles klappt, sollte in unserem Github-Repository mit der Kubernetes-Config etwas passieren.
commit d685ad67d808842258622a6f07326b5c0c3f2a56 Author: kube-backup <kube-backup@example.com> Date: Fri Oct 4 18:23:32 2019 +0000 Automatic backup at Fri Oct 4 18:23:32 UTC 2019
Auf der Github-Webseite sollten wir nur Datensalat bei den Secrets sehen (bin). Im Klartext (also base64 Inhalt) sehen wir die Dateien auf unserem eigenen Rechner und auf dem Minikube-Rechner wegen git-crypt.
Im Cluster sehen wir sowas wie
# kubectl get jobs -n kube-system
NAME COMPLETIONS DURATION AGE
kube-state-backup-1570216080 1/1 29s 3m3s
kube-state-backup-1570216140 1/1 29s 2m3s
kube-state-backup-1570216200 1/1 29s 63s
kube-state-backup-1570216260 0/1 3s 3s
Sicherlich keine perfekte Loesung, aber eine automatisierte. Ueber die Variable RESOURCETYPES kann ich noch steuern, welche Resourcetypen ich backupen moechte. Eine kleine Auswahl ist schon dabei.
Credits gehen an https://github.com/pieterlange | https://www.fullstaq.com | https://twitter.com/fullstaq |