Mit Kubernetes lassen sich Container auf effektive Weise orchestrieren. Sei es Lastverteilung, Hochverfügbarkeit, automatische Skalierung von Pods oder automatisches Neustarten bei definierten Ereignissen, es lassen sich sehr viele Szenarien damit abdecken. Die Verwaltung von Kubernetes kann durchaus eine Herausforderung sein. Daher macht es schon Sinn, eine Strategie zu haben, bevor man damit loslegt. Ein wichtiger Punkt ist für einen hohen Grad an Standardisierung, so viel wie möglich zu automatisieren. Dies hat einige Vorteile wie z.B. Zeitersparnis, geringere Fehleranfälligkeit, einheitliches Vorgehen oder leichterer Wissenstransfer.
Eine sehr wichtige Komponente eines Kubernetes Clusters ist etcd. In dieser Open Source basierten “Key Value Datenbank” werden sowohl Konfigurationen als auch Metadaten des Kubernetes Clusters gespeichert. etcd ist entscheidend für die Konsistenz und Verfügbarkeit der Cluster-Daten.
Damit im Problemfall der Stressfaktor nicht zu hoch wird, sollte etcd regelmäßig gesichert werden. Dafür gibt es eigene Werkzeuge, die das übernehmen. Auch wenn ein manuelles Backup natürlich besser ist als gar keines, sollte der Vorgang dennoch automatisiert werden. Dadurch wird die identische Ausführung gewährleistet und durch geplante Aufgaben lassen sich die für den Betrieb optimalen Zeiten dafür definieren.
Wenn schon ein Kubernetes Cluster initial durch Ansible aufgesetzt wird, lässt sich auch das Backup für etcd damit sehr einfach umsetzen.
Im Ansible Inventory können als Beispiel zwei Gruppen definiert werden. Einmal für die Kubernetes Control Planes und einmal für die Kubernetes Worker Nodes. Gibt es zum Beispiel mehrere Control Planes, arbeitet Ansible alle Mitglieder der Gruppe ab.
kubernetes_cplane:
hosts:
k8scplane.foo.bar:
kubernetes_nodes:
hosts:
k8snode1.foo.bar:
k8snode2.foo.bar:
Über die “group_vars” lassen sich z.B. für die Gruppe “kubernetes_cplane” weitere Variablen definieren, die somit nur gültig für Hosts sind, die Mitglied in der entsprechenden Gruppe sind.
etcd_backup_target: /opt/backup/etcd
etcd_backups_keep: 5
etcdctl_api: 3
etcd_advertise_client_url: https://{{ apiserver_advertise_address }}:2379
etcd_cert_file: /etc/kubernetes/pki/etcd/server.crt
etcd_key_file: /etc/kubernetes/pki/etcd/server.key
etcd_trusted_ca_file: /etc/kubernetes/pki/etcd/ca.crt
Dadurch wird festgelegt, wie das Backup zu realisieren ist. Wohin wird das Backup geschrieben, wie viele Backups sollen vorgehalten werden und woher kommen die Zertifikatsinformationen, um auf die Daten zugreifen zu können.
Da das Ansible Playbook zum Sichern der etcd Datenbank nur auf Control Planes ausgeführt werden muss, kann in der Playbook Definition bei “hosts” direkt die richtige Inventory Gruppe (kubernetes_cplane) angegeben werden. Damit ist sichergestellt, dass das Playbook nicht auf den Worker Nodes oder anderen Systemen ausgeführt wird, auf dem es gar nicht erforderlich ist.
Das im Folgende dargestellte Ansible Playbook sorgt nun für den kompletten Ablauf. Kommentare in den eigenen Tasks sollen die Abläufe genauer erklären.
---
# Definition der Hosts, auf denen das Playbook ausgeführt werden soll
- hosts: kubernetes_cplane
gather_facts: true
become: true
tasks:
# Paket Repository aktualisieren
- name: Update package index
ansible.builtin.apt:
update_cache: yes
# Kubernetes CLI installieren, um das Backup ausführen zu können
- name: Install of kubernetes etcd-client
ansible.builtin.apt:
name: etcd-client
state: present
# Zielverzeichnis für Backup erstellen
# und die Berechtigungen auf den eigenen Kubernetes User setzen
- name: Create etcd backup target directory
ansible.builtin.file:
path: "{{ etcd_backup_target }}"
state: directory
owner: "{{ k8s_user }}"
group: "{{ k8s_user }}"
mode: '0755'
# Ausführen des etcd Backups mit 'etcdctl'
# Das Ergebnis der Ausgabe wird in die Variable 'etcd_snapshot' geschrieben
# und wird im Abschluss ausgewertet
- name: Create etcd-Snapshot with etcdctl
ansible.builtin.shell: |
ETCDCTL_API={{ etcdctl_api }} etcdctl \
--endpoints={{ etcd_advertise_client_url }} \
--cacert={{ etcd_trusted_ca_file }} \
--cert={{ etcd_cert_file }} \
--key={{ etcd_key_file }} \
snapshot save {{ etcd_backup_target }}/etcd_{{ ansible_date_time.date }}.db
register: etcd_snapshot
# Ausgabe des zuvor Ausgeführten Befehls, um im Log zu sehen, was passiert ist
- name: Print snapshot results
ansible.builtin.debug:
var: etcd_snapshot.stdout_lines
# Ownership des Backups auf den Kubernetes User ändern
- name: Change file ownership to user {{ k8s_user }}
ansible.builtin.file:
path: "{{ etcd_backup_target }}/etcd_{{ ansible_date_time.date }}.db"
owner: "{{ k8s_user }}"
group: "{{ k8s_user }}"
mode: '0600'
# Erzeugtes Backup verifizieren mit 'etcdctl'
# Ergebnis wird in die Variable 'etcd_snapshot_verify' geschrieben
- name: Verify etcd snapshot
ansible.builtin.shell: |
ETCDCTL_API={{ etcdctl_api }} etcdctl --write-out=table snapshot status {{ etcd_backup_target }}/etcd_{{ ansible_date_time.date }}.db
register: etcd_snapshot_verify
# Ausgabe der Prüfung, um das Ergebnis in den Logs sehen zu können
- name: Print verify snapshot results
ansible.builtin.debug:
var: etcd_snapshot_verify.stdout_lines
# Erzeugte Backups werden sortiert und nur die definierte Anzahl an Backups wird behalten
- name: Find all existing backups
ansible.builtin.find:
paths: "{{ etcd_backup_target }}"
patterns: "etcd_*.db"
register: etcd_backup_files
- name: Sort files by modification time
ansible.builtin.set_fact:
sorted_files: "{{ etcd_backup_files.files|sort(attribute='mtime')|reverse }}"
- name: Delete files except the last {{ etcd_backups_keep }}
ansible.builtin.file:
path: "{{ item.path }}"
state: absent
loop: "{{ sorted_files[etcd_backups_keep:] }}"
...
Das Ansible Playbook kann dann manuell ausgeführt werden.
ansible-playbook -i ./inventory/hosts.yml playbooks/playbook_kubernetes_etcd_backup.yml
Da das Playbook die Ausgaben des Backups und der Prüfung des Backups ausgeben soll, lässt sich das in den Logs auch entsprechend auswerten.


Es ist natürlich nicht zwingend erforderlich, dass Playbook direkt auf den Kubernetes Control Planes auszuführen. Wird es auf einem anderen Host, außerhalb des Clusters ausgeführt, ist nur wichtig, dass der Ansible Benutzer auch Zugriff auf die Kubernetes Konfiguration hat.
Das Playbook lässt sich jetzt auch planen, damit es regelmäßig ausgeführt wird. Dies kann per systemd Timer, Cronjob oder durch CI/CD Tools wie Semaphore automatisch gestartet werden.
Wichtig ist natürlich, regelmäßig die Backups zu prüfen und auch gelegentlich den Restore in Test Clustern durchzuspielen um die volle Funktionalität zu gewährleisten.