Neuigkeiten von trion.
Immer gut informiert.

etcd Schreiblast reduzieren und Performance steigern

etcd

Kubernetes speichert sämtliche Konfigurationsdaten des Clusters in einer Datenbank, typischerweise etcd.

etcd ist ein verteilter Key-Value-Store, durch mehrere Instanzen kann die Verfügbarkeit und Datensicherheit gewährleistet werden. Damit keine Daten verloren gehen, signalisiert etcd dem Betriebssystem per fsync()-Aufruf, dass ein sofortiges Schreiben auf Festplatte erfolgen soll.

Doch etcd kann auch zum Flaschenhals werden: Wenn keine Schreiboperationen möglich sind, ist auch die Clusteradministration blockiert. Ein weiterer Aspekt ist, dass selbst in einem relativ stabilen Cluster kontinuierliche Aktualisierungen diverser Kubernetes-Objekte erfolgen, wie z.B. zur Leader-Election.
Das führt zu recht hoher I/O-Last und kann bei günstigen SSDs/NVMe Speichern zu schneller Alterung führen.

Kommt vielleicht sogar eine SD-Karte, z.B. in einem Single-Board-Computer wie einem RasperryPI oder ODROID zum Einsatz, kann die permanente Schreiblast zu einem vorzeitigen Ableben des Speichermediums führen.

Für beide Aspekte gibt es einen relativ einfachen Tuning-Mechanismus:
etcd erlaubt per Konfiguration den fsync()-Aufruf zu deaktivieren. Das resultiert darin, dass das Betriebssystem nun selbst entscheiden kann, wann eine Synchronisierung der zu schreibenden Daten stattfindet.

Linux hat typischerweise eine Zeitschwelle von fünf Minuten konfiguriert, bis Schreiboperationen spätestens bis zum physischen Speicher weitergereicht werden. Damit können viele kleine Schreiboperationen sinnvoll zusammengefasst werden, und damit die Gesamtanzahl gesenkt werden.
Auch "überholen" sich manche Operationen, wie z.B. bei der Leader-Election, so dass statt alle 5-10 Sekunden lediglich alle fünf Minuten eine Schreiboperation durchgeführt wird. Das senkt entsprechend die Abnutzung des Speichermediums.
Und speziell in größeren Clustern kann die so gesparte Schreiblast dazu beitragen, dass der Cluster besser skaliert.

Performance vs. Datensicherheit

Auf der anderen Seite droht Datenverlust: Kommt es zu einem Ausfall, können die gepufferten Daten nun nicht mehr geschrieben werden.
Das ist lediglich dann ein reales Problem, wenn etcd entweder nicht mit mehreren Nodes redundant betrieben wird oder aber wenn es zu einem Stromausfall kommt, der alle diese Nodes gleichzeitig erwischt.

Doch wie wichtig sind die Daten eigentlich?
Die meisten Daten in Kubernetes sind vergängliche Daten, wie z.B. die bereits ausgeführte Leader-Election oder Informationen zum Container-Zustand. Fallen alle Nodes aus, stimmt der Container-Zustand sowieso nicht mehr. Und auch dieser wird durch kubelet neu geschrieben, wenn sich Änderungen ergeben. Das selbe gilt für viele andere Objekte, die durch Controller verwaltet werden.

Und nicht zuletzt sollten alle Konfigurationen nicht ausschließlich im Cluster vorhanden sein. Stattdessen sollten die Konfigurationen z.B. in einer Versionskontrolle nachvollziehbar abgelegt werden, wenn nicht sowieso ein GitOps-Ansatz verwendet wird.

Insofern mag das Risiko von Datenverlust anders eingeordnet werden, als in einem manuell verwalteten Cluster. Speziell bei einem Single-Node-Cluster mit SD-Karte kann es sogar sehr ratsam sein, auf ein ganz anderes System zu wechseln als etcd, da mit Verlust der SD-Karte automatisch Datenverlust einhergeht. Dies wird z.B. mit kine möglich.

etcd Konfiguration

Wird der Kubernetes Cluster mit kubeadm verwaltet, so gibt es zwei Stellen, um etcd zu konfigurieren:

  • In /etc/kubernetes/manifests/etcd.yaml

  • In der ConfigMap kube-system/kubeadm-config

Ersteres wird sofort aktiv, kann jedoch bei zukünftigen Upgrades durch kubeadm überschrieben werden, da diese Datei lediglich das Ergebnis von kubeadm init bzw. kubeadm upgrade ist.
Damit eignet sich ersteres vor allem für temporäre Tests, die ConfigMap für dauerhafte Konfiguration.

Der zu setzende Schalter ist --unsafe-no-fsync=true.

Konfiguration in manifests/etcd.yaml
$ cat /etc/kubernetes/manifests/etcd.yaml
apiVersion: v1
kind: Pod
metadata:
...
  name: etcd
  namespace: kube-system
spec:
  containers:
  - command:
    - etcd
    - --unsafe-no-fsync=true
    - --cert-file=/etc/kubernetes/pki/etcd/server.crt
    - --client-cert-auth=true
...

Nachdem diese Änderung gespeichert ist, wird kubelet sofort einen neuen Pod für etcd erstellen und den alten beenden, da es sich um statische Manifeste handelt.

Die Änderung in der ConfigMap wird erst bei dem nächsten Durchlauf von kubeadm aktiv.

$ kubectl -n kube-system get cm kubeadm-config -o yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: kubeadm-config
  namespace: kube-system
...
data:
  ClusterConfiguration: |
    apiVersion: kubeadm.k8s.io/v1beta4
    kind: ClusterConfiguration
    apiServer:
...
    etcd:
      local:
        dataDir: /var/lib/etcd
        extraArgs:
          unsafe-no-fsync: "true"
    imageRepository: registry.k8s.io
    kubernetesVersion: v1.33.4
...

Die hier beschriebene Maßnahme sollte nicht leichtfertig ergriffen werden. Es handelt sich jedoch um ein Werkzeug, dass jedem Kubernetes Administrator vertraut sein sollte, um so bei der Architektur der eigenen Cluster informierte Entscheidungen treffen zu können.




Zu den Themen Kubernetes, Docker und Cloudarchitektur bieten wir sowohl Beratung, Entwicklungsunterstützung als auch passende Schulungen an:

Auch für Ihren individuellen Bedarf können wir Workshops und Schulungen anbieten. Sprechen Sie uns gerne an.

Feedback oder Fragen zu einem Artikel – per E-Mail an (info a-t trion.de) oder über unser Kontaktformular. Wir freuen uns auf eine Kontaktaufnahme!

Los geht's!

Bitte teilen Sie uns mit, wie wir Sie am besten erreichen können.