Zum Inhalt springen

Dies ist die mehrseitige Druckansicht dieses Abschnitts. .

Zur normalen Ansicht dieser Seite zurückkehren.

etcd 3.7 Dokumentation

Offizielle etcd-3.7-Anleitungen für Entwicklung, Betrieb, Upgrades, APIs und interne Abläufe.

etcd ist ein verteilter Schlüssel-Wert-Speicher mit starker Konsistenz. Diese Anleitungen behandeln die Installation und den Betrieb von etcd, die Entwicklung von Anwendungen mit seinen APIs, den internen Aufbau, Leistungsmessungen sowie Upgrades und Downgrades von Clustern innerhalb der Versionsreihe 3.7.

Beginnen Sie mit dem Schnellstart für einen lokalen Ein-Mitglied-Cluster, der Installation für unterstützte Installationswege oder dem Betriebshandbuch für Produktionsumgebungen.

1 - Aufgaben

Dieser Abschnitt bietet aufgabenbezogene Anleitungen für Entwickler, die Anwendungen mit etcd erstellen, sowie für Betreiber, die etcd-Cluster bereitstellen, konfigurieren und warten.

1.1 - Aufgaben für Betreiber

Betriebsanleitungen zum Bereitstellen, Konfigurieren und Warten eines etcd-Clusters.

1.1.1 - Einen etcd-Democluster einrichten

Anleitung zum Einrichten eines etcd-Clusters
01_etcd_clustering_2016050601

Auf jedem etcd-Knoten die Clustermitglieder angeben:

TOKEN=token-01
CLUSTER_STATE=new
NAME_1=machine-1
NAME_2=machine-2
NAME_3=machine-3
HOST_1=10.240.0.17
HOST_2=10.240.0.18
HOST_3=10.240.0.19
CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380

Auf jedem Rechner Folgendes ausführen:

# For machine 1
THIS_NAME=${NAME_1}
THIS_IP=${HOST_1}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
	--initial-cluster ${CLUSTER} \
	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}

# For machine 2
THIS_NAME=${NAME_2}
THIS_IP=${HOST_2}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
	--initial-cluster ${CLUSTER} \
	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}

# For machine 3
THIS_NAME=${NAME_3}
THIS_IP=${HOST_3}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
	--initial-cluster ${CLUSTER} \
	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}

Oder unseren öffentlichen Discovery-Dienst verwenden:

curl https://discovery.etcd.io/new?size=3
https://discovery.etcd.io/a81b5818e67a6ea83e9d4daea5ecbc92

# grab this token
TOKEN=token-01
CLUSTER_STATE=new
NAME_1=machine-1
NAME_2=machine-2
NAME_3=machine-3
HOST_1=10.240.0.17
HOST_2=10.240.0.18
HOST_3=10.240.0.19
DISCOVERY=https://discovery.etcd.io/a81b5818e67a6ea83e9d4daea5ecbc92

THIS_NAME=${NAME_1}
THIS_IP=${HOST_1}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
	--discovery ${DISCOVERY} \
	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}

THIS_NAME=${NAME_2}
THIS_IP=${HOST_2}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
	--discovery ${DISCOVERY} \
	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}

THIS_NAME=${NAME_3}
THIS_IP=${HOST_3}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
	--discovery ${DISCOVERY} \
	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}

Damit ist etcd einsatzbereit! So lässt sich mit etcdctl eine Verbindung zu etcd herstellen:

export ETCDCTL_API=3
HOST_1=10.240.0.17
HOST_2=10.240.0.18
HOST_3=10.240.0.19
ENDPOINTS=$HOST_1:2379,$HOST_2:2379,$HOST_3:2379

etcdctl --endpoints=$ENDPOINTS member list

1.1.2 - Eine Leader-Wahl in einem etcd-Cluster durchführen

Schritte zum Durchführen einer Leader-Wahl mit dem etcdctl-Client

Voraussetzungen

  • Sicherstellen, dass etcd und etcdctl installiert sind.
  • Prüfen, ob ein etcd-Cluster aktiv ist.

Eine Leader-Wahl durchführen

Mit dem Befehl etcdctl werden Leader-Wahlen in einem etcd-Cluster durchgeführt. Er stellt sicher, dass jeweils nur ein Client Leader werden kann.

etcdctl --endpoints=$ENDPOINTS elect <election-name> [proposal]

etcdctl --endpoints=$ENDPOINTS elect election-name p1

Optionen

  • --endpoints : $ENDPOINTS

Adresse jedes Mitglieds des etcd-Clusters.

  • election-name Zeichenfolge

Eine Zeichenfolge als Kennung der Wahl. Alle Teilnehmer, die um die Leader-Rolle konkurrieren, müssen denselben Wahlnamen verwenden.

  • leader-name Zeichenfolge

Vorschlagswert des neuen Leaders.

Beispiel

./etcdctl elect my-election proposal1
my-election/694d99fafea88404
proposal1

another election:
./etcdctl elect new-election proposal1
new-election/694d99fafea8840f
proposal1

1.1.3 - Den Clusterstatus prüfen

Anleitung zum Prüfen des Status eines etcd-Clusters

Voraussetzungen

Gesamtstatus prüfen

Mit endpoint status den Gesamtstatus jedes über die Option --endpoints angegebenen Endpunkts prüfen:

etcdctl endpoint status (--endpoints=$ENDPOINTS|--cluster)

Optionen

--cluster[=false]: use all endpoints from the cluster member list

Funktionsfähigkeit prüfen

Mit endpoint health die Funktionsfähigkeit jedes über die Option --endpoints angegebenen Endpunkts prüfen:

etcdctl endpoint health (--endpoints=$ENDPOINTS|--cluster)

Optionen

--cluster[=false]: use all endpoints from the cluster member list

KV-Hash prüfen

Mit endpoint hashkv den Hash des KV-Verlaufs jedes über die Option --endpoints angegebenen Endpunkts prüfen:

etcdctl endpoint hashkv (--endpoints=$ENDPOINTS|--cluster) [rev=$REV]

Optionen

--cluster[=false]: use all endpoints from the cluster member list
--rev=0: maximum revision to hash (default: latest revision)

Von übergeordneten Befehlen geerbte Optionen

--endpoints="127.0.0.1:2379": gRPC endpoints
-w, --write-out="simple": set the output format (fields, json, protobuf, simple, table)

Beispiele

etcdctl --write-out=table --endpoints=$ENDPOINTS endpoint status

+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
|    ENDPOINT      |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| 10.240.0.17:2379 | 4917a7ab173fabe7 |  3.5.0  |   45 kB |      true |      false |         4 |      16726 |              16726 |        |
| 10.240.0.18:2379 | 59796ba9cd1bcd72 |  3.5.0  |   45 kB |     false |      false |         4 |      16726 |              16726 |        |
| 10.240.0.19:2379 | 94df724b66343e6c |  3.5.0  |   45 kB |     false |      false |         4 |      16726 |              16726 |        |
+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------|
etcdctl --endpoints=$ENDPOINTS endpoint health

10.240.0.17:2379 is healthy: successfully committed proposal: took = 3.345431ms
10.240.0.19:2379 is healthy: successfully committed proposal: took = 3.767967ms
10.240.0.18:2379 is healthy: successfully committed proposal: took = 4.025451ms
etcdctl --cluster endpoint hashkv  --write-out=table

+------------------+------------+---------------+
|     ENDPOINT     |    HASH    | HASH REVISION |
+------------------+------------+---------------+
| 10.240.0.17:2379 | 3892279174 |             3 |
| 10.240.0.18:2379 | 3892279174 |             3 |
| 10.240.0.19:2379 | 3892279174 |             3 |
+------------------+------------+---------------+

1.1.4 - Die Datenbank sichern

Anleitung zum Erstellen eines Snapshots der etcd-Datenbank

Voraussetzungen

Einen Snapshot der Datenbank erstellen

snapshot zum Speichern eines Snapshots der etcd-Datenbank zu einem bestimmten Zeitpunkt:

etcdctl --endpoints=$ENDPOINT snapshot save DB_NAME

Globale Optionen

etcdctl

--endpoints=[127.0.0.1:2379], gRPC endpoints

Ein Snapshot kann nur von einem einzelnen etcd-Knoten angefordert werden. Daher sollte die Option --endpoints nur einen Endpunkt enthalten.

etcdutl

-w, --write-out string   set the output format (fields, json, protobuf, simple, table) (default "simple")

Beispiel

11_etcdctl_snapshot_2016051001
ENDPOINTS=$HOST_1:2379
etcdctl --endpoints=$ENDPOINTS snapshot save my.db

Snapshot saved at my.db
etcdutl --write-out=table snapshot status my.db

+---------+----------+------------+------------+
|  HASH   | REVISION | TOTAL KEYS | TOTAL SIZE |
+---------+----------+------------+------------+
| c55e8b8 |        9 |         13 | 25 kB      |
+---------+----------+------------+------------+

1.1.5 - Mitglieder hinzufügen und entfernen

Anleitung zur Verwaltung der Mitgliedschaft in einem etcd-Cluster

member zum Hinzufügen, Entfernen und Aktualisieren von Mitgliedern:

13_etcdctl_member_2016062301
# For each machine
TOKEN=my-etcd-token-1
CLUSTER_STATE=new
NAME_1=etcd-node-1
NAME_2=etcd-node-2
NAME_3=etcd-node-3
HOST_1=10.240.0.13
HOST_2=10.240.0.14
HOST_3=10.240.0.15
CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380

# For node 1
THIS_NAME=${NAME_1}
THIS_IP=${HOST_1}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 \
	--listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 \
	--listen-client-urls http://${THIS_IP}:2379 \
	--initial-cluster ${CLUSTER} \
	--initial-cluster-state ${CLUSTER_STATE} \
	--initial-cluster-token ${TOKEN}

# For node 2
THIS_NAME=${NAME_2}
THIS_IP=${HOST_2}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 \
	--listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 \
	--listen-client-urls http://${THIS_IP}:2379 \
	--initial-cluster ${CLUSTER} \
	--initial-cluster-state ${CLUSTER_STATE} \
	--initial-cluster-token ${TOKEN}

# For node 3
THIS_NAME=${NAME_3}
THIS_IP=${HOST_3}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 \
	--listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 \
	--listen-client-urls http://${THIS_IP}:2379 \
	--initial-cluster ${CLUSTER} \
	--initial-cluster-state ${CLUSTER_STATE} \
	--initial-cluster-token ${TOKEN}

Anschließend ein Mitglied mit den Befehlen member remove und member add ersetzen:

# get member ID
export ETCDCTL_API=3
HOST_1=10.240.0.13
HOST_2=10.240.0.14
HOST_3=10.240.0.15
etcdctl --endpoints=${HOST_1}:2379,${HOST_2}:2379,${HOST_3}:2379 member list

# remove the member
MEMBER_ID=278c654c9a6dfd3b
etcdctl --endpoints=${HOST_1}:2379,${HOST_2}:2379,${HOST_3}:2379 \
	member remove ${MEMBER_ID}

# add a new member (node 4)
export ETCDCTL_API=3
NAME_1=etcd-node-1
NAME_2=etcd-node-2
NAME_4=etcd-node-4
HOST_1=10.240.0.13
HOST_2=10.240.0.14
HOST_4=10.240.0.16 # new member
etcdctl --endpoints=${HOST_1}:2379,${HOST_2}:2379 \
	member add ${NAME_4} \
	--peer-urls=http://${HOST_4}:2380

Danach das neue Mitglied mit der Option --initial-cluster-state existing starten:

# [WARNING] If the new member starts from the same disk space,
# make sure to remove the data directory of the old member
#
# restart with 'existing' flag
TOKEN=my-etcd-token-1
CLUSTER_STATE=existing
NAME_1=etcd-node-1
NAME_2=etcd-node-2
NAME_4=etcd-node-4
HOST_1=10.240.0.13
HOST_2=10.240.0.14
HOST_4=10.240.0.16 # new member
CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_4}=http://${HOST_4}:2380

THIS_NAME=${NAME_4}
THIS_IP=${HOST_4}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 \
	--listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 \
	--listen-client-urls http://${THIS_IP}:2379 \
	--initial-cluster ${CLUSTER} \
	--initial-cluster-state ${CLUSTER_STATE} \
	--initial-cluster-token ${TOKEN}

1.2 - Aufgaben für Entwickler

Schrittweise Anleitungen für Entwickler, die etcd als Schlüssel-Wert-Speicher in ihren Anwendungen verwenden.

1.2.1 - Aus etcd lesen

Einen Wert aus einem etcd-Cluster lesen

Voraussetzungen

  • etcdctl installieren

Vorgehensweise

Mit dem Unterbefehl get aus etcd lesen:

$ etcdctl --endpoints=$ENDPOINTS get foo
foo
Hello World!
$

Dabei gilt:

  • foo ist der angeforderte Schlüssel
  • Hello World! ist der abgerufene Wert

Für eine formatierte Ausgabe:

$ etcdctl --endpoints=$ENDPOINTS --write-out="json" get foo
{"header":{"cluster_id":289318470931837780,"member_id":14947050114012957595,"revision":3,"raft_term":4,
"kvs":[{"key":"Zm9v","create_revision":2,"mod_revision":3,"version":2,"value":"SGVsbG8gV29ybGQh"}]}}
$

Dabei gibt write-out="json" JSON aus, in dem sowohl der Schlüssel als auch der Wert base64-kodiert sind.

1.2.2 - In etcd schreiben

Ein KV-Paar zu einem etcd-Cluster hinzufügen

Voraussetzungen

  • etcdctl installieren

Vorgehensweise

Mit dem Unterbefehl put ein Schlüssel-Wert-Paar schreiben:

etcdctl --endpoints=$ENDPOINTS put foo "Hello World!"

Dabei gilt:

  • foo ist der Schlüsselname
  • "Hello World!" ist der in Anführungszeichen eingeschlossene Wert

1.2.3 - Schlüssel anhand eines Präfixes abrufen

Anleitung zum Abrufen von etcd-Schlüsseln anhand ihres Präfixes

Voraussetzungen

Schlüssel anhand eines Präfixes abrufen

$ etcdctl --endpoints=$ENDPOINTS get PREFIX --prefix

Globale Optionen

--endpoints=[127.0.0.1:2379], gRPC endpoints

Optionen

--prefix, get a range of keys with matching prefix

Beispiel

03_etcdctl_get_by_prefix_2016050501
etcdctl --endpoints=$ENDPOINTS put web1 value1
etcdctl --endpoints=$ENDPOINTS put web2 value2
etcdctl --endpoints=$ENDPOINTS put web3 value3

etcdctl --endpoints=$ENDPOINTS get web --prefix

1.2.4 - Schlüssel löschen

Eine Möglichkeit zum Löschen von etcd-Schlüsseln

Voraussetzungen

Schlüssel hinzufügen oder löschen

del zum Entfernen des angegebenen Schlüssels oder Schlüsselbereichs:

etcdctl del $KEY [$END_KEY]

Optionen

--prefix[=false]: delete keys with matching prefix
--prev-kv[=false]: return deleted key-value pairs
--from-key[=false]: delete keys that are greater than or equal to the given key using byte compare
--range[=false]: delete range of keys without delay

Von übergeordneten Befehlen geerbte Optionen

--endpoints="127.0.0.1:2379": gRPC endpoints

Beispiele

04_etcdctl_delete_2016050601
etcdctl --endpoints=$ENDPOINTS put key myvalue
etcdctl --endpoints=$ENDPOINTS del key

etcdctl --endpoints=$ENDPOINTS put k1 value1
etcdctl --endpoints=$ENDPOINTS put k2 value2
etcdctl --endpoints=$ENDPOINTS del k --prefix

1.2.5 - Mehrere Schreibvorgänge in einer Transaktion ausführen

Anleitung zu transaktionalen Schreibvorgängen

Voraussetzungen

Begriffe

Im Folgenden werden wichtige Begriffe aus dem unten stehenden Beispiel definiert.

Begriffe Definition
etcdctl Das Befehlszeilenwerkzeug zur Interaktion mit dem etcd-Server.
Befehl txn Der Befehl txn ist eine Abkürzung für „transaction“ (Transaktion). Er liest mehrere etcd-Anfragen von der Standardeingabe und wendet sie als eine einzige atomare Transaktion an. Eine Transaktion besteht aus einer Liste von Bedingungen, einer Liste von Anfragen für den Fall, dass alle Bedingungen erfüllt sind, und einer Liste von Anfragen für den Fall, dass mindestens eine Bedingung nicht erfüllt ist. Weitere Informationen unter etcdctl-Befehle für Schlüssel-Wert-Paare .
compare Die Klausel compare innerhalb einer Transaktion (txn) prüft eine Bedingung und entscheidet dadurch, ob die Operationen der Transaktion ausgeführt werden sollen. Änderungen werden nur angewendet, wenn der aktuelle Zustand des Schlüssel-Wert-Speichers den erwarteten Bedingungen entspricht. Dies erhält die Datenkonsistenz und verhindert Konflikte bei nebenläufigen Zugriffen. Der Aufbau des Befehls wird im folgenden Abschnitt Eine Transaktion ausführen gezeigt.

Transaktionen

txn zum Verarbeiten aller Anfragen in einer Transaktion:

etcdctl txn --help

Mit Transaktionen in etcd lassen sich mehrere Operationen atomar ausführen: Entweder werden alle Operationen angewendet oder keine. Das ist entscheidend, um bei zusammengehörigen Aktualisierungen die Datenkonsistenz zu wahren. Weitere Informationen zu Transaktionen enthält die API-Dokumentation .

Beispiel

Angenommen, die E-Mail-Adresse und Telefonnummer eines Benutzers sollen in einer einzigen Transaktion aktualisiert werden. So werden beide Änderungen gemeinsam angewendet.

05_etcdctl_transaction_2024101213

0. Verwendete Variablen und Optionen

Variablen
/users/{<user_id>/email : etcd-Schlüssel für die E-Mail-Adresse eines Benutzers.
/users/<user_id>/phone : etcd-Schlüssel für die Telefonnummer eines Benutzers.
Optionen
--interactive : Option zur manuellen Eingabe von Transaktionsdaten

1. Anfangsdaten einrichten

Zunächst einen Benutzer mit einigen Anfangsdaten erstellen.

etcdctl put /users/12345/email "old.address@johndoe.com"
etcdctl put /users/12345/phone "123-456-7890"

2. Eine Transaktion ausführen

Die E-Mail-Adresse und Telefonnummer des Benutzers in einer einzigen Transaktion aktualisieren.

etcdctl txn --interactive

compares:
value("/users/12345/email") = "old.address@johndoe.com"

success requests (get, put, delete):
put /users/12345/email "new.address@johndoe.com"
put /users/12345/phone "098-765-4321"

failure requests (get, put, delete):
get /users/12345/email
  • Vergleich: Prüfen, ob die aktuelle E-Mail-Adresse “old.address@johndoe.com ” lautet. So wird die Transaktion nur fortgesetzt, wenn die Daten dem erwarteten Zustand entsprechen.
  • Erfolg: Bei erfolgreichem Vergleich sowohl die E-Mail-Adresse als auch die Telefonnummer aktualisieren.
  • Fehlschlag: Schlägt der Vergleich fehl, die aktuelle E-Mail-Adresse abrufen, um zu verstehen, warum die Transaktion nicht fortgesetzt wurde.

Wichtige Hinweise

  • Atomarität: Die Transaktion stellt sicher, dass E-Mail-Adresse und Telefonnummer gemeinsam aktualisiert werden. Ist die Anfangsbedingung (der Vergleich) nicht erfüllt, wird keine der beiden Änderungen angewendet.
  • Konsistenz: Transaktionen erhalten die Datenkonsistenz, insbesondere bei mehreren zusammengehörigen Aktualisierungen.
  • Mehrere put-Operationen für denselben Schlüssel vermeiden: Innerhalb einer einzigen Transaktion nicht mehrere Werte für denselben Schlüssel schreiben, da dies zu unerwarteten Ergebnissen führen kann. Jeder Schlüssel sollte pro Transaktion nur einmal aktualisiert werden.

1.2.6 - Schlüssel überwachen

Anleitung zum Überwachen von etcd-Schlüsseln

Voraussetzungen

Schlüssel überwachen

watch für Benachrichtigungen über künftige Änderungen:

etcdctl watch $KEY [$END_KEY]

Optionen

-i, --interactive[=false]: interactive mode
--prefix[=false]: watch on a prefix if prefix is set
--rev=0: Revision to start watching
--prev-kv[=false]: get the previous key-value pair before the event happens
--progress-notify[=false]: get periodic watch progress notification from server

Von übergeordneten Befehlen geerbte Optionen

--endpoints="127.0.0.1:2379": gRPC endpoints

Beispiele

06_etcdctl_watch_2016050501
etcdctl --endpoints=$ENDPOINTS watch stock1
etcdctl --endpoints=$ENDPOINTS put stock1 1000

etcdctl --endpoints=$ENDPOINTS watch stock --prefix
etcdctl --endpoints=$ENDPOINTS put stock1 10
etcdctl --endpoints=$ENDPOINTS put stock2 20

1.2.7 - Eine Lease erstellen

Anleitung zum Erstellen einer Lease in etcd

lease zum Schreiben mit TTL:

07_etcdctl_lease_2016050501
etcdctl --endpoints=$ENDPOINTS lease grant 300
# lease 2be7547fbc6a5afa granted with TTL(300s)

etcdctl --endpoints=$ENDPOINTS put sample value --lease=2be7547fbc6a5afa
etcdctl --endpoints=$ENDPOINTS get sample

etcdctl --endpoints=$ENDPOINTS lease keep-alive 2be7547fbc6a5afa
etcdctl --endpoints=$ENDPOINTS lease revoke 2be7547fbc6a5afa
# or after 300 seconds
etcdctl --endpoints=$ENDPOINTS get sample

1.2.8 - Sperren erstellen

Anleitung zum Erstellen verteilter Sperren in etcd

LOCK erwirbt einen verteilten Mutex mit einem bestimmten Namen. Sobald die Sperre erworben wurde, bleibt sie bis zum Beenden von etcdctl bestehen.

Voraussetzungen

Eine Sperre erstellen

lock für eine verteilte Sperre:

08_etcdctl_lock_2016050501
etcdctl --endpoints=$ENDPOINTS lock mutex1

Optionen

  • endpoints – definiert eine durch Kommas getrennte Liste der Rechneradressen im Cluster.
  • ttl – Zeitüberschreitung der Sperrsitzung in Sekunden.

2 - Schnellstart

etcd in weniger als 5 Minuten einsatzbereit machen!

Befolgen Sie diese Anweisungen, um einen lokalen Ein-Mitglied-Cluster mit etcd zu installieren, zu starten und zu testen:

  1. Installieren Sie etcd aus vorkompilierten Binärdateien oder aus dem Quellcode. Weitere Einzelheiten finden Sie in der Installationsanleitung .

    Warnung

    Wichtig: Führen Sie unbedingt den letzten Schritt der Installationsanleitung aus, um zu prüfen, ob etcd über Ihren Suchpfad aufrufbar ist.

  2. Starten Sie etcd:

    $ etcd
    {"level":"info","ts":"2021-09-17T09:19:32.783-0400","caller":"etcdmain/etcd.go:72","msg":... }
    ⋮
    
    Hinweis

    Hinweis: Die Ausgabe von etcd besteht aus Protokollen — Protokolle auf Info-Ebene können ignoriert werden.

  3. Verwenden Sie in einem anderen Terminal etcdctl, um einen Schlüssel festzulegen:

    $ etcdctl put greeting "Hello, etcd"
    OK
    
  4. Rufen Sie den Schlüssel aus demselben Terminal ab:

    $ etcdctl get greeting
    greeting
    Hello, etcd
    

Was kommt als Nächstes?

Erfahren Sie auf den folgenden Seiten mehr über weitere Möglichkeiten zur Konfiguration und Nutzung von etcd:

3 - Demo

Vorgehensweisen für die Arbeit mit einem etcd-Cluster

Diese Beispiele zeigen die grundlegenden Vorgehensweisen für die Arbeit mit einem etcd-Cluster.

Authentifizierung

auth,user,role für die Authentifizierung:

export ETCDCTL_API=3
ENDPOINTS=localhost:2379

etcdctl --endpoints=${ENDPOINTS} role add root
etcdctl --endpoints=${ENDPOINTS} role get root

etcdctl --endpoints=${ENDPOINTS} user add root
etcdctl --endpoints=${ENDPOINTS} user grant-role root root
etcdctl --endpoints=${ENDPOINTS} user get root

etcdctl --endpoints=${ENDPOINTS} role add role0
etcdctl --endpoints=${ENDPOINTS} role grant-permission role0 readwrite foo
etcdctl --endpoints=${ENDPOINTS} user add user0
etcdctl --endpoints=${ENDPOINTS} user grant-role user0 role0

etcdctl --endpoints=${ENDPOINTS} auth enable
# now all client requests go through auth

etcdctl --endpoints=${ENDPOINTS} --user=user0:123 put foo bar
etcdctl --endpoints=${ENDPOINTS} get foo
# permission denied, user name is empty because the request does not issue an authentication request
etcdctl --endpoints=${ENDPOINTS} --user=user0:123 get foo
# user0 can read the key foo
etcdctl --endpoints=${ENDPOINTS} --user=user0:123 get foo1

4 - Installation

Anleitung zur Installation von etcd aus vorkompilierten Binärdateien oder aus dem Quellcode.

Voraussetzungen

Vor der Installation von etcd die folgenden Seiten lesen:

Vorkompilierte Binärdateien installieren

Am einfachsten lässt sich etcd aus vorkompilierten Binärdateien installieren:

  1. Unter Veröffentlichungen die komprimierte Archivdatei für die gewünschte Plattform herunterladen. Dabei Version v3.7.2 oder neuer wählen.

  2. Die Archivdatei entpacken. Dadurch entsteht ein Verzeichnis mit den Binärdateien.

  3. Die ausführbaren Binärdateien zum Suchpfad hinzufügen. Dazu die Binärdateien beispielsweise umbenennen und/oder in ein Verzeichnis im Suchpfad verschieben (etwa /usr/local/bin) oder das im vorigen Schritt erstellte Verzeichnis zum Suchpfad hinzufügen.

  4. In einer Shell prüfen, ob etcd im Suchpfad liegt:

    $ etcd --version
    etcd Version: 3.7.2
    ...

Aus dem Quellcode bauen

Für etcd v3.7.2 Go ab Version 1.26 verwenden; das Release legt die Go-Toolchain auf Version 1.26.8 fest. Mit den folgenden Schritten lässt sich etcd aus dem Quellcode bauen:

  1. Das etcd-Repository als ZIP-Datei herunterladen und entpacken oder das Repository mit folgendem Befehl klonen.

    $ git clone -b v3.7.2 https://github.com/etcd-io/etcd.git

    Zum Bauen aus main@HEAD die Option -b v3.7.2 weglassen.

  2. Das Verzeichnis wechseln:

    $ cd etcd
  3. Das Build-Skript ausführen:

    $ ./scripts/build.sh

    Die Binärdateien befinden sich im Verzeichnis bin.

  4. Den vollständigen Pfad zum Verzeichnis bin zum Suchpfad hinzufügen, zum Beispiel:

    $ export PATH="$PATH:`pwd`/bin"
  5. Prüfen, ob etcd im Suchpfad liegt:

    $ etcd --version

Installation über Betriebssystempakete

Hinweis: Bei der Installation von etcd über Paketmanager des Betriebssystems können veraltete Versionen installiert werden. Diese Pakete werden vom etcd-Projekt weder automatisch gepflegt noch offiziell unterstützt. Betriebssystempakete daher mit Vorsicht verwenden.

Für die verschiedenen Betriebssysteme gibt es unterschiedliche Möglichkeiten, etcd zu installieren. Im Folgenden werden einige Beispiele gezeigt.

MacOS (Homebrew)

  1. Homebrew aktualisieren:
$ brew update
  1. etcd installieren:
$ brew install etcd
  1. Installation überprüfen
$ etcd --version

Linux

etcd lässt sich zwar über die offiziellen Repositories und Paketmanager vieler großer Linux-Distributionen installieren, die angebotenen Versionen können jedoch erheblich veraltet sein. Von dieser Installationsweise wird daher dringend abgeraten.

Für Linux wird die Installation aus vorkompilierten Binärdateien oder mit Homebrew empfohlen.

Homebrew unter Linux

Homebrew läuft auch unter Linux und kann aktuelle Softwareversionen bereitstellen.

  • Voraussetzungen

    • Homebrew aktualisieren:

      $ brew update
  • Vorgehensweise

    • Mit brew installieren:

      $ brew install etcd
  • Ergebnis

    • Die Installation durch Abrufen der Version überprüfen:

      $ etcd --version
      etcd Version: 3.7.2
      ...

      Die Ausgabe oben ist ein Beispiel. Homebrew kann eine andere Patchversion bereitstellen; die tatsächlich installierte Version mit etcd --version prüfen.

Docker

etcd verwendet gcr.io/etcd-development/etcd als primäre Container-Registry und quay.io/coreos/etcd als sekundäre.

etcd mit Docker ausführen:

ETCD_VER=v3.7.2

rm -rf /tmp/etcd-data.tmp && mkdir -p /tmp/etcd-data.tmp && \
  docker rmi gcr.io/etcd-development/etcd:${ETCD_VER} || true && \
  docker run \
  -p 2379:2379 \
  -p 2380:2380 \
  --mount type=bind,source=/tmp/etcd-data.tmp,destination=/etcd-data \
  --name etcd-gcr-${ETCD_VER} \
  gcr.io/etcd-development/etcd:${ETCD_VER} \
  /usr/local/bin/etcd \
  --name s1 \
  --data-dir /etcd-data \
  --listen-client-urls http://0.0.0.0:2379 \
  --advertise-client-urls http://0.0.0.0:2379 \
  --listen-peer-urls http://0.0.0.0:2380 \
  --initial-advertise-peer-urls http://0.0.0.0:2380 \
  --initial-cluster s1=http://0.0.0.0:2380 \
  --initial-cluster-token tkn \
  --initial-cluster-state new \
  --log-level info \
  --logger zap \
  --log-outputs stderr

docker exec etcd-gcr-${ETCD_VER} /usr/local/bin/etcd --version
docker exec etcd-gcr-${ETCD_VER} /usr/local/bin/etcdctl version
docker exec etcd-gcr-${ETCD_VER} /usr/local/bin/etcdutl version
docker exec etcd-gcr-${ETCD_VER} /usr/local/bin/etcdctl endpoint health
docker exec etcd-gcr-${ETCD_VER} /usr/local/bin/etcdctl put foo bar
docker exec etcd-gcr-${ETCD_VER} /usr/local/bin/etcdctl get foo

Installation im Rahmen einer Kubernetes-Installation

Installation überprüfen

Eine etwas ausführlichere Funktionsprüfung der Installation bietet der Schnellstart .

5 - Funktionsschalter

Diese Seite gibt einen Überblick über die verschiedenen Funktionsschalter, die Administratoren für etcd festlegen können.

Die Entwicklungsphasen einer Funktion werden unter Funktionsphasen erläutert.

Überblick

Funktionsschalter sind eine Menge von key=value-Paaren, die etcd-Funktionen beschreiben. Mit der Befehlszeilenoption --feature-gates lassen sich diese Funktionen in etcd ein- oder ausschalten.

etcd ermöglicht das Aktivieren oder Deaktivieren einer Gruppe von Funktionsschaltern. Mit der Option -h lässt sich die vollständige Liste der Funktionsschalter anzeigen. Zum Festlegen der Funktionsschalter der Option --feature-gates auf der Befehlszeile eine Liste von Funktionspaaren zuweisen:

--feature-gates=...,StopGRPCServiceOnDefrag=true

Alternativ feature-gates in der YAML-Konfigurationsdatei angeben:

feature-gates: ...,StopGRPCServiceOnDefrag=true

Änderung an der Struktur embed.Config

In 3.6 wird das Feld ServerFeatureGate zu embed.Config hinzugefügt. Es sollte die unten aufgeführten experimentellen Felder ersetzen:

package embed

type Config struct {
  // Deprecated: Use CompactHashCheck Feature Gate instead. Will be decommissioned in v3.7.
  ExperimentalCompactHashCheckEnabled bool `json:"experimental-compact-hash-check-enabled"`

  // Deprecated: Use InitialCorruptCheck Feature Gate instead. Will be decommissioned in v3.7.
  ExperimentalInitialCorruptCheck bool `json:"experimental-initial-corrupt-check"`

  // Deprecated: Use TxnModeWriteWithSharedBuffer Feature Gate instead. Will be decommissioned in v3.7.
  ExperimentalTxnModeWriteWithSharedBuffer bool `json:"experimental-txn-mode-write-with-shared-buffer"`

  // Deprecated: Use StopGRPCServiceOnDefrag Feature Gate instead. Will be decommissioned in v3.7.
  ExperimentalStopGRPCServiceOnDefrag bool `json:"experimental-stop-grpc-service-on-defrag"`

  // Deprecated: Use LeaseCheckpoint Feature Gate instead. Will be decommissioned in v3.7.
  ExperimentalEnableLeaseCheckpoint bool `json:"experimental-enable-lease-checkpoint"`
  
  // Deprecated: Use LeaseCheckpointPersist Feature Gate instead. Will be decommissioned in v3.7.
  ExperimentalEnableLeaseCheckpointPersist bool `json:"experimental-enable-lease-checkpoint-persist"`

+ // ServerFeatureGate is a server level feature gate
+ ServerFeatureGate featuregate.FeatureGate
  ...

Funktionsschalter für Alpha- oder Beta-Funktionen

Die folgenden Tabellen fassen die Funktionsschalter zusammen, die für etcd gesetzt werden können.

Funktion Standardwert Phase Einzelheiten
CompactHashCheck false Alpha Ermöglicht dem Leader, die Kompaktierungs-Hashes der Follower regelmäßig zu prüfen.
InitialCorruptCheck false Alpha Ermöglicht die Prüfung auf Datenkorruption, bevor Client- oder Peer-Verkehr bedient wird.
LeaseCheckpoint false Alpha Ermöglicht dem Leader, regelmäßig Checkpoints an andere Mitglieder zu senden, damit die verbleibende TTL bei einem Leader-Wechsel nicht zurückgesetzt wird.
LeaseCheckpointPersist false Alpha Ermöglicht das dauerhafte Speichern von remainingTTL, um eine unbegrenzte automatische Verlängerung langlebiger Leases zu verhindern.
SetMemberLocalAddr false Alpha Ermöglicht es, die erste in initial-advertise-peer-urls angegebene lokale Adresse, die keine Loopback-Adresse ist, bei der Kommunikation mit einem Peer als lokale Adresse zu verwenden.
StopGRPCServiceOnDefrag false Alpha Ermöglicht es dem gRPC-Dienst von etcd, während der Defragmentierung keine Clientanfragen mehr zu bedienen.
TxnModeWriteWithSharedBuffer true Beta Ermöglicht einer Schreibtransaktion, für ihre schreibgeschützten Prüfoperationen einen gemeinsamen Puffer zu verwenden.

Eine Funktion verwenden

Funktionsphasen

Eine Funktion kann sich in der Phase Alpha, Beta, GA oder Veraltet befinden. Eine Alpha-Funktion bedeutet:

  • Standardmäßig deaktiviert.
  • Möglicherweise fehlerhaft. Durch das Aktivieren der Funktion können Fehler auftreten.
  • Die Unterstützung der Funktion kann jederzeit ohne Ankündigung eingestellt werden.
  • Die API kann sich in einer späteren Softwareversion ohne Ankündigung inkompatibel ändern.
  • Aufgrund des erhöhten Fehlerrisikos und der fehlenden langfristigen Unterstützung nur für kurzlebige Testcluster empfohlen.

Eine Beta-Funktion bedeutet:

  • Standardmäßig aktiviert.
  • Die Funktion ist gründlich getestet. Ihre Aktivierung gilt als sicher.
  • Die Unterstützung der Funktion insgesamt wird nicht eingestellt, Einzelheiten können sich jedoch ändern.
  • Nur für nicht geschäftskritische Einsatzzwecke empfohlen, da bei breiterer Nutzung neue, schwer erkennbare Fehler entdeckt werden können.
Hinweis

Bitte Beta-Funktionen ausprobieren und Rückmeldungen dazu geben! Nach dem Ende der Beta-Phase lassen sich weitere Änderungen möglicherweise nicht mehr sinnvoll umsetzen.

Eine Funktion mit allgemeiner Verfügbarkeit (GA) wird auch als stabile Funktion bezeichnet. Das bedeutet:

  • Die Funktion ist immer aktiviert und lässt sich nicht deaktivieren.
  • Der zugehörige Funktionsschalter wird nicht mehr benötigt.
  • Stabile Versionen von Funktionen werden in vielen nachfolgenden Softwareversionen enthalten sein.

Eine veraltete Funktion bedeutet:

  • Der Funktionsschalter wird nicht mehr verwendet.
  • Die Funktion hat den Status GA erreicht oder wurde entfernt.

6 - FAQ

Häufig gestellte Fragen

Allgemeines zu etcd

Was ist etcd?

etcd ist ein konsistenter, verteilter Schlüssel-Wert-Speicher. Es wird hauptsächlich als separater Koordinationsdienst in verteilten Systemen verwendet und ist für kleine Datenmengen ausgelegt, die vollständig in den Arbeitsspeicher passen.

Wie wird etcd ausgesprochen?

etcd wird /ˈɛtsiːdiː/ ausgesprochen und bedeutet „verteiltes etc-Verzeichnis“.

Müssen Clients Anfragen an den etcd-Leader senden?

Raft arbeitet mit einem Leader; dieser bearbeitet alle Clientanfragen, die einen Konsens im Cluster erfordern. Der Client muss jedoch nicht wissen, welcher Knoten der Leader ist. Jede an einen Follower gesendete Anfrage, die Konsens benötigt, wird automatisch an den Leader weitergeleitet. Anfragen ohne Konsensanforderung (etwa serialisierbare Lesezugriffe) kann jedes Clustermitglied verarbeiten.

Konfiguration

Worin unterscheiden sich listen-<client,peer>-urls, advertise-client-urls und initial-advertise-peer-urls?

listen-client-urls und listen-peer-urls legen die lokalen Adressen fest, an die sich der etcd-Server bindet, um eingehende Verbindungen anzunehmen. Um einen Port auf allen Schnittstellen zu überwachen, 0.0.0.0 als IP-Adresse zum Lauschen angeben.

advertise-client-urls und initial-advertise-peer-urls legen die Adressen fest, über die etcd-Clients oder andere etcd-Mitglieder den etcd-Server erreichen sollten. Die bekannt gegebenen Adressen müssen von den entfernten Rechnern erreichbar sein. In einer Produktionsumgebung keine Adressen wie localhost oder 0.0.0.0 bekannt geben, da diese von entfernten Rechnern nicht erreichbar sind.

Warum aktualisiert eine Änderung von --listen-peer-urls oder --initial-advertise-peer-urls nicht die in etcdctl member list bekannt gegebenen Peer-URLs?

Die bekannt gegebenen Peer-URLs eines Mitglieds stammen beim ersten Clusterstart aus --initial-advertise-peer-urls. Werden nach dem Start des Mitglieds die Adressen zum Lauschen für Peers oder die anfänglich bekannt gegebenen Peer-Adressen geändert, beeinflusst dies die veröffentlichten Peer-URLs nicht. Änderungen müssen vom Quorum bestätigt werden, um einen Split-Brain-Zustand der Mitgliedschaftskonfiguration zu vermeiden. Mit etcdctl member update lassen sich die Peer-URLs eines Mitglieds aktualisieren.

Bereitstellung

Systemanforderungen

Da etcd Daten auf den Datenträger schreibt, hängt seine Leistung stark von dessen Leistung ab. Daher wird eine SSD dringend empfohlen. Um zu prüfen, ob ein Datenträger für etcd schnell genug ist, kann ein Benchmarkwerkzeug wie fio verwendet werden. Ein Beispiel dazu gibt es hier . Um Leistungseinbußen oder eine unbeabsichtigte Überlastung des Schlüssel-Wert-Speichers zu verhindern, setzt etcd eine konfigurierbare Speicherplatzquote durch, die standardmäßig 2GB beträgt. Um Auslagerung oder Speichermangel zu vermeiden, sollte der Rechner mindestens so viel RAM haben, wie die Quote vorsieht. Für normale Umgebungen wird eine maximale Größe von 8GB empfohlen; überschreitet der konfigurierte Wert diese Grenze, warnt etcd beim Start. Bei CoreOS wird ein etcd-Cluster üblicherweise auf dedizierten Rechnern mit CoreOS Container Linux betrieben, die mindestens einen Zweikernprozessor, 2GB RAM und 80GB SSD-Speicher besitzen. Die Leistung hängt wesentlich von der Arbeitslast ab; vor dem Produktiveinsatz bitte testen. Weitere Empfehlungen stehen unter Hardware .

Die stabilste Produktionsumgebung ist Linux auf der amd64-Architektur; weitere Informationen unter Unterstützte Plattformen .

Warum eine ungerade Anzahl von Clustermitgliedern?

In einem etcd-Cluster muss die Mehrheit der Knoten, das Quorum, Änderungen am Clusterzustand zustimmen. Bei einem Cluster mit n Mitgliedern beträgt das Quorum (n/2)+1. Bei einem Cluster mit ungerader Mitgliederzahl erhöht das Hinzufügen eines Knotens immer die für das Quorum erforderliche Knotenzahl. Obwohl ein zusätzlicher Knoten wegen der höheren Rechnerzahl vorteilhaft erscheint, verschlechtert sich die Fehlertoleranz: Ohne Quorumverlust dürfen weiterhin genauso viele Knoten ausfallen, doch es gibt mehr Knoten, die ausfallen können. Kann der Cluster keine weiteren Ausfälle mehr verkraften, ist das Hinzufügen eines Knotens vor dem Entfernen von Knoten gefährlich. Kann sich der neue Knoten nicht beim Cluster registrieren (etwa wegen einer falsch konfigurierten Adresse), geht das Quorum dauerhaft verloren.

Wie groß darf ein Cluster maximal sein?

Theoretisch gibt es keine feste Grenze. Ein etcd-Cluster sollte jedoch wahrscheinlich nicht mehr als sieben Knoten haben. Der Google-Chubby-Sperrdienst , der etcd ähnelt und bei Google seit vielen Jahren weit verbreitet ist, empfiehlt fünf Knoten. Ein etcd-Cluster mit 5 Mitgliedern kann den Ausfall von zwei Mitgliedern verkraften, was in den meisten Fällen ausreicht. Größere Cluster bieten zwar eine bessere Fehlertoleranz, ihre Schreibleistung leidet jedoch darunter, dass Daten auf mehr Rechner repliziert werden müssen.

Was bedeutet Fehlertoleranz?

Ein etcd-Cluster arbeitet, solange ein Quorum seiner Mitglieder hergestellt werden kann. Geht das Quorum durch vorübergehende Netzwerkfehler (etwa Partitionierungen) verloren, setzt etcd den Betrieb automatisch und sicher fort, sobald das Netzwerk wieder funktioniert und das Quorum wiederhergestellt ist; Raft gewährleistet die Clusterkonsistenz. Für den Fall eines Stromausfalls speichert etcd das Raft-Protokoll dauerhaft auf dem Datenträger. Es spielt das Protokoll bis zum Zeitpunkt des Ausfalls erneut ab und nimmt wieder am Cluster teil. Bei einem dauerhaften Hardwareausfall kann der Knoten durch Rekonfiguration im laufenden Betrieb aus dem Cluster entfernt werden.

Eine ungerade Mitgliederzahl wird empfohlen. Ein Cluster mit ungerader Mitgliederzahl verkraftet dieselbe Zahl von Ausfällen wie ein Cluster mit gerader Mitgliederzahl, benötigt dafür aber weniger Knoten. Der Vergleich zeigt den Unterschied:

Clustergröße Mehrheit Fehlertoleranz
1 1 0
2 2 0
3 2 1
4 3 1
5 3 2
6 4 2
7 4 3
8 5 3
9 5 4

Ein Mitglied hinzuzufügen, um eine gerade Clustergröße zu erreichen, bringt keine zusätzliche Fehlertoleranz. Ebenso gewährleistet eine ungerade Mitgliederzahl bei einer Aufteilung des Netzwerks in zwei Partitionen, dass stets eine Mehrheitspartition vorhanden ist, die weiterarbeiten und nach dem Ende der Partitionierung als maßgebliche Datenquelle dienen kann.

Funktioniert etcd bei Bereitstellungen über Regionen oder Rechenzentren hinweg?

Eine Bereitstellung über mehrere Regionen verbessert die Fehlertoleranz von etcd, da die Mitglieder in getrennten Ausfallbereichen liegen. Der Preis ist eine höhere Latenz für Konsensanfragen über Rechenzentrumsgrenzen hinweg. Da etcd für den Konsens ein Quorum seiner Mitglieder benötigt, fällt diese zusätzliche Latenz ins Gewicht: Mindestens die Mehrheit der Clustermitglieder muss auf Konsensanfragen antworten. Außerdem müssen Clusterdaten auf alle Peers repliziert werden, wodurch auch Bandbreitenkosten entstehen.

Bei längeren Latenzen kann die Standardkonfiguration von etcd häufige Wahlen oder Heartbeat-Zeitüberschreitungen verursachen. Hinweise zum Anpassen der Zeitüberschreitungen für Bereitstellungen mit hoher Latenz enthält der Abschnitt Optimierung .

Betrieb

Wie wird ein Backup eines etcd-Clusters erstellt?

etcdctl stellt den Befehl snapshot zum Erstellen von Backups bereit. Weitere Einzelheiten unter Backup .

Sollte vor dem Entfernen eines nicht funktionsfähigen Mitglieds ein neues hinzugefügt werden?

Beim Ersetzen eines etcd-Knotens ist es wichtig, zuerst das Mitglied zu entfernen und dann seinen Ersatz hinzuzufügen.

etcd verwendet verteilten Konsens auf Basis eines Quorummodells: (n/2)+1 Mitglieder, also die Mehrheit, müssen einem Vorschlag zustimmen, bevor er im Cluster festgeschrieben werden kann. Solche Vorschläge umfassen Schlüssel-Wert-Aktualisierungen und Änderungen der Mitgliedschaft. Dieses Modell schließt Inkonsistenzen durch Split Brain vollständig aus. Der Nachteil ist, dass ein dauerhafter Quorumverlust katastrophal ist.

Für die Mitgliedschaft bedeutet dies: Ist in einem Cluster mit 3 Mitgliedern 1 Mitglied ausgefallen, kann der Cluster weiterhin Fortschritte machen, denn das Quorum beträgt 2 und 2 Mitglieder sind noch aktiv. Wird dem Cluster mit 3 Mitgliedern jedoch ein neues Mitglied hinzugefügt, steigt das Quorum auf 3, da für die Mehrheit von 4 Mitgliedern 3 Stimmen erforderlich sind. Wegen des gestiegenen Quorums bringt das zusätzliche Mitglied keinen Gewinn an Fehlertoleranz; der Ausfall eines weiteren Knotens würde den Cluster weiterhin unwiederherstellbar machen.

Außerdem birgt das neue Mitglied ein Risiko: Es könnte falsch konfiguriert sein oder dem Cluster nicht beitreten können. Dann lässt sich das Quorum nicht wiederherstellen. Der Cluster hat zwei ausgefallene und zwei aktive Mitglieder, benötigt aber drei Stimmen für eine Änderung der Mitgliedschaft, um das misslungene Hinzufügen rückgängig zu machen. etcd lehnt standardmäßig Versuche ab, Mitglieder hinzuzufügen, wenn sie den Cluster auf diese Weise zum Ausfall bringen könnten.

Wird dagegen zuerst das ausgefallene Mitglied aus der Clustermitgliedschaft entfernt, sinkt die Mitgliederzahl auf 2 und das Quorum bleibt bei 2. Auch das anschließende Hinzufügen eines neuen Mitglieds hält das Quorum bei 2. Selbst wenn sich der neue Knoten nicht starten lässt, können die verbleibenden aktiven Mitglieder das neue Mitglied daher weiterhin durch ein Quorum entfernen.

Warum akzeptiert etcd meine Änderungen der Mitgliedschaft nicht?

etcd setzt strict-reconfig-check, um Rekonfigurationsanfragen abzulehnen, die zum Quorumverlust führen würden. Auf das Quorum zu verzichten ist sehr riskant, insbesondere bei einem bereits beeinträchtigten Cluster. Bei Quorumverlust mag es verlockend sein, die Quorumprüfung zu deaktivieren, um ein neues Mitglied hinzuzufügen. Dies könnte jedoch den gesamten Cluster inkonsistent machen. Für viele Anwendungen würde das Problem dadurch noch schlimmer; eine Beschädigung der Datenträgergeometrie gehört zu den erschreckendsten möglichen Folgen.

Warum verliert etcd bei Spitzen der Datenträgerlatenz seinen Leader?

Dieses Verhalten ist beabsichtigt: Die Datenträgerlatenz gehört zur Beurteilung der Funktionsfähigkeit des Leaders. Angenommen, der Cluster-Leader benötigt eine Minute, um eine Aktualisierung des Raft-Logs per fsync auf den Datenträger zu schreiben, während die Wahlzeitüberschreitung des etcd-Clusters eine Sekunde beträgt. Auch wenn der Leader Netzwerknachrichten innerhalb des Wahlintervalls verarbeiten kann, etwa Heartbeats senden, ist er praktisch nicht verfügbar: Er kann keine neuen Vorschläge festschreiben, weil er auf den langsamen Datenträger wartet. Verliert der Cluster wegen Datenträgerlatenzen häufig seinen Leader, versuchen, die Datenträgereinstellungen oder die Zeitparameter von etcd zu optimieren .

Was bedeutet die etcd-Warnung “request ignored (cluster ID mismatch)”?

Jeder neue etcd-Cluster erzeugt aus der anfänglichen Clusterkonfiguration und einem vom Benutzer angegebenen eindeutigen Wert für initial-cluster-token eine neue Cluster-ID. Eindeutige Cluster-IDs schützen etcd vor Wechselwirkungen zwischen Clustern, die den Cluster beschädigen könnten.

Diese Warnung tritt üblicherweise auf, nachdem ein alter Cluster abgebaut wurde und einige seiner Peer-Adressen für einen neuen Cluster wiederverwendet werden. Läuft noch ein etcd-Prozess des alten Clusters, versucht er, den neuen Cluster zu kontaktieren. Dieser erkennt die abweichende Cluster-ID, ignoriert die Anfrage und gibt die Warnung aus. Häufig lässt sich die Warnung beseitigen, indem sichergestellt wird, dass verschiedene Cluster keine gemeinsamen Peer-Adressen haben.

Was bedeutet “mvcc: database space exceeded” und wie lässt sich das beheben?

Das Datenmodell von etcd mit Mehrversionen-Nebenläufigkeitskontrolle bewahrt einen exakten Verlauf des Schlüsselraums. Ohne regelmäßige Kompaktierung dieses Verlaufs, etwa durch Setzen von --auto-compaction-mode und --auto-compaction-retention, wird etcd seinen Speicherplatz irgendwann aufbrauchen. Bei knappem Speicherplatz löst etcd einen Speicherplatzquotenalarm aus, um den Cluster vor weiteren Schreibzugriffen zu schützen. Solange der Alarm aktiv ist, beantwortet etcd Schreibanfragen mit dem Fehler mvcc: database space exceeded.

So lässt sich der Speicherplatzquotenalarm beheben:

  1. Den Verlauf von etcd kompaktieren .
  2. Jeden etcd-Endpunkt defragmentieren .
  3. Den Alarm deaktivieren .

Was bedeutet die etcd-Warnung “etcdserver/api/v3rpc: transport: http2Server.HandleStreams failed to read frame: read tcp 127.0.0.1:2379->127.0.0.1:43020: read: connection reset by peer”?

Dies ist eine gRPC-seitige Warnung, wenn ein Server ein TCP-RST-Flag empfängt, weil clientseitige Streams vorzeitig geschlossen wurden. Ein Client schließt beispielsweise seine Verbindung, bevor der gRPC-Server alle HTTP/2-Frames in der TCP-Warteschlange verarbeitet hat. Auf Serverseite können dabei Daten verloren gegangen sein; solange die Clientverbindung bereits geschlossen wurde, ist das jedoch unproblematisch.

Nur alte gRPC-Versionen protokollieren dies. etcd >=v3.2.13 protokolliert es standardmäßig auf der Stufe DEBUG , sodass es nur mit aktivierter Option --log-level=debug sichtbar ist.

Leistung

Wie sollte etcd einem Benchmark unterzogen werden?

Das Werkzeug benchmark ausprobieren. Aktuelle Benchmark-Ergebnisse stehen zum Vergleich bereit.

Was bedeutet die etcd-Warnung “apply entries took too long”?

Nachdem die Mehrheit der etcd-Mitglieder dem Festschreiben einer Anfrage zugestimmt hat, wendet jeder etcd-Server die Anfrage auf seinen Datenspeicher an und speichert das Ergebnis dauerhaft auf dem Datenträger. Selbst mit einem langsamen mechanischen Datenträger oder einem virtualisierten Netzwerkdatenträger wie Amazons EBS oder Googles PD sollte das Anwenden einer Anfrage normalerweise weniger als 50 Millisekunden dauern. Übersteigt die durchschnittliche Anwendungsdauer 100 Millisekunden, warnt etcd, dass das Anwenden der Einträge zu lange dauert.

Meist wird dieses Problem durch einen langsamen Datenträger verursacht. Möglicherweise konkurrieren etcd und andere Anwendungen um Datenträgerzugriffe, oder der Datenträger ist schlicht zu langsam, etwa ein gemeinsam genutzter virtualisierter Datenträger. Um einen langsamen Datenträger als Ursache auszuschließen, backend_commit_duration_seconds überwachen (die p99-Dauer sollte unter 25ms liegen) und so prüfen, ob der Datenträger ausreichend schnell ist. Ist er zu langsam, lässt sich das Problem in der Regel durch einen dedizierten oder schnelleren Datenträger für etcd lösen.

Die zweithäufigste Ursache ist ein Mangel an CPU-Zeit. Zeigt die Überwachung der CPU-Nutzung des Rechners eine hohe Auslastung, reicht die Rechenkapazität für etcd möglicherweise nicht aus. In der Regel hilft es, etcd auf einen dedizierten Rechner zu verlagern, die Ressourcenisolierung der Prozesse mit cgroups zu verstärken oder dem etcd-Serverprozess mit renice eine höhere Priorität zu geben.

Aufwendige Benutzeranfragen, die auf zu viele Schlüssel zugreifen, etwa das Abrufen des gesamten Schlüsselraums, können ebenfalls lange Anwendungslatenzen verursachen. Zugriffe auf weniger als einige Hundert Schlüssel pro Anfrage sollten jedoch immer schnell sein.

Beseitigt keiner dieser Vorschläge die Warnungen, bitte ein Issue erstellen und ausführliche Protokolle, Überwachungsdaten, Metriken sowie gegebenenfalls Informationen zur Arbeitslast beifügen.

Was bedeutet die etcd-Warnung “failed to send out heartbeat on time”?

etcd verwendet ein auf einem Leader basierendes Konsensprotokoll für konsistente Datenreplikation und Log-Ausführung. Die Clustermitglieder wählen einen einzigen Leader; alle anderen Mitglieder werden Follower. Der gewählte Leader muss regelmäßig Heartbeats an seine Follower senden, um seine Rolle beizubehalten. Erhalten Follower innerhalb eines Wahlintervalls keine Heartbeats, nehmen sie einen Leader-Ausfall an und lösen eine Wahl aus. Sendet ein noch laufender Leader seine Heartbeats nicht rechtzeitig, ist die Wahl unnötig und wird wahrscheinlich durch unzureichende Ressourcen ausgelöst. Um solche Funktionsstörungen zu erkennen, warnt etcd, wenn der Leader zwei Heartbeat-Intervalle auslässt, dass ein Heartbeat nicht rechtzeitig gesendet wurde.

Meist wird dieses Problem durch einen langsamen Datenträger verursacht. Bevor der Leader Heartbeats mit angehängten Metadaten sendet, muss er die Metadaten möglicherweise dauerhaft auf dem Datenträger speichern. Möglicherweise konkurrieren etcd und andere Anwendungen um Datenträgerzugriffe, oder der Datenträger ist schlicht zu langsam, etwa ein gemeinsam genutzter virtualisierter Datenträger. Um einen langsamen Datenträger als Ursache auszuschließen, wal_fsync_duration_seconds überwachen (die p99-Dauer sollte unter 10ms liegen) und so prüfen, ob der Datenträger ausreichend schnell ist. Ist er zu langsam, lässt sich das Problem in der Regel durch einen dedizierten oder schnelleren Datenträger für etcd lösen. Ob ein Datenträger schnell genug für etcd ist, lässt sich mit einem Benchmarkwerkzeug wie fio prüfen. Ein Beispiel steht hier .

Die zweithäufigste Ursache ist ein Mangel an CPU-Zeit. Zeigt die Überwachung der CPU-Nutzung des Rechners eine hohe Auslastung, reicht die Rechenkapazität für etcd möglicherweise nicht aus. In der Regel hilft es, etcd auf einen dedizierten Rechner zu verlagern, die Ressourcenisolierung der Prozesse mit cgroups zu verstärken oder dem etcd-Serverprozess mit renice eine höhere Priorität zu geben.

Auch ein langsames Netzwerk kann dieses Problem verursachen. Zeigen die Netzwerkmetriken zwischen den etcd-Rechnern lange Latenzen oder eine hohe Verlustrate, reicht die Netzwerkkapazität für etcd möglicherweise nicht aus. In der Regel hilft es, die etcd-Mitglieder in ein weniger ausgelastetes Netzwerk zu verlagern. Bei einem über mehrere Rechenzentren verteilten etcd-Cluster sind lange Latenzen zwischen den Mitgliedern jedoch zu erwarten. Für solche Bereitstellungen heartbeat-interval ungefähr auf die Umlaufzeit zwischen den Rechnern einstellen und election-timeout auf mindestens 5 * heartbeat-interval setzen. Einzelheiten enthält die Dokumentation zur Optimierung .

Beseitigt keiner dieser Vorschläge die Warnungen, bitte ein Issue erstellen und ausführliche Protokolle, Überwachungsdaten, Metriken sowie gegebenenfalls Informationen zur Arbeitslast beifügen.

Was bedeutet die etcd-Warnung “snapshotting is taking more than x seconds to finish …”?

etcd sendet einen Snapshot seines vollständigen Schlüssel-Wert-Speichers, um langsame Follower auf den aktuellen Stand zu bringen und Backups zu erstellen. Langsame Snapshot-Übertragungen erhöhen die MTTR. Nimmt der Cluster Daten mit hohem Durchsatz auf, können langsame Follower in einen Livelock geraten: Sie benötigen bereits einen neuen Snapshot, bevor sie den vorherigen vollständig empfangen haben. Um langsame Snapshot-Übertragungen zu erkennen, warnt etcd, wenn das Senden eines Snapshots länger als dreißig Sekunden dauert und die für eine 1Gbps-Verbindung erwartete Übertragungszeit überschreitet.

7 - Bibliotheken und Werkzeuge

Eine Übersicht über etcd-Werkzeuge und Clientbibliotheken

Die unten aufgeführten Bibliotheken und Werkzeuge von Drittanbietern, die nicht unter https://github.com/etcd-io gehostet werden, werden vom etcd-Team weder getestet noch gepflegt. Es wird empfohlen, sich vor der Verwendung darüber zu informieren und sie zu prüfen.

Werkzeuge

  • etcdctl - Ein Befehlszeilenclient für etcd
  • etcd-dump - Befehlszeilenwerkzeug zum Exportieren und Wiederherstellen von etcd.
  • etcd-fs - FUSE-Dateisystem für etcd
  • etcddir - Echtzeitsynchronisierung zwischen etcd und einem lokalen Verzeichnis. Funktioniert unter Windows und Linux.
  • etcd-browser - Ein webbasierter Schlüssel-Wert-Editor für etcd mit AngularJS
  • etcd-lock - Implementierung von Master-Wahl und verteilten Lese-/Schreibsperren mit etcd – Unterstützt v2
  • etcd-console - Ein webbasierter Schlüssel-Wert-Editor für etcd mit PHP
  • etcd-viewer - Ein in Java geschriebener Editor und Betrachter für den etcd-Schlüssel-Wert-Speicher
  • etcdtool - etcd-Verzeichnisse als JSON/YAML/TOML exportieren, importieren und bearbeiten sowie mit JSON-Schema validieren
  • etcdloadtest - Ein Befehlszeilenclient für Lasttests mit etcd ab Version 3.0.
  • etcd-tui - Eine moderne Terminaloberfläche (TUI) für die Interaktion mit einer etcd-Datenbank. Durch Schlüssel navigieren, Werte anzeigen, Daten filtern und den etcd-Cluster direkt im Terminal verwalten.
  • etcdfinder - Eine sehr schnelle, moderne Weboberfläche (UI) für etcd mit Sofortsuche. Unterstützt sowohl etcd v2 als auch v3.
  • lucas - Ein webbasierter Betrachter für Schlüssel-Wert-Paare in Kubernetes-Clustern mit etcd3.0+.
  • etcd-manager - Eine moderne, effiziente, plattformübergreifende und kostenlose GUI samt Clientwerkzeug für etcd 3.x. Verfügbar für Windows, Linux und Mac.
  • etcd-backup-restore - Werkzeug für regelmäßige inkrementelle Backups und die Wiederherstellung von etcd.
  • etcd-druid - Ein Kubernetes-Operator zum Bereitstellen von etcd-Clustern und zur Verwaltung des laufenden Betriebs (day-2).
  • etcdadm - Ein Befehlszeilenwerkzeug zum Betreiben eines etcd-Clusters.
  • etcd-defrag - Ein einfacher bedienbares und intelligenteres Werkzeug zur Defragmentierung von etcd.
  • etcdhelper - Ein etcd-Plugin für die IntelliJ-Plattform.

Bibliotheken

Die folgenden Abschnitte führen etcd-Clientbibliotheken nach Programmiersprache auf.

Go

  • etcd/client/v3 - Der offiziell gepflegte Go-Client für v3
  • go-etcd - Der veraltete offizielle Client. Kann für ältere etcd-Versionen (<2.0.0) nützlich sein.
  • encWrapper - encWrapper ist ein Verschlüsselungs-Wrapper für die Keys API/KV des etcd-Clients.

Java

Scala

  • maciej/etcd-client - Unterstützt v2. Vollständig asynchroner Client auf Basis von Akka HTTP
  • eiipii/etcdhttpclient - Unterstützt v2. Asynchroner HTTP-Client auf Basis von Netty und Scala Futures.
  • mingchuno/etcd4s - Unterstützt v3 über gRPC, mit optionaler Unterstützung für Akka Stream.

Perl

Python

Node

Ruby

C

C++

Clojure

Erlang

Elixir

.NET

PHP

Haskell

R

Nim

Tcl

Rust

Gradle

Lua

Werkzeuge zur Bereitstellung

Chef-Integrationen

Chef-Cookbooks

BOSH-Releases

Projekte, die etcd verwenden

  • Nutzer von etcd-Raft - Projekte, die die Raft-Bibliotheksimplementierung von etcd verwenden.
  • Apache APISIX - Ein API-Gateway, das etcd als Konfigurationsspeicher verwendet.
  • apache/celix - Eine für C und C++ angepasste Implementierung der OSGi-Spezifikation
  • binocarlos/yoda - etcd + ZeroMQ
  • blox/blox - Eine Sammlung von Open-Source-Projekten zur Containerverwaltung und -orchestrierung mit AWS ECS
  • calavera/active-proxy - Ein mit etcd konfigurierter HTTP-Proxy
  • chain/chain - Software zum Betreiben hochskalierbarer zugangsbeschränkter Blockchain-Netzwerke und zum Herstellen von Verbindungen zu ihnen
  • derekchiang/etcdplus - Eine Sammlung verteilter Synchronisationsprimitive auf Basis von etcd
  • go-discover - Diensterkennung in Go
  • gleicon/goreman - Zweig des Go-Foreman-Klons mit etcd-Unterstützung
  • garethr/hiera-etcd - Puppet-hiera-Backend mit etcd
  • mattn/etcd-vim - Schlüssel mit SET und GET direkt in vim schreiben und lesen
  • mattn/etcdenv - „env“-Shebang mit etcd-Integration
  • kelseyhightower/confd - Lokale Anwendungskonfigurationsdateien mit Vorlagen und Daten aus etcd verwalten
  • configdb - Eine relationale REST-Abstraktion über beliebigen Datenbank-Backends zum Speichern von Konfigurationen und Inventaren.
  • kubernetes/kubernetes - Von Google eingeführte Verwaltung für Containercluster.
  • mailgun/vulcand - HTTP-Proxy, der etcd als Konfigurations-Backend verwendet.
  • duedil-ltd/discodns - Einfacher DNS-Nameserver, der etcd als Datenbank für Namen und Einträge verwendet.
  • skynetservices/skydns - RFC-konformer DNS-Server
  • xordataexchange/crypt - Werte mit GPG-Verschlüsselung sicher in etcd speichern
  • spf13/viper - Go-Konfigurationsbibliothek; liest Werte aus ENV, pflags, Dateien und etcd, mit optionaler Verschlüsselung
  • lytics/metafora - Go-Bibliothek für verteilte Aufgaben
  • ryandoyle/nss-etcd - Ein GNU-libc-NSS-Modul zur Namensauflösung aus etcd.
  • Gru - Orchestrierung mit Go leicht gemacht
  • Vitess - Vitess ist ein Datenbank-Clustersystem zur horizontalen Skalierung von MySQL.
  • lclarkmichalek/etcdhcp - DHCP-Server, der etcd für Persistenz und Koordination verwendet.
  • openstack/networking-vpp - Ein Netzwerktreiber, der die FD.io-VPP-Datenebene programmiert, um virtuelle Cloud-Netzwerke für OpenStack bereitzustellen
  • OpenStack - OpenStack-Dienste können etcd als Basisdienst verwenden.
  • CoreDNS - CoreDNS ist ein DNS-Server mit verketteten Plugins und Teil von CNCF und Kubernetes
  • Uber M3 - M3: Ubers Open-Source-Metrikplattform für Prometheus im großen Maßstab
  • Rook - Speicherorchestrierung für Kubernetes
  • Patroni - Eine Vorlage für PostgreSQL-Hochverfügbarkeit mit ZooKeeper, etcd oder Consul
  • Trillian - Trillian implementiert einen Merkle-Baum, dessen Inhalte aus einer Datenspeicherschicht bereitgestellt werden, um die Skalierung auf extrem große Bäume zu ermöglichen.
  • purpleidea/mgmt - Verteilte, ereignisgesteuerte, parallele Konfigurationsverwaltung der nächsten Generation!
  • Portworx/kvdb - Die interne kvdb zum Speichern der Portworx-Clusterkonfiguration.
  • Apache Pulsar - Apache Pulsar ist eine quelloffene, verteilte Messaging- und Streaming-Plattform für die Cloud.

8 - Metriken

Metriken für Echtzeitüberwachung und Fehlersuche

etcd verwendet Prometheus zur Bereitstellung von Metriken. Sie lassen sich für Echtzeitüberwachung und Fehlersuche nutzen. etcd speichert seine Metriken nicht dauerhaft; beim Neustart eines Mitglieds werden sie zurückgesetzt.

Die verfügbaren Metriken lassen sich am einfachsten mit cURL am Metrikendpunkt /metrics abrufen. Das Format wird in der Prometheus-Dokumentation beschrieben.

Mit der Prometheus-Einstiegsanleitung lässt sich ein Prometheus-Server zum Sammeln von etcd-Metriken starten.

Die Benennung der Metriken folgt den empfohlenen bewährten Verfahren von Prometheus . Ein Metrikname enthält etcd oder etcd_debugging als Namensraumpräfix sowie ein Präfix für das Subsystem (zum Beispiel wal und etcdserver).

Metriken im Namensraum etcd

Metriken mit dem Präfix etcd dienen der Überwachung und Alarmierung. Sie sind stabile Metriken auf hoher Abstraktionsebene. Änderungen an diesen Metriken werden in den Versionshinweisen aufgeführt.

Metriken zu etcd2 sind im v2-Metrikleitfaden dokumentiert.

Server

Diese Metriken beschreiben den Zustand des etcd-Servers. Um Ausfälle oder Probleme für die Fehlersuche zu erkennen, sollten die Servermetriken jedes etcd-Clusters im Produktivbetrieb genau überwacht werden.

Alle diese Metriken haben das Präfix etcd_server_

Name Beschreibung Typ
has_leader Ob ein Leader vorhanden ist. 1 bedeutet vorhanden, 0 bedeutet nicht vorhanden. Gauge
leader_changes_seen_total Anzahl der beobachteten Leader-Wechsel. Counter
proposals_committed_total Gesamtzahl der festgeschriebenen Konsensvorschläge. Gauge
proposals_applied_total Gesamtzahl der angewendeten Konsensvorschläge. Gauge
proposals_pending Aktuelle Anzahl der ausstehenden Vorschläge. Gauge
proposals_failed_total Gesamtzahl der beobachteten fehlgeschlagenen Vorschläge. Counter

has_leader zeigt an, ob das Mitglied einen Leader hat. Ohne Leader ist ein Mitglied vollständig nicht verfügbar. Hat kein Mitglied im Cluster einen Leader, ist der gesamte Cluster vollständig nicht verfügbar.

leader_changes_seen_total zählt die Leader-Wechsel, die das Mitglied seit seinem Start beobachtet hat. Häufige Leader-Wechsel beeinträchtigen die Leistung von etcd erheblich. Sie weisen auch auf einen instabilen Leader hin, möglicherweise aufgrund von Netzwerkverbindungsproblemen oder übermäßiger Last auf dem etcd-Cluster.

proposals_committed_total erfasst die Gesamtzahl der festgeschriebenen Konsensvorschläge. In einem funktionsfähigen Cluster sollte dieser Gauge-Wert mit der Zeit steigen. Mehrere funktionsfähige Mitglieder eines etcd-Clusters können zum selben Zeitpunkt unterschiedliche Gesamtzahlen festgeschriebener Vorschläge haben. Mögliche Gründe dafür sind das Nachholen von Daten von Peers nach dem Start, ein Rückstand gegenüber dem Leader oder die Rolle als Leader, der deshalb die meisten Commits hat. Wichtig ist, diese Metrik über alle Clustermitglieder hinweg zu beobachten: Ein dauerhaft großer Rückstand eines einzelnen Mitglieds gegenüber seinem Leader deutet darauf hin, dass das Mitglied langsam oder nicht funktionsfähig ist.

proposals_applied_total erfasst die Gesamtzahl der angewendeten Konsensvorschläge. Der etcd-Server wendet jeden festgeschriebenen Vorschlag asynchron an. Der Unterschied zwischen proposals_committed_total und proposals_applied_total sollte normalerweise gering sein (selbst unter hoher Last innerhalb weniger Tausend). Steigt die Differenz weiter an, weist dies auf eine Überlastung des etcd-Servers hin. Das kann bei aufwendigen Abfragen geschehen, etwa umfangreichen Bereichsabfragen oder großen txn-Operationen.

proposals_pending zeigt an, wie viele Vorschläge zum Festschreiben anstehen. Eine steigende Zahl ausstehender Vorschläge deutet auf hohe Clientlast hin oder darauf, dass das Mitglied Vorschläge nicht festschreiben kann.

proposals_failed_total hängt normalerweise mit zwei Problemen zusammen: vorübergehenden Fehlern während einer Leader-Wahl oder längeren Ausfällen durch den Verlust des Quorums im Cluster.

Datenträger

Diese Metriken beschreiben den Zustand der Datenträgeroperationen.

Alle diese Metriken haben das Präfix etcd_disk_.

Name Beschreibung Typ
wal_fsync_duration_seconds Latenzverteilungen der von wal aufgerufenen fsync-Operationen Histogram
backend_commit_duration_seconds Latenzverteilungen der vom Backend aufgerufenen commit-Operationen. Histogram

wal_fsync wird aufgerufen, wenn etcd seine Protokolleinträge auf dem Datenträger dauerhaft speichert, bevor es sie anwendet.

backend_commit wird aufgerufen, wenn etcd einen inkrementellen Snapshot seiner neuesten Änderungen auf dem Datenträger festschreibt.

Hohe Latenzen bei Datenträgeroperationen (wal_fsync_duration_seconds oder backend_commit_duration_seconds) weisen häufig auf Datenträgerprobleme hin. Sie können hohe Anfragelatenzen verursachen oder den Cluster instabil machen.

Netzwerk

Diese Metriken beschreiben den Zustand des Netzwerks.

Alle diese Metriken haben das Präfix etcd_network_

Name Beschreibung Typ
peer_sent_bytes_total Gesamtzahl der an den Peer mit der ID To gesendeten Bytes. Counter(To)
peer_received_bytes_total Gesamtzahl der vom Peer mit der ID From empfangenen Bytes. Counter(From)
peer_sent_failures_total Gesamtzahl der Sendefehler zum Peer mit der ID To. Counter(To)
peer_received_failures_total Gesamtzahl der Empfangsfehler vom Peer mit der ID From. Counter(From)
peer_round_trip_time_seconds Histogramm der Umlaufzeiten zwischen Peers. Histogram(To)
client_grpc_sent_bytes_total Gesamtzahl der an gRPC-Clients gesendeten Bytes. Counter
client_grpc_received_bytes_total Gesamtzahl der von gRPC-Clients empfangenen Bytes. Counter

peer_sent_bytes_total zählt die Gesamtzahl der an einen bestimmten Peer gesendeten Bytes. Normalerweise sendet das Leader-Mitglied mehr Daten als andere Mitglieder, da es die replizierten Daten überträgt.

peer_received_bytes_total zählt die Gesamtzahl der von einem bestimmten Peer empfangenen Bytes. Normalerweise empfangen Follower-Mitglieder nur Daten vom Leader-Mitglied.

gRPC-Anfragen

Diese Metriken werden über go-grpc-prometheus bereitgestellt.

Metriken im Namensraum etcd_debugging

Die Metriken mit dem Präfix etcd_debugging dienen der Fehlersuche. Sie hängen stark von der Implementierung ab und ändern sich häufig. In neuen etcd-Versionen können sie ohne Vorwarnung geändert oder entfernt werden. Einige dieser Metriken können zum Präfix etcd wechseln, sobald sie stabiler sind.

Snapshot

Name Beschreibung Typ
snapshot_save_total_duration_seconds Verteilungen der Gesamtlatenz der von snapshot aufgerufenen save-Operationen Histogram

Eine ungewöhnlich lange Snapshot-Dauer (snapshot_save_total_duration_seconds) weist auf Datenträgerprobleme hin und kann den Cluster instabil machen.

Von Prometheus bereitgestellte Metriken

Die Prometheus-Clientbibliothek stellt zahlreiche Metriken in den Namensräumen go und process bereit. Einige sind besonders interessant.

Name Beschreibung Typ
process_open_fds Anzahl offener Dateideskriptoren. Gauge
process_max_fds Maximale Anzahl offener Dateideskriptoren. Gauge
Hinweis

Prozessmetriken wie process_open_fds und process_max_fds werden derzeit auf Darwin-Systemen (macOS) nicht unterstützt.

Eine hohe Nutzung von Dateideskriptoren (process_open_fds), also nahe am Limit des Prozesses (process_max_fds), weist auf eine mögliche Erschöpfung der Dateideskriptoren hin. Sind keine Dateideskriptoren mehr verfügbar, kann etcd mit einer Panic abbrechen, weil es keine neuen WAL-Dateien erstellen kann.

Generierte Liste der Metriken

9 - Fehler melden

Fehlerberichte für das etcd-Projekt erstellen

Fehler in einem Teil des etcd-Projekts oder in seiner Dokumentation bitte durch Erstellen eines Issues melden. Wir nehmen Fehler und Mängel sehr ernst und halten kein Problem für zu klein. Vor dem Erstellen eines Fehlerberichts bitte prüfen, ob dasselbe Problem bereits gemeldet wurde.

Damit Fehlerberichte präzise und leicht verständlich sind, sollten sie möglichst folgende Eigenschaften haben:

  • Konkret. Möglichst viele Einzelheiten angeben: Version, Umgebung, Konfiguration usw. Bei Fehlern im Betrieb des etcd-Servers bitte das etcd-Protokoll beifügen (besonders wichtig ist das Startprotokoll mit der etcd-Konfiguration).

  • Reproduzierbar. Die Schritte zum Reproduzieren des Problems angeben. Wir wissen, dass sich manche Probleme nur schwer reproduzieren lassen; in solchen Fällen bitte die Schritte angeben, die zum Problem führen könnten. Wenn möglich, dem Fehlerbericht das betroffene etcd-Datenverzeichnis und den Stacktrace beifügen.

  • Isoliert. Den Fehler möglichst mit einem Minimum an Abhängigkeiten isolieren und reproduzieren. Zu viele Abhängigkeiten in einem Fehlerbericht verlangsamen die Behebung erheblich. Die Fehlersuche in externen Systemen, die etcd verwenden, liegt außerhalb unseres Zuständigkeitsbereichs. Wir geben aber gern Hinweise zur weiteren Suche oder helfen bei der Verwendung von etcd selbst.

  • Einmalig. Keine bereits vorhandenen Fehlerberichte duplizieren.

  • Abgegrenzt. Pro Bericht nur einen Fehler melden. Keinen weiteren Fehler an einen bestehenden Bericht anhängen.

Vor dem Erstellen eines Fehlerberichts kann es hilfreich sein, Elika Etemads Artikel über gute Fehlerberichte zu lesen.

Zur Eingrenzung eines Fehlers fragen wir möglicherweise nach weiteren Informationen. Doppelte Fehlerberichte werden geschlossen.

Häufig gestellte Fragen

Einen Stacktrace abrufen

$ kill -QUIT $PID

Die etcd-Version abrufen

$ etcd --version

etcd-Konfiguration und Protokoll beim Betrieb als systemd-Dienst ‘etcd2.service’ abrufen

$ sudo systemctl cat etcd2
$ sudo journalctl -u etcd2

Aufgrund eines Fehlers in systemd kann journald die letzten Protokollzeilen verlieren, wenn seine Prozesse enden. Wenn journalctl meldet, dass etcd ohne eine fatal- oder panic-Meldung beendet wurde, mit sudo journalctl -f -t etcd2 versuchen, das vollständige Protokoll abzurufen.

10 - Optimierung

Wann das Heartbeat-Intervall und die Wahlzeitüberschreitung angepasst werden sollten

Die Standardeinstellungen von etcd sollten für Installationen in einem lokalen Netzwerk mit geringer durchschnittlicher Netzwerklatenz gut geeignet sein. Beim Einsatz von etcd über mehrere Rechenzentren oder Netzwerke mit hoher Latenz hinweg kann es jedoch nötig sein, das Heartbeat-Intervall und die Wahlzeitüberschreitung anzupassen.

Das Netzwerk ist nicht die einzige Latenzquelle. Langsame Datenträger auf Leader und Follower können jede Anfrage und Antwort beeinträchtigen. Jede dieser Zeitüberschreitungen bezieht sich auf die gesamte Zeit von der Anfrage bis zur erfolgreichen Antwort des anderen Rechners.

Zeitparameter

Das zugrunde liegende verteilte Konsensprotokoll verwendet zwei getrennte Zeitparameter, damit Knoten die Leader-Rolle übergeben können, wenn ein Knoten blockiert oder offline geht. Der erste Parameter heißt Heartbeat-Intervall. Er legt fest, wie oft der Leader seinen Followern mitteilt, dass er weiterhin Leader ist. Als bewährte Vorgehensweise sollte der Parameter ungefähr auf die Umlaufzeit zwischen den Mitgliedern gesetzt werden. Standardmäßig verwendet etcd ein Heartbeat-Intervall von 100ms.

Der zweite Parameter heißt Wahlzeitüberschreitung. Er legt fest, wie lange ein Follower-Knoten ohne Heartbeat wartet, bevor er selbst versucht, Leader zu werden. Standardmäßig verwendet etcd eine Wahlzeitüberschreitung von 1000ms.

Bei der Anpassung dieser Werte ist eine Abwägung nötig. Für das Heartbeat-Intervall wird ungefähr das Maximum der durchschnittlichen Umlaufzeiten (RTT) zwischen den Mitgliedern empfohlen, in der Regel bei etwa 0.5-1.5x der Umlaufzeit. Ist das Heartbeat-Intervall zu kurz, sendet etcd unnötige Nachrichten und beansprucht dadurch mehr CPU- und Netzwerkressourcen. Ein zu langes Heartbeat-Intervall führt dagegen zu einer langen Wahlzeitüberschreitung. Bei einer längeren Wahlzeitüberschreitung dauert es länger, den Ausfall eines Leaders zu erkennen. Am einfachsten lässt sich die Umlaufzeit (RTT) mit dem PING-Werkzeug messen.

Die Wahlzeitüberschreitung sollte anhand des Heartbeat-Intervalls und der durchschnittlichen Umlaufzeit zwischen den Mitgliedern festgelegt werden. Sie muss mindestens das 10-Fache der Umlaufzeit betragen, um Schwankungen im Netzwerk zu berücksichtigen. Beträgt die Umlaufzeit zwischen den Mitgliedern beispielsweise 10ms, sollte die Wahlzeitüberschreitung mindestens 100ms betragen.

Die Obergrenze der Wahlzeitüberschreitung beträgt 50000ms (50s). Dieser Wert sollte nur bei einem weltweit verteilten etcd-Cluster verwendet werden. Auf dem US-Festland ist eine Umlaufzeit von 130ms realistisch, zwischen den USA und Japan etwa 350-400ms. Bei schwankender Netzwerkleistung oder regelmäßigen Paketverzögerungen bzw. -verlusten können mehrere Wiederholungen nötig sein, um ein Paket erfolgreich zu senden. Daher sind 5s eine sichere Obergrenze für die weltweite Umlaufzeit. Da die Wahlzeitüberschreitung eine Größenordnung über der Broadcast-Zeit liegen sollte, sind bei ~5s für einen weltweit verteilten Cluster 50 Sekunden ein angemessenes Maximum.

Heartbeat-Intervall und Wahlzeitüberschreitung sollten für alle Mitglieder eines Clusters gleich sein. Unterschiedliche Werte für etcd-Mitglieder können die Stabilität des Clusters beeinträchtigen.

Die Standardwerte lassen sich auf der Befehlszeile überschreiben:

# Command line arguments:
$ etcd --heartbeat-interval=100 --election-timeout=500

# Environment variables:
$ ETCD_HEARTBEAT_INTERVAL=100 ETCD_ELECTION_TIMEOUT=500 etcd

Die Werte werden in Millisekunden angegeben.

Snapshots

etcd hängt alle Schlüsseländerungen an eine Protokolldatei an. Dieses Protokoll wächst unbegrenzt und enthält den vollständigen linearen Verlauf aller Änderungen an den Schlüsseln. Für wenig genutzte Cluster eignet sich ein vollständiger Verlauf gut; stark genutzte Cluster müssten jedoch ein großes Protokoll mitführen.

Um ein riesiges Protokoll zu vermeiden, erstellt etcd regelmäßig Snapshots. Sie ermöglichen die Kompaktierung des Protokolls: Der aktuelle Systemzustand wird gespeichert, alte Protokolle werden entfernt.

Snapshots optimieren

Raft-Snapshots werden nach einer konfigurierten Anzahl angewendeter Einträge erstellt; etcd 3.7 verwendet das V2-Backend nicht mehr. Standardmäßig erfolgt dies nach jeweils 10,000 Änderungen. Wenn der Arbeitsspeicher- und Datenträgerverbrauch von etcd zu hoch ist, versuchen, den Snapshot-Schwellenwert mit folgender Befehlszeilenoption zu senken:

# Command line arguments:
$ etcd --snapshot-count=5000

# Environment variables:
$ ETCD_SNAPSHOT_COUNT=5000 etcd

Datenträger

Ein etcd-Cluster reagiert sehr empfindlich auf Datenträgerlatenzen. Da etcd Vorschläge dauerhaft in seinem Protokoll speichern muss, können Datenträgerzugriffe anderer Prozesse lange fsync-Latenzen verursachen. Dadurch kann etcd Heartbeats verpassen, was zu Zeitüberschreitungen bei Anfragen und zum vorübergehenden Verlust des Leaders führt. Mit hoher Priorität für Datenträgerzugriffe kann ein etcd-Server unter Umständen stabil neben diesen Prozessen laufen.

Unter Linux lässt sich die Priorität der Datenträgerzugriffe von etcd mit ionice konfigurieren:

# best effort, highest priority
$ sudo ionice -c2 -n0 -p `pgrep etcd`

Netzwerk

Wenn der etcd-Leader viele gleichzeitige Clientanfragen bedient, kann eine Netzwerküberlastung die Verarbeitung von Peer-Anfragen der Follower verzögern. Dies äußert sich auf den Follower-Knoten in Fehlermeldungen zum Sendepuffer:

dropped MsgProp to 247ae21ff9436b2d since streamMsg's sending buffer is full
dropped MsgAppResp to 247ae21ff9436b2d since streamMsg's sending buffer is full

Diese Fehler lassen sich möglicherweise beheben, indem der Peer-Verkehr von etcd gegenüber dem Clientverkehr priorisiert wird. Unter Linux kann der Peer-Verkehr mit dem Mechanismus zur Verkehrssteuerung priorisiert werden:

tc qdisc add dev eth0 root handle 1: prio bands 3
tc filter add dev eth0 parent 1: protocol ip prio 1 u32 match ip sport 2380 0xffff flowid 1:1
tc filter add dev eth0 parent 1: protocol ip prio 1 u32 match ip dport 2380 0xffff flowid 1:1
tc filter add dev eth0 parent 1: protocol ip prio 2 u32 match ip sport 2379 0xffff flowid 1:1
tc filter add dev eth0 parent 1: protocol ip prio 2 u32 match ip dport 2379 0xffff flowid 1:1

Zum Aufheben von tc Folgendes ausführen:

tc qdisc del dev eth0 root

CPU

Da etcd sehr empfindlich auf Latenz reagiert, lässt sich die Leistung unter Linux weiter optimieren, indem der CPU-Governor auf den Modus performance oder conservative gesetzt wird.

Unter Linux lässt sich der CPU-Governor auf den Modus performance setzen:

echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

11 - Interne Architektur

Discovery, Protokollierung und Go-Modulkonventionen für Mitwirkende an etcd.

11.1 - Protokoll des Discovery-Dienstes

Andere etcd-Mitglieder während der Clusterinitialisierung finden

Das Protokoll des Discovery-Dienstes hilft einem neuen etcd-Mitglied, während der Clusterinitialisierung alle anderen Mitglieder über ein gemeinsames Discovery-Token und eine Endpunktliste zu finden.

Das Protokoll des Discovery-Dienstes wird nur während der Clusterinitialisierung verwendet. Es kann nicht zur Neukonfiguration im laufenden Betrieb oder zur Clusterüberwachung genutzt werden.

Das Protokoll verwendet ein neues Discovery-Token, um einen eindeutigen etcd-Cluster zu initialisieren. Ein Discovery-Token kann nur einen etcd-Cluster repräsentieren. Sobald das Discovery-Protokoll mit diesem Token startet, darf es nicht zur Initialisierung eines anderen etcd-Clusters verwendet werden, auch wenn der Vorgang auf halbem Weg fehlschlägt.

Der Rest dieses Artikels erläutert den Discovery-Ablauf anhand von Beispielen für einen selbst betriebenen Discovery-Cluster.

Dieses Dokument behandelt ausschließlich v3-Discovery. Einzelheiten zu v2-Discovery enthält die frühere Dokumentation.

Protokollablauf

Das Discovery-Protokoll nutzt einen internen etcd-Cluster, um die Initialisierung eines neuen Clusters zu koordinieren. Zuerst kommunizieren alle neuen Mitglieder mit dem Discovery-Dienst und helfen dabei, die erwartete Mitgliederliste zu erstellen. Anschließend initialisiert jedes neue Mitglied seinen Server anhand dieser Liste. Sie erfüllt dieselbe Funktion wie die Option -initial-cluster.

Im folgenden Beispielablauf wird jeder Protokollschritt zur Veranschaulichung mit einem etcdctl-Befehl dargestellt. Dabei wird angenommen, dass unter http://example.com:2379 ein etcd-Cluster für den Discovery-Dienst läuft.

Das etcd-Discovery-Protokoll verwendet vereinbarungsgemäß das Schlüsselpräfix /_etcd/registry.

Ein neues Discovery-Token erstellen

Ein eindeutiges Token erzeugen, das den neuen Cluster identifiziert. In den folgenden Schritten dient es als eindeutiges Präfix im Discovery-Schlüsselraum. Mit uuidgen lässt es sich einfach erzeugen:

UUID=$(uuidgen)

Die erwartete Clustergröße angeben

Für das Discovery-Token muss eine Clustergröße angegeben werden. Anhand dieser Größe erkennt der Discovery-Dienst, wann er alle Mitglieder gefunden hat, die den Cluster anfänglich bilden sollen.

etcdctl --endpoints=http://example.com:2379 put /_etcd/registry/${UUID}/_config/size ${cluster_size}

Üblicherweise beträgt die Clustergröße 3, 5 oder 7. Weitere Einzelheiten enthält der Abschnitt zur optimalen Clustergröße .

etcd-Prozesse starten

Das Discovery-Token ${UUID} mit der Option --discovery-token und die Endpunkte des etcd-Clusters hinter dem Discovery-Dienst mit der Option --discovery-endpoints angeben. Damit wird v3-Discovery zur Initialisierung des etcd-Clusters aktiviert.

Wenn die Optionen --discovery-token und --discovery-endpoints angegeben sind, führt jeder etcd-Prozess intern die folgenden Schritte aus.

Wenn der Discovery-Dienst die Authentifizierung mit Client-Zertifikaten aktiviert hat, die folgenden Optionen konfigurieren. Ihre Verwendung entspricht genau der Verwendung von etcdctl zur Kommunikation mit einem etcd-Cluster.

--discovery-insecure-transport
--discovery-insecure-skip-tls-verify
--discovery-cert
--discovery-key
--discovery-cacert

Wenn der Discovery-Dienst rollenbasierte Authentifizierung aktiviert hat, die folgenden Optionen konfigurieren. Ihre Verwendung entspricht genau der Verwendung von etcdctl zur Kommunikation mit einem etcd-Cluster.

--discovery-user
--discovery-password

Die Standardwerte für Zeitintervalle und Zeitüberschreitungen können ebenfalls über die folgenden Optionen geändert werden. Ihre Verwendung entspricht genau der Verwendung von etcdctl zur Kommunikation mit einem etcd-Cluster.

--discovery-dial-timeout
--discovery-request-timeout
--discovery-keepalive-time
--discovery-keepalive-timeout

Selbstregistrierung

Zuerst registriert sich jeder etcd-Prozess als Mitglied des angegebenen neuen Clusters. Dazu legt er seine Mitglieds-ID als Schlüssel unter dem vollständigen Registrierungsschlüssel an.

etcdctl --endpoints=http://example.com:2379 put /_etcd/registry/${UUID}/members/${member_id} ${member_name}=${member_peer_url_1}&${member_name}=${member_peer_url_2}

Status prüfen

Er prüft die erwartete Clustergröße und den Registrierungsstatus und entscheidet dann über den nächsten Schritt.

etcdctl --endpoints=http://example.com:2379 get /_etcd/registry/${UUID}/_config/size
etcdctl --endpoints=http://example.com:2379 get /_etcd/registry/${UUID}/members

Wenn noch nicht genügend Mitglieder registriert sind, wartet er auf weitere Mitglieder.

Wenn die Anzahl registrierter Mitglieder die erwartete Größe N übersteigt, gelten die ersten N registrierten Mitglieder als Mitgliederliste des Clusters. Ist das Mitglied selbst in dieser Liste enthalten, ist der Discovery-Vorgang erfolgreich, und es ermittelt alle Peers anhand der Mitgliederliste. Ist es nicht enthalten, endet der Discovery-Vorgang mit der Fehlermeldung, dass der Cluster bereits voll ist.

Das Mitglied kann den Clusterstatus bereits vor seiner Registrierung prüfen. So kann es frühzeitig mit einem Fehler abbrechen, wenn der Cluster bereits voll ist.

Auf alle Mitglieder warten

Der Wartevorgang beobachtet das Schlüsselpräfix /_etcd/registry/${UUID}/members, bis alle Mitglieder gefunden sind.

etcdctl --endpoints=http://example.com:2379 watch /_etcd/registry/${UUID}/members --prefix

11.2 - Konventionen für die Protokollierung

Kategorien der Protokollierungsstufen

etcd verwendet die Bibliothek zap , um Anwendungsausgaben nach Stufen gegliedert zu protokollieren. Die Stufe einer Protokollmeldung richtet sich nach diesen Konventionen:

  • DebugLevel-Meldungen sind meist umfangreich und im Produktivbetrieb üblicherweise deaktiviert.

    • Beispiele:
      • Eine normale Nachricht an einen entfernten Peer senden
      • Einen Protokolleintrag auf den Datenträger schreiben
  • InfoLevel ist die standardmäßige Protokollierungspriorität.

    • Beispiele:
      • Startkonfiguration
      • Einen Snapshot beginnen
      • Einen neuen Knoten zum Cluster hinzufügen
      • Einen neuen Benutzer zum Authentifizierungssubsystem hinzufügen
  • WarnLevel-Meldungen sind wichtiger als Info-Meldungen, müssen aber nicht einzeln von einer Person geprüft werden.

    • Beispiele:
      • Fehler beim Senden einer Raft-Nachricht an einen entfernten Peer
      • Keine Heartbeat-Nachricht innerhalb des konfigurierten Wahlzeitlimits empfangen
  • ErrorLevel-Meldungen haben hohe Priorität. Wenn eine Anwendung störungsfrei läuft, sollte sie keine Meldungen dieser Stufe erzeugen.

    • Beispiele:
      • Fehler beim Zuweisen von Datenträgerspeicher für das WAL
  • PanicLevel protokolliert eine Meldung und löst anschließend eine Panic aus.

    • Beispiele:
      • Fehler beim Kodieren von Raft-Nachrichten
  • FatalLevel protokolliert eine Meldung und ruft anschließend os.Exit(1) auf.

    • Beispiele:
      • Fehler beim Speichern eines Raft-Snapshots

11.3 - Go-Module

Aufbau der Go-Module des etcd-Projekts

Das etcd-Projekt ist seit Version 3.5 in mehrere Go-Module gegliedert, die in einem gemeinsamen Repository liegen.

Moduldiagramm

Es gibt folgende Module:

  • go.etcd.io/etcd/api/v3 - enthält API-Definitionen (wie Protos und daraus generierte Bibliotheken), die das Kommunikationsprotokoll zwischen etcd-Clients und -Servern festlegen.

  • go.etcd.io/etcd/pkg/v3 - Sammlung von Hilfspaketen, die etcd verwendet, die jedoch nicht spezifisch für etcd sind. Ein Paket gehört nur dann hierher, wenn es künftig in ein eigenes Repository ausgelagert werden könnte. Hier sollte kein Code mit vielen eigenen Abhängigkeiten hinzugefügt werden, da diese automatisch zu Abhängigkeiten der Client-Bibliothek werden, die wir schlank halten möchten.

  • go.etcd.io/etcd/client/v3 - Client-Bibliothek für den Zugriff auf etcd über das Netzwerk (grpc). Für alle neuen Anwendungen von etcd empfohlen.

  • go.etcd.io/etcd/client/v2 - alte Client-Bibliothek für den Zugriff auf etcd über das HTTP-Protokoll. Veraltet. Alle neuen Anwendungen sollten die Bibliothek /v3 verwenden.

  • go.etcd.io/etcd/raft/v3 - Implementierung des verteilten Konsensprotokolls. Sollte keinen etcd-spezifischen Code enthalten.

  • go.etcd.io/etcd/server/v3 - etcd-Implementierung. Der Code in diesem Paket ist für den internen Gebrauch in etcd bestimmt und sollte von externen Projekten nicht verwendet werden. Der Paketaufbau und die API können sich innerhalb von Minor-Versionen ändern.

  • go.etcd.io/etcd/etcdctl/v3 - ein Befehlszeilenwerkzeug für den Zugriff auf und die Verwaltung von etcd.

  • go.etcd.io/etcd/tests/v3 - ein Modul mit allen Integrationstests von etcd. Hinweis: Alle Unit-Tests, die schnell sind und keine modulübergreifenden Abhängigkeiten benötigen, sollten in den jeweiligen Modulen beim getesteten Code liegen.

  • go.etcd.io/bbolt - Implementierung eines persistenten B-Baums. Liegt in einem separaten Repository: https://github.com/etcd-io/bbolt .

Abläufe

  1. Alle etcd-Module sollten mit denselben Versionen veröffentlicht werden, z. B. muss go.etcd.io/etcd/client/v3@v3.5.10 von go.etcd.io/etcd/api/v3@v3.5.10 abhängen.

    Die Versionen lassen sich mit folgendem Befehl einheitlich aktualisieren:

    % DRY_RUN=false TARGET_VERSION="v3.5.10" ./scripts/release_mod.sh update_versions
  2. Veröffentlichte Module sollten gemäß den Regeln unter https://golang.org/ref/mod#vcs-version mit Tags versehen werden. Jedes Modul sollte also einen eigenen Tag erhalten. Die Tags lassen sich mit folgendem Befehl setzen:

    % DRY_RUN=false REMOTE_REPO="origin" ./scripts/release_mod.sh push_mod_tags
  3. Alle etcd-Module sollten dieselben Versionen ihrer zugrunde liegenden Abhängigkeiten verwenden. Dies lässt sich folgendermaßen überprüfen:

    % PASSES="dep" ./test.sh
  4. Die go.mod-Dateien dürfen keine ungenutzten Abhängigkeiten enthalten und müssen dem Format von go mod tidy entsprechen. Dies wird folgendermaßen überprüft:

    % PASSES="mod_tidy" ./test.sh
  5. Um Aktionen über alle Module hinweg auszuführen, etwa alle Dateien automatisch zu formatieren, das folgende Skript verwenden oder erweitern:

    % ./scripts/fix.sh

Zukunft

Als langfristiges Ziel möchten wir die Entwicklung der etcd-Module hin zum folgenden Modell prüfen:

Moduldiagramm

Dies setzt Folgendes voraus:

  • etcdmigrate/etcdadm aus der etcdctl-Binärdatei ausgliedern. Dadurch würde etcdctl klar zu einer Befehlszeilenhülle für die Netzwerk-Client-API, während etcdmigrate/etcdadm direkte physische Operationen auf den Speicherdateien von etcd unterstützen würden.
  • etcd-proxy aus der Binärdatei ./etcd ausgliedern, da er mehr experimentellen Code und somit zusätzliche Risiken und Abhängigkeiten enthält.
  • Die Unterstützung des v2-Protokolls als veraltet einstufen.

12 - Grundlagen

Lernmaterialien

12.1 - Datenmodell

Verfahren zur Datenspeicherung in etcd

etcd ist darauf ausgelegt, selten aktualisierte Daten zuverlässig zu speichern und zuverlässige Watch-Abfragen bereitzustellen. etcd macht frühere Versionen von Schlüssel-Wert-Paaren zugänglich, um kostengünstige Snapshots und die Beobachtung historischer Ereignisse zu ermöglichen („Zeitreiseabfragen“). Ein persistentes Datenmodell mit Mehrversions-Nebenläufigkeitskontrolle eignet sich gut für diese Anwendungsfälle.

etcd speichert Daten in einem persistenten Schlüssel-Wert-Speicher mit mehreren Versionen. Dieser bewahrt die vorherige Version eines Schlüssel-Wert-Paars auf, wenn dessen Wert durch neue Daten ersetzt wird. Der Schlüssel-Wert-Speicher ist praktisch unveränderlich: Seine Operationen aktualisieren die Struktur nicht an Ort und Stelle, sondern erzeugen stets eine neue, aktualisierte Struktur. Alle früheren Versionen von Schlüsseln bleiben nach einer Änderung zugänglich und können beobachtet werden. Damit der Datenspeicher nicht unbegrenzt wächst und alte Versionen dauerhaft vorhält, kann er kompaktiert werden, um die ältesten Versionen ersetzter Daten zu entfernen.

Logische Sicht

Die logische Sicht auf den Speicher ist ein flacher binärer Schlüsselraum. Ein lexikalisch sortierter Index über Schlüssel aus Bytefolgen ermöglicht kostengünstige Bereichsabfragen.

Der Schlüsselraum verwaltet mehrere Revisionen. Beim Anlegen des Speichers ist die erste Revision 1. Jede atomare ändernde Operation erzeugt eine neue Revision des Schlüsselraums; eine Transaktionsoperation kann beispielsweise mehrere Operationen enthalten. Alle Daten früherer Revisionen bleiben unverändert. Alte Schlüsselversionen sind über frühere Revisionen weiterhin zugänglich. Auch die Revisionen sind indiziert, sodass Watcher effizient Revisionsbereiche durchlaufen können. Wird der Speicher zur Platzersparnis kompaktiert, werden die Revisionen vor der Kompaktierungsrevision entfernt. Revisionen steigen während der gesamten Lebensdauer eines Clusters monoton an.

Das Leben eines Schlüssels umfasst eine Generation von der Erstellung bis zur Löschung. Jeder Schlüssel kann eine oder mehrere Generationen haben. Das Anlegen eines Schlüssels erhöht seine Version, beginnend bei 1, falls der Schlüssel in der aktuellen Revision nicht existiert. Das Löschen erzeugt einen Tombstone für den Schlüssel und beendet dessen aktuelle Generation, indem seine Version auf 0 zurückgesetzt wird. Jede Änderung eines Schlüssels erhöht seine Version. Versionen steigen daher innerhalb einer Schlüsselgeneration monoton an. Bei einer Kompaktierung werden alle Generationen entfernt, die vor der Kompaktierungsrevision endeten. Auch alle vor dieser Revision gesetzten Werte außer dem jeweils neuesten werden entfernt.

Physische Sicht

etcd speichert die physischen Daten als Schlüssel-Wert-Paare in einem persistenten B+-Baum . Aus Effizienzgründen enthält jede Revision des Speicherzustands nur die Differenz zur vorherigen Revision. Einer einzelnen Revision können mehrere Schlüssel im Baum entsprechen.

Der Schlüssel eines Schlüssel-Wert-Paars ist ein 3-Tupel (major, sub, type). Major ist die Speicherrevision, die den Schlüssel enthält. Sub unterscheidet Schlüssel innerhalb derselben Revision. Type ist ein optionales Suffix für besondere Werte, etwa t, wenn der Wert einen Tombstone enthält. Der Wert des Schlüssel-Wert-Paars enthält die Änderung gegenüber der vorherigen Revision, also eine Differenz zu ihr. Der B+-Baum ist lexikalisch nach den Bytes der Schlüssel sortiert. Bereichssuchen über Revisionsdifferenzen sind schnell; so lassen sich Änderungen zwischen zwei bestimmten Revisionen rasch ermitteln. Die Kompaktierung entfernt veraltete Schlüssel-Wert-Paare.

etcd hält außerdem einen sekundären B-Baum -Index im Arbeitsspeicher, um Bereichsabfragen über Schlüssel zu beschleunigen. Die Schlüssel in diesem Index sind die für Benutzer sichtbaren Schlüssel des Speichers. Der Wert ist ein Zeiger auf die Änderung im persistenten B+-Baum. Die Kompaktierung entfernt ungültig gewordene Zeiger.

etcd ermittelt also die Revisionsinformationen aus dem B-Baum und verwendet anschließend die Revision als Schlüssel, um den Wert aus dem B+-Baum abzurufen (siehe unten).

![MVCC-Datenmodell](/docs/etcd/learning/img/data-model-figure-01.png)

12.2 - Design des etcd-Clients

Architekturentscheidungen des Clients und Details ihrer Implementierung

Design des etcd-Clients

Gyuho Lee (github.com/gyuho, Amazon Web Services, Inc.), Joe Betz (github.com/jpbetz, Google Inc.)

Einleitung

Der etcd-Server hat seine Robustheit in jahrelangen Tests mit gezielt ausgelösten Fehlern bewiesen. Die meiste komplexe Anwendungslogik übernimmt bereits der etcd-Server mit seinen Datenspeichern. Beispielsweise bleibt die Clustermitgliedschaft für Clients transparent, da die Raft-Schicht Vorschläge an den Leader weiterleitet. Auch wenn die Serverkomponenten korrekt arbeiten, erfordert ihr Zusammenspiel mit dem Client weitere komplexe Protokolle, um Korrektheit und Hochverfügbarkeit auch bei Fehlern zu gewährleisten. Idealerweise bietet der etcd-Server eine einzige logische Clustersicht auf viele physische Rechner, während der Client automatisches Failover zwischen Replikaten implementiert. Dieses Dokument beschreibt die Architekturentscheidungen des Clients und die Details ihrer Implementierung.

Glossar

clientv3: Offizieller Go-Client von etcd für die etcd-v3-API.

clientv3-grpc1.0: Offizielle Client-Implementierung mit grpc-go v1.0.x , die in der neuesten Version von etcd v3.1 verwendet wird.

clientv3-grpc1.7: Offizielle Client-Implementierung mit grpc-go v1.7.x , die in den neuesten Versionen von etcd v3.2 und v3.3 verwendet wird.

clientv3-grpc1.23: Offizielle Client-Implementierung mit grpc-go v1.23.x , die in der neuesten Version von etcd v3.4 verwendet wird.

Load-Balancer: Lastverteiler des etcd-Clients, der Wiederholungs- und Failover-Mechanismen implementiert. Der etcd-Client sollte die Last automatisch auf mehrere Endpunkte verteilen.

Endpunkte: Eine Liste von etcd-Serverendpunkten, mit denen sich Clients verbinden können. Üblicherweise sind dies 3 oder 5 Client-URLs eines etcd-Clusters.

Fest zugeordneter Endpunkt: Bei mehreren konfigurierten Endpunkten wählt der Client-Load-Balancer in Versionen <= v3.3 nur einen Endpunkt für eine TCP-Verbindung aus, um die Gesamtzahl offener Verbindungen zum etcd-Cluster gering zu halten. In v3.4 wechselt der Load-Balancer für jede Anfrage im Round-Robin-Verfahren zwischen den fest zugeordneten Endpunkten und verteilt die Last dadurch gleichmäßiger.

Client-Verbindung: Eine über gRPC Dial aufgebaute TCP-Verbindung zu einem etcd-Server.

Unterverbindung: Die gRPC-Schnittstelle SubConn. Jede Unterverbindung enthält eine Adressliste. Der Load-Balancer erstellt aus einer Liste aufgelöster Adressen eine SubConn. Eine gRPC ClientConn kann mehreren SubConn entsprechen, etwa wenn example.com auf 10.10.10.1 und 10.10.10.2 zweier Unterverbindungen aufgelöst wird. Der Load-Balancer von etcd v3.4 verwendet einen internen Resolver, um für jeden Endpunkt eine Unterverbindung aufzubauen.

Vorübergehender Verbindungsabbruch: Wenn der gRPC-Server einen Statusfehler vom Typ code Unavailable zurückgibt.

Anforderungen an den Client

Korrektheit. Bei Serverfehlern können Anfragen fehlschlagen. Konsistenzgarantien werden jedoch nie verletzt: Eigenschaften der globalen Reihenfolge, kein Schreiben beschädigter Daten, At-most-once-Semantik für ändernde Operationen, keine Beobachtung unvollständiger Ereignisse durch Watches usw.

Fortschrittsgarantie. Server können ausfallen oder kurzzeitig die Verbindung verlieren. Clients sollten in beiden Fällen Fortschritte machen. Sie sollten beim Warten auf die Rückkehr eines offline gegangenen Servers niemals dauerhaft blockieren , sofern dies nicht ausdrücklich konfiguriert ist. Idealerweise erkennen Clients nicht verfügbare Server mit HTTP/2-Pings und wechseln mit verständlichen Fehlermeldungen zu anderen Knoten.

Effizienz. Clients sollten mit minimalem Ressourcenverbrauch wirksam arbeiten: Nach einem Endpunktwechsel sollten vorherige TCP-Verbindungen geordnet geschlossen werden. Der Failover-Mechanismus sollte das nächste geeignete Replikat für eine Verbindung bestimmen, ohne Ressourcen durch wiederholte Versuche an ausgefallenen Knoten zu verschwenden.

Portierbarkeit. Der offizielle Client sollte klar dokumentiert sein, und seine Implementierung sollte sich auf Anbindungen anderer Sprachen übertragen lassen. Die Fehlerbehandlung sollte über die Sprachanbindungen hinweg konsistent sein. Da etcd vollständig auf gRPC setzt, sollte sich die Implementierung eng an den langfristigen Entwurfszielen von gRPC orientieren. Beispielsweise sollte eine austauschbare Wiederholungsrichtlinie mit gRPC-Wiederholungen kompatibel sein. Upgrades zwischen zwei Client-Versionen sollten den Betrieb nicht unterbrechen.

Client-Überblick

Der etcd-Client implementiert die folgenden Komponenten:

  • einen Load-Balancer, der gRPC-Verbindungen zu einem etcd-Cluster aufbaut,
  • einen API-Client, der RPCs an einen etcd-Server sendet, und
  • eine Fehlerbehandlung, die entscheidet, ob eine fehlgeschlagene Anfrage wiederholt oder der Endpunkt gewechselt wird.

Sprachen können sich darin unterscheiden, wie die erste Verbindung aufgebaut wird, etwa durch TLS-Konfiguration, wie Protocol-Buffer-Nachrichten kodiert und an den Server gesendet werden, wie Streaming-RPCs verarbeitet werden usw. Die vom etcd-Server zurückgegebenen Fehler sind jedoch dieselben. Entsprechend sollten auch Fehlerbehandlung und Wiederholungsrichtlinie gleich sein.

Beispielsweise kann der etcd-Server "rpc error: code = Unavailable desc = etcdserver: request timed out" zurückgeben, einen vorübergehenden Fehler, bei dem Wiederholungen erwartet werden. Oder er gibt rpc error: code = InvalidArgument desc = etcdserver: key is not provided zurück. Dies bedeutet, dass die Anfrage ungültig war und nicht wiederholt werden sollte. Der Go-Client kann Fehler mit google.golang.org/grpc/status.FromError auswerten, der Java-Client mit io.grpc.Status.fromThrowable.

clientv3-grpc1.0: Überblick über den Load-Balancer

Bei mehreren konfigurierten etcd-Endpunkten hält clientv3-grpc1.0 mehrere TCP-Verbindungen offen. Anschließend wählt er eine Adresse und sendet darüber alle Client-Anfragen. Die fest zugeordnete Adresse bleibt erhalten, bis das Client-Objekt geschlossen wird (siehe Abbildung 1). Wenn der Client einen Fehler erhält, wählt er zufällig eine andere Adresse und versucht es erneut.

client-balancer-figure-01.png

clientv3-grpc1.0: Einschränkungen des Load-Balancers

Die mehreren TCP-Verbindungen von clientv3-grpc1.0 können ein schnelleres Failover des Load-Balancers ermöglichen, benötigen aber mehr Ressourcen. Der Load-Balancer kennt weder den Zustand der Knoten noch ihre Clustermitgliedschaft. Daher kann er an einem ausgefallenen oder durch eine Netzwerkpartition abgetrennten Knoten hängen bleiben.

clientv3-grpc1.7: Überblick über den Load-Balancer

clientv3-grpc1.7 hält nur eine TCP-Verbindung zu einem ausgewählten etcd-Server offen. Bei mehreren angegebenen Clusterendpunkten versucht ein Client zunächst, sich mit allen zu verbinden. Sobald eine Verbindung steht, ordnet der Load-Balancer die Adresse fest zu und schließt die anderen Verbindungen (siehe Abbildung 2). Die Adresse soll zugeordnet bleiben, bis das Client-Objekt geschlossen wird. Ein Fehler des Servers oder des Client-Netzwerks wird an die Fehlerbehandlung des Clients weitergeleitet (siehe Abbildung 3).

client-balancer-figure-02.pngclient-balancer-figure-03.png

Die Fehlerbehandlung des Clients erhält einen Fehler vom gRPC-Server und entscheidet anhand von Fehlercode und Meldung, ob dieselbe Anfrage am selben Endpunkt wiederholt oder zu einer anderen Adresse gewechselt wird (siehe Abbildung 4 und Abbildung 5).

client-balancer-figure-04.pngclient-balancer-figure-05.png

Streaming-RPCs wie Watch und KeepAlive werden häufig ohne Zeitlimit angefordert. Stattdessen kann der Client regelmäßig HTTP/2-Pings senden, um den Zustand eines fest zugeordneten Endpunkts zu prüfen. Antwortet der Server nicht auf den Ping, wechselt der Load-Balancer zu anderen Endpunkten (siehe Abbildung 6).

client-balancer-figure-06.png

clientv3-grpc1.7: Einschränkungen des Load-Balancers

Der Load-Balancer von clientv3-grpc1.7 sendet HTTP/2-Keepalives, um Verbindungsabbrüche bei Streaming-Anfragen zu erkennen. Dieser einfache Ping-Mechanismus für gRPC-Server berücksichtigt keine Clustermitgliedschaft und kann daher Netzwerkpartitionen nicht erkennen. Da ein abgetrennter gRPC-Server weiterhin auf Client-Pings antworten kann, kann der Load-Balancer an diesem Knoten hängen bleiben. Idealerweise erkennt der Keepalive-Ping die Partition und löst vor Ablauf des Anfragezeitlimits einen Endpunktwechsel aus (siehe etcd#8673 und Abbildung 7).

client-balancer-figure-07.png

Der Load-Balancer von clientv3-grpc1.7 führt eine Liste nicht funktionsfähiger Endpunkte. Adressen mit abgebrochener Verbindung werden dieser Liste hinzugefügt und gelten bis zum Ende einer Wartezeit als nicht verfügbar. Diese Wartezeit ist fest an das Verbindungsaufbau-Zeitlimit mit einem Standardwert von 5 Sekunden gekoppelt. Der Load-Balancer kann Endpunkte fälschlich als nicht funktionsfähig einstufen. Beispielsweise kann Endpunkt A unmittelbar nach Aufnahme in die Sperrliste zurückkehren, bleibt aber dennoch für die nächsten 5 Sekunden unbenutzbar (siehe Abbildung 8).

clientv3-grpc1.0 hatte dieselben oben beschriebenen Probleme.

client-balancer-figure-08.png

Das Upstream-Projekt gRPC Go war bereits auf die neue Load-Balancer-Schnittstelle umgestiegen. So verwendet die zugrunde liegende Implementierung von clientv3-grpc1.7 den neuen gRPC-Load-Balancer und versucht dabei, das Verhalten des alten beizubehalten. Obwohl die Kompatibilität recht gut erhalten blieb, war der etcd-Client dennoch von subtilen inkompatiblen Änderungen betroffen . Zudem empfiehlt der gRPC-Maintainer, sich nicht auf die alte Load-Balancer-Schnittstelle zu stützen . Für bessere Unterstützung durch Upstream ist es generell am besten, mit den neuesten gRPC-Versionen Schritt zu halten. Neue Funktionen wie Wiederholungsrichtlinien werden möglicherweise nicht auf den gRPC-1.7-Zweig zurückportiert. Daher müssen sowohl etcd-Server als auch -Client auf die neuesten gRPC-Versionen umsteigen.

clientv3-grpc1.23: Überblick über den Load-Balancer

clientv3-grpc1.7 ist so eng an die alte gRPC-Schnittstelle gekoppelt, dass jedes Upgrade der gRPC-Abhängigkeit das Client-Verhalten beeinträchtigte. Der Großteil der Entwicklungs- und Fehlersucharbeit floss in die Behebung dieser Verhaltensänderungen. Dadurch wurde die Implementierung übermäßig komplex und beruhte auf falschen Annahmen über Serververbindungen.

Das Hauptziel von clientv3-grpc1.23 ist eine einfachere Failover-Logik des Load-Balancers. Statt eine möglicherweise veraltete Liste nicht funktionsfähiger Endpunkte zu führen, wechselt er bei jedem Verbindungsabbruch zum aktuellen Endpunkt im Round-Robin-Verfahren zum nächsten. Er trifft keine Annahmen über den Endpunktzustand. Eine komplexe Zustandsverfolgung ist daher nicht mehr nötig (siehe Abbildung 8 und die vorangehenden Erläuterungen). Ein Upgrade auf clientv3-grpc1.23 sollte problemlos sein: Alle Änderungen waren intern und bewahrten die vollständige Abwärtskompatibilität.

Bei mehreren Endpunkten erstellt clientv3-grpc1.23 intern mehrere Unterverbindungen, eine pro Endpunkt. clientv3-grpc1.7 erstellt dagegen nur eine Verbindung zu einem fest zugeordneten Endpunkt (siehe Abbildung 9). In einem Cluster mit 5 Knoten benötigt der Load-Balancer von clientv3-grpc1.23 beispielsweise 5 TCP-Verbindungen, während clientv3-grpc1.7 nur eine benötigt. Durch den erhaltenen TCP-Verbindungspool kann clientv3-grpc1.23 mehr Ressourcen verbrauchen, bietet aber eine flexiblere Lastverteilung mit besserer Failover-Leistung. Standardmäßig wird Round Robin verwendet; andere Verfahren wie „Power of Two“ oder die Auswahl des Leaders lassen sich leicht ergänzen. clientv3-grpc1.23 verwendet eine gRPC-Resolver-Gruppe und implementiert eine Auswahlrichtlinie für den Load-Balancer, um die komplexe Lastverteilung an Upstream-gRPC zu delegieren. clientv3-grpc1.7 verwaltet dagegen jede gRPC-Verbindung und das Failover selbst, was die Implementierung verkompliziert. clientv3-grpc1.23 implementiert Wiederholungen in der gRPC-Interceptor-Kette, die interne gRPC-Fehler automatisch behandelt und fortgeschrittene Wiederholungsrichtlinien wie Backoff ermöglicht. clientv3-grpc1.7 wertet gRPC-Fehler für Wiederholungen dagegen selbst aus.

client-balancer-figure-09.png

clientv3-grpc1.23: Einschränkungen des Load-Balancers

Verbesserungen sind durch Zwischenspeichern des Zustands jedes Endpunkts möglich. Beispielsweise kann der Load-Balancer vorab jeden Server anpingen, um eine Liste funktionsfähiger Kandidaten zu führen und diese Informationen beim Round-Robin-Verfahren zu nutzen. Oder er kann nach einem Verbindungsabbruch funktionsfähige Endpunkte bevorzugen. Dies kann die Implementierung verkomplizieren und deshalb in späteren Versionen behandelt werden.

Der clientseitige Keepalive-Ping berücksichtigt weiterhin keine Netzwerkpartitionen. Streaming-Anfragen können an einem abgetrennten Knoten hängen bleiben. Um die Clustermitgliedschaft zu berücksichtigen, muss ein erweiterter Health-Check-Dienst implementiert werden (Einzelheiten unter etcd#8673 ).

client-balancer-figure-07.png

Derzeit wird die Wiederholungslogik manuell als Interceptor umgesetzt. Dies kann durch offizielle gRPC-Wiederholungen vereinfacht werden.

12.3 - Design der Learner in etcd

Häufige Schwierigkeiten bei der Neukonfiguration der Clustermitgliedschaft entschärfen

Learner in etcd

Gyuho Lee (github.com/gyuho, Amazon Web Services, Inc.), Joe Betz (github.com/jpbetz, Google Inc.)

Hintergrund

Die Neukonfiguration der Clustermitgliedschaft zählt zu den größten Herausforderungen im Betrieb. Im Folgenden werden häufige Schwierigkeiten betrachtet.

1. Ein neues Clustermitglied überlastet den Leader

Ein neu beigetretenes etcd-Mitglied startet ohne Daten und fordert daher zusätzliche Aktualisierungen vom Leader an, bis es dessen Logstand erreicht hat. Dadurch kann das Netzwerk des Leaders leichter überlastet werden, sodass seine Heartbeats an Follower blockiert oder verworfen werden. In diesem Fall kann bei einem Follower das Wahlzeitlimit ablaufen und eine neue Leader-Wahl auslösen. Ein Cluster mit einem neuen Mitglied ist somit anfälliger für Leader-Wahlen. Sowohl die Wahl als auch die anschließende Übertragung der Aktualisierungen an das neue Mitglied können Zeiträume verursachen, in denen der Cluster nicht verfügbar ist (siehe Abbildung 1).

server-learner-figure-01

2. Szenarien mit Netzwerkpartitionen

Was passiert bei einer Netzwerkpartition? Das hängt von der Partition des Leaders ab. Verfügt der Leader weiterhin über ein aktives Quorum, arbeitet der Cluster weiter (siehe Abbildung 2).

server-learner-figure-02

2.1 Isolation des Leaders

Was passiert, wenn der Leader vom Rest des Clusters isoliert wird? Der Leader überwacht den Fortschritt jedes Followers. Verliert er die Verbindung zum Quorum, kehrt er in die Follower-Rolle zurück. Dies beeinträchtigt die Clusterverfügbarkeit (siehe Abbildung 3).

server-learner-figure-03

Wird einem Cluster mit 3 Knoten ein neuer Knoten hinzugefügt, steigt die Clustergröße auf 4 und die Quorumgröße auf 3. Was passiert, wenn nach dem Beitritt eines neuen Knotens eine Netzwerkpartition auftritt? Das hängt davon ab, in welcher Partition sich das neue Mitglied anschließend befindet.

2.2 Clusteraufteilung 3+1

Befindet sich der neue Knoten in derselben Partition wie der Leader, verfügt dieser weiterhin über ein aktives Quorum von 3. Es findet keine Leader-Wahl statt, und die Clusterverfügbarkeit bleibt unbeeinträchtigt (siehe Abbildung 4).

server-learner-figure-04

2.3 Clusteraufteilung 2+2

Wird der Cluster in 2 und 2 Knoten aufgeteilt, erreicht keine Partition das Quorum von 3. In diesem Fall findet eine Leader-Wahl statt (siehe Abbildung 5).

server-learner-figure-05

2.4 Quorum verloren

Was passiert, wenn zuerst eine Netzwerkpartition auftritt und danach ein neues Mitglied hinzugefügt wird? In einem partitionierten Cluster mit 3 Knoten ist bereits ein Follower abgetrennt. Wird ein neues Mitglied hinzugefügt, steigt das Quorum von 2 auf 3. Der Cluster hat nun nur 2 aktive von 4 Knoten, verliert dadurch sein Quorum und beginnt eine neue Leader-Wahl (siehe Abbildung 6).

server-learner-figure-06

Da das Hinzufügen eines Mitglieds die Quorumgröße ändern kann, wird beim Ersetzen eines nicht funktionsfähigen Knotens stets empfohlen, zuerst „member remove“ auszuführen.

Das Hinzufügen eines neuen Mitglieds zu einem Cluster mit 1 Knoten erhöht die Quorumgröße auf 2. Sobald der bisherige Leader feststellt, dass das Quorum nicht aktiv ist, löst dies unmittelbar eine Leader-Wahl aus. Der Grund: „member add“ ist ein Vorgang mit 2 Schritten, bei dem der Benutzer zuerst den Befehl „member add“ ausführen und anschließend den Prozess des neuen Knotens starten muss (siehe Abbildung 7).

server-learner-figure-07

3. Fehlkonfigurationen des Clusters

Noch problematischer ist ein falsch konfiguriertes hinzugefügtes Mitglied. Die Neukonfiguration der Mitgliedschaft besteht aus zwei Schritten: „etcdctl member add“ und dem Start eines etcd-Serverprozesses mit der angegebenen Peer-URL. Der Befehl „member add“ wird also unabhängig von der URL angewendet, selbst wenn diese ungültig ist. Werden im ersten Schritt ungültige URLs verwendet, kann der zweite Schritt den neuen etcd-Prozess nicht einmal starten. Sobald der Cluster sein Quorum verliert, lässt sich die Mitgliedschaftsänderung nicht mehr rückgängig machen (siehe Abbildung 8).

server-learner-figure-08

Dasselbe gilt für einen Cluster mit mehreren Knoten. Beispielsweise hat der Cluster zwei nicht verfügbare Mitglieder, eines ausgefallen und eines falsch konfiguriert, sowie zwei aktive Mitglieder. Er benötigt nun aber mindestens 3 Stimmen, um die Clustermitgliedschaft zu ändern (siehe Abbildung 9).

server-learner-figure-09

Wie gezeigt, kann eine einfache Fehlkonfiguration den gesamten Cluster funktionsunfähig machen. In diesem Fall muss ein Betreiber den Cluster manuell mit der Option etcd --force-new-cluster neu erstellen. Da etcd für Kubernetes zu einem betriebskritischen Dienst geworden ist, können selbst kürzeste Ausfälle erhebliche Auswirkungen auf Benutzer haben. Wie lassen sich solche etcd-Operationen vereinfachen? Besonders entscheidend für die Clusterverfügbarkeit ist die Leader-Wahl: Lässt sich die Neukonfiguration der Mitgliedschaft weniger störend gestalten, indem die Quorumgröße unverändert bleibt? Kann ein neuer Knoten zunächst inaktiv bleiben und nur die nötigsten Aktualisierungen vom Leader anfordern, bis er aufgeholt hat? Lassen sich Fehlkonfigurationen der Mitgliedschaft immer rückgängig machen und sicherer behandeln, sodass ein falscher Befehl zum Hinzufügen eines Mitglieds niemals den Cluster ausfallen lässt? Sollte ein Benutzer beim Hinzufügen eines Mitglieds die Netzwerktopologie berücksichtigen müssen? Kann die API zum Hinzufügen von Mitgliedern unabhängig von der Lage der Knoten und bestehenden Netzwerkpartitionen funktionieren?

Raft-Learner

Um die im vorigen Abschnitt beschriebenen Verfügbarkeitslücken zu verringern, führt Raft §4.2.1 den neuen Knotenzustand „Learner“ ein. Ein solcher Knoten tritt dem Cluster als nicht stimmberechtigtes Mitglied bei, bis er den Logstand des Leaders erreicht hat.

Funktionen in v3.4

Ein Betreiber sollte möglichst wenig Aufwand haben, um einen neuen Learner-Knoten hinzuzufügen. Der Befehl member add --learner fügt einen Learner hinzu, der als nicht stimmberechtigtes Mitglied beitritt, aber dennoch alle Daten vom Leader empfängt (siehe Abbildung 10).

server-learner-figure-10

Hat ein Learner den Fortschritt des Leaders eingeholt, kann er über die API member promote zu einem stimmberechtigten Mitglied hochgestuft werden und zählt dann zum Quorum (siehe Abbildung 11).

server-learner-figure-11

Der etcd-Server validiert die Hochstufungsanfrage, um einen sicheren Betrieb zu gewährleisten. Erst wenn sein Log den Stand des Leaders erreicht hat, kann ein Learner zu einem stimmberechtigten Mitglied hochgestuft werden (siehe Abbildung 12).

server-learner-figure-12

Bis zur Hochstufung dient ein Learner nur als Standby-Knoten: Die Führungsrolle kann ihm nicht übertragen werden. Ein Learner lehnt Lese- und Schreibanfragen von Clients ab; der Client-Load-Balancer sollte keine Anfragen an ihn weiterleiten. Daher muss ein Learner keine Read-Index-Anfragen an den Leader senden. Diese Einschränkung vereinfacht die erste Learner-Implementierung in v3.4 (siehe Abbildung 13).

server-learner-figure-13

Außerdem begrenzt etcd die Gesamtzahl der Learner in einem Cluster, um eine Überlastung des Leaders durch Logreplikation zu vermeiden. Ein Learner stuft sich niemals selbst hoch. etcd liefert Statusinformationen über Learner und Sicherheitsprüfungen; die endgültige Entscheidung über eine Hochstufung muss jedoch der Clusterbetreiber treffen.

Vorgeschlagene Funktionen für künftige Versionen

Learner als einzigen Anfangszustand und Standard festlegen: Wird der Anfangszustand neuer Mitglieder auf Learner gesetzt, erhöht dies die Sicherheit der Mitgliedschaftsneukonfiguration erheblich, da Learner die Quorumgröße nicht verändern. Fehlkonfigurationen lassen sich dann immer rückgängig machen, ohne das Quorum zu verlieren.

Die Hochstufung zum stimmberechtigten Mitglied vollständig automatisieren: Sobald ein Learner den Logstand des Leaders erreicht hat, kann der Cluster ihn automatisch hochstufen. Der Benutzer legt bestimmte von etcd benötigte Schwellenwerte fest. Sind die Anforderungen erfüllt, stuft sich der Learner selbst zu einem stimmberechtigten Mitglied hoch. Aus Benutzersicht würde „member add“ wie bisher funktionieren, aber dank der Learner-Funktion mehr Sicherheit bieten.

Learner als Standby-Knoten für Failover verwenden: Ein Learner tritt als Standby-Knoten bei und wird automatisch hochgestuft, wenn die Clusterverfügbarkeit beeinträchtigt ist.

Learner nur für Lesezugriffe verwenden: Ein Learner kann als ausschließlich lesender Knoten dienen, der nie hochgestuft wird. In einem Modus mit schwacher Konsistenz empfängt er nur Daten vom Leader und verarbeitet keine Schreibvorgänge. Lokale Lesezugriffe ohne Konsensaufwand würden die Last des Leaders erheblich verringern, können aber veraltete Daten liefern. In einem Modus mit starker Konsistenz fordert der Learner einen Leseindex vom Leader an, um die neuesten Daten bereitzustellen, lehnt Schreibvorgänge aber weiterhin ab.

Learner und Mirror Maker im Vergleich

etcd implementiert „mirror maker“ mit der Watch-API, um Schlüsselerstellungen und -aktualisierungen fortlaufend an einen separaten Cluster weiterzuleiten. Nach Abschluss der anfänglichen Synchronisierung verursacht die Spiegelung gewöhnlich nur geringe zusätzliche Latenz. Learner und Spiegelung überschneiden sich darin, dass beide vorhandene Daten für reine Lesezugriffe replizieren können. Die Spiegelung garantiert jedoch keine Linearisierbarkeit. Bei Netzwerkunterbrechungen können frühere Schlüssel-Wert-Paare bereits verworfen worden sein, und von Clients wird erwartet, die Watch-Antworten auf korrekte Reihenfolge zu prüfen. Eine Spiegelung bietet daher keine Reihenfolgegarantie. Spiegelung eignet sich für minimale Latenz, etwa zwischen Rechenzentren, auf Kosten der Konsistenz. Learner eignen sich, um alle historischen Daten und deren Reihenfolge zu erhalten.

Anhang: Learner-Implementierung in v3.4

Den Knotentyp “Learner” in der API “MemberAdd” verfügbar machen.

Der etcd-Client ergänzt die API „MemberAdd“ um eine Option für Learner-Knoten. Der Server-Handler von etcd wendet einen Mitgliedschaftsänderungseintrag vom Typ pb.ConfChangeAddLearnerNode an. Nach Anwendung des Befehls tritt ein Server mit der Option etcd --initial-cluster-state=existing dem Cluster bei. Dieser Learner-Knoten ist weder stimmberechtigt noch zählt er zum Quorum.

Der etcd-Server darf die Führungsrolle keinem Learner übertragen, da dieser noch zurückliegen kann und nicht zum Quorum zählt. Der etcd-Server begrenzt die Anzahl der Learner pro Cluster auf einen: Je mehr Learner vorhanden sind, desto mehr Daten muss der Leader verteilen. Clients können mit einem Learner-Knoten kommunizieren, dieser lehnt jedoch alle Anfragen außer serialisierbaren Lesezugriffen und der API für den Mitgliedsstatus ab. Das vereinfacht die erste Implementierung. Künftig kann ein Learner zu einem ausschließlich lesenden Server erweitert werden, der Clusterdaten fortlaufend spiegelt. Der Client-Load-Balancer muss eine Hilfsfunktion bereitstellen, um den Endpunkt eines Learner-Knotens auszuschließen. Andernfalls können Anfragen an den Learner fehlschlagen. Der Client-Aufruf zur Mitgliedersynchronisierung sollte den Knotentyp Learner berücksichtigen, ebenso der Aufruf zur Aktualisierung der Client-Endpunkte.

Die Antworten von MemberList und MemberStatus sollten angeben, welcher Knoten ein Learner ist.

Die API “MemberPromote” hinzufügen.

Raft-intern stuft ein zweiter MemberAdd-Aufruf für den Learner-Knoten diesen zu einem stimmberechtigten Mitglied hoch. Der Leader verwaltet den Fortschritt jedes Followers und Learners. Hat der Learner die Verarbeitung seiner Snapshot-Nachricht noch nicht abgeschlossen, wird die Hochstufungsanfrage abgelehnt. Sie wird genau dann angenommen, wenn der Learner-Knoten funktionsfähig ist und mit dem Leader synchron ist oder die Differenz innerhalb des Schwellenwerts liegt. Beispielsweise muss die Zahl der an den Learner zu replizierenden Einträge unter 1/10 der Snapshot-Anzahl liegen; damit ist es weniger wahrscheinlich, dass der Leader selbst nach der Hochstufung einen Snapshot an den Learner senden müsste. Diese gesamte Logik ist im Paket etcdserver fest codiert und nicht konfigurierbar.

Referenzen

12.4 - Authentifizierungsdesign von etcd v3

Authentifizierung in etcd v3

Warum das Authentifizierungssystem von v2 nicht wiederverwenden?

Das v3-Protokoll verwendet gRPC als Transport anstelle einer RESTful-Schnittstelle wie in v2. Das neue Protokoll bietet die Gelegenheit, den Entwurf von v2 weiterzuentwickeln und zu verbessern. Beispielsweise authentifiziert v3 pro Verbindung, während die langsamere Authentifizierung in v2 pro Anfrage erfolgt. Zudem erschwert die Semantik der v2-Authentifizierung in der Praxis Überlegungen zur Konsistenz, wie die nächsten Abschnitte erläutern. Für v3 gibt es eine klar definierte Beschreibung und Implementierung des Authentifizierungsmechanismus, die die Schwächen des v2-Systems behebt.

Funktionale Anforderungen

  • Authentifizierung pro Verbindung statt pro Anfrage
    • Auf Benutzer-ID und Passwort basierende Authentifizierung für die gRPC-API
    • Die Authentifizierung muss nach Änderungen der Authentifizierungsrichtlinie erneuert werden
  • Die Funktionalität sollte so einfach und nützlich sein wie in v2
    • v3 bietet einen flachen Schlüsselraum statt der Verzeichnisstruktur von v2. Berechtigungen werden durch Intervallabgleich geprüft.
  • Sie sollte stärkere Konsistenzgarantien als die v2-Authentifizierung bieten

Wesentliche erforderliche Änderungen

  • Ein Client muss vor dem Senden authentifizierter Anfragen eine eigene Verbindung ausschließlich zur Authentifizierung aufbauen
  • Berechtigungsinformationen (Benutzer-ID und autorisierte Revision) zu den Raft-Befehlen (etcdserverpb.InternalRaftRequest) hinzufügen
  • Die Berechtigungen jeder Anfrage werden in der Zustandsmaschinenschicht statt in der API-Schicht geprüft

Konsistenz der Berechtigungsmetadaten

Die Authentifizierungsmetadaten sollten wie andere Daten in etcd im Speicher abgelegt und verwaltet werden, den das Raft-Protokoll von etcd kontrolliert. Das ist erforderlich, um Verfügbarkeit und Konsistenz des gesamten etcd-Clusters zu erhalten. Wenn das Lesen oder Schreiben der Metadaten, etwa von Berechtigungsinformationen, die Zustimmung jedes Knotens und damit mehr als ein Quorum benötigt, kann der Ausfall eines einzelnen Knotens den gesamten Cluster anhalten. Müssen alle Knoten gleichzeitig zustimmen, lässt sich die Prüfung gewöhnlicher Lese- und Schreibanfragen nicht abschließen, sobald ein Clustermitglied ausfällt, selbst wenn noch ein Quorum verfügbar ist. Dieses Einstimmigkeitsverfahren verschlechtert letztlich die Clusterverfügbarkeit. Der auf einem Quorum basierende Raft-Konsens sollte ausreichen, da die Übereinstimmung aus einer konsistenten Reihenfolge folgt.

Der Authentifizierungsmechanismus des etcd-v2-Protokolls hat eine problematische Eigenschaft: Die Metadatenkonsistenz sollte wie oben beschrieben funktionieren, tut es aber nicht. Jede Berechtigungsprüfung wird von dem etcd-Mitglied durchgeführt, das die Client-Anfrage empfängt (server/etcdserver/api/v2http/client.go), einschließlich Follower-Mitgliedern. Die Prüfung kann daher auf veralteten Metadaten beruhen.

Aufgrund dieser möglichen Veraltung wird die Authentifizierungskonfiguration nicht zwingend wirksam, sobald Betreiber etcdctl ausführen. Es lässt sich daher nicht feststellen, wie lange veraltete Metadaten noch gelten. In der Praxis wird die Konfigurationsänderung unmittelbar nach der Befehlsausführung wirksam. Unter hoher Last kann der inkonsistente Zustand jedoch länger anhalten und für Benutzer und Entwickler unerwartete Situationen verursachen. Dafür ist eine Umgehungslösung wie diese erforderlich.

Inkonsistente Berechtigungen gefährden linearisierte Anfragen

Ein inkonsistenter Authentifizierungszustand ist bei Schreibvorgängen am schwerwiegendsten. Selbst wenn ein Betreiber einem Benutzer das Schreiben verbietet, kann ein Schreibvorgang erfolgreich abgeschlossen werden, sofern seine Reihenfolge nur gegenüber dem Schlüssel-Wert-Speicher, nicht aber gegenüber dem Authentifizierungssystem festgelegt ist. Ohne eine Reihenfolge über Authentifizierungsspeicher und Schlüssel-Wert-Speicher hinweg ist das System für Angriffe mit veralteten Berechtigungen anfällig.

Deshalb sollte die Berechtigungsprüfung in die Zustandsmaschine von etcd aufgenommen werden. Jede Zustandsmaschine sollte Anfragen in der Apply-Phase anhand ihrer Berechtigungsinformationen prüfen. Die Authentifizierungsinformationen dürfen dabei nicht veraltet sein.

Entwurf und Implementierung

Authentifizierung

Zunächst muss ein Client eine gRPC-Verbindung ausschließlich zur Authentifizierung seiner Benutzer-ID und seines Passworts aufbauen. Ein etcd-Server antwortet bei Erfolg mit einem Authentifizierungstoken, bei Fehlschlag mit einem Fehler. Der Client kann das Token verwenden, um sich bei API-Anfragen gegenüber etcd auszuweisen.

Die Client-Verbindung, über die das Authentifizierungstoken angefordert wurde, wird üblicherweise verworfen; sie kann die Anmeldedaten des neuen Tokens nicht übertragen. gRPC bietet nämlich keine Möglichkeit, nach dem Verbindungsaufbau durch grpc.Dial() Anmeldedaten pro RPC hinzuzufügen. Ein Client kann einer Verbindung daher kein Token zuweisen, das er über diese Verbindung erhalten hat. Zur Verwendung des Tokens benötigt er eine neue Verbindung.

Hinweise zur Implementierung des RPC Authenticate()

Der RPC Authenticate() erzeugt anhand eines angegebenen Benutzernamens und Passworts ein Authentifizierungstoken. etcd verwendet das Go-Paket bcrypt, um ein konfiguriertes Passwort zu speichern und ein angegebenes Passwort dagegen zu prüfen. Die Passwortprüfung von bcrypt ist absichtlich rechenaufwendig und dauert auf einem gewöhnlichen x64-Server fast 100ms. Diese Prüfung in der Apply-Phase der Zustandsmaschine würde daher Leistungsprobleme verursachen: Der gesamte etcd-Cluster könnte nur knapp 10 Authenticate()-Anfragen pro Sekunde verarbeiten.

Aus Leistungsgründen prüft der v3-Authentifizierungsmechanismus Passwörter in der API-Schicht von etcd, wo dies außerhalb von Raft parallelisiert werden kann. Dadurch können jedoch Berechtigungslücken zwischen Prüf- und Verwendungszeitpunkt entstehen (Time-of-check/Time-of-use, TOCTOU):

  1. Client A sendet eine Anfrage Authenticate()
  2. Die API-Schicht führt die Passwortprüfung von Authenticate() aus
  3. Ein anderer Client B sendet eine Anfrage ChangePassword(), die der Server abschließt
  4. Die Zustandsmaschinenschicht ermittelt die Revisionsnummer für Authenticate() von A
  5. Der Server meldet A Erfolg
  6. A ist nun mit einem veralteten Passwort authentifiziert

Um diese Situation zu vermeiden, führt die API-Schicht eine Validierung der Versionsnummer anhand der Revisionsnummer des Authentifizierungsspeichers durch. Während der Passwortprüfung speichert sie dessen Revisionsnummer. Nach erfolgreicher Prüfung vergleicht sie die gespeicherte mit der neuesten Revisionsnummer. Unterscheiden sich die Nummern, wurden die Authentifizierungsmetadaten zwischenzeitlich aktualisiert, und die Prüfung wird wiederholt. Dieser Mechanismus verhindert eine erfolgreiche Prüfung anhand eines veralteten Passworts.

Ein Token in der API-Schicht auflösen

Nach der Authentifizierung mit Authenticate() kann ein Client wie ohne Authentifizierung eine gRPC-Verbindung aufbauen. Zusätzlich zum bestehenden Initialisierungsablauf muss er das Token der neu erstellten Verbindung zuordnen. grpc.WithPerRPCCredentials() bietet die dafür erforderliche Funktion.

Jede authentifizierte Client-Anfrage enthält ein Token. Serverseitig lässt es sich mit grpc.metadata.FromIncomingContext() abrufen. Der Server kann daraus ermitteln, wer die Anfrage stellt und wann der Benutzer autorisiert wurde. Die API-Schicht trägt diese Informationen in den Header (etcdserverpb.RequestHeader.Username und etcdserverpb.RequestHeader.AuthRevision) eines Raft-Logeintrags (etcdserverpb.InternalRaftRequest) ein.

Berechtigungen in der Zustandsmaschine prüfen

Die Authentifizierungsinformationen in etcdserverpb.RequestHeader werden in der Apply-Phase der Zustandsmaschine geprüft. Dabei wird anhand der neuesten Revision des Authentifizierungsspeichers geprüft, ob der Benutzer Zugriff auf die angeforderten Schlüssel hat.

Zwei Token-Typen: simple und JWT

Es gibt zwei Token-Typen: simple und JWT. Das simple-Token ist nicht für den Produktivbetrieb vorgesehen. Diese Token sind nicht kryptografisch signiert, und die Server müssen die Zuordnung zwischen Token und Benutzern als Zustand verwalten. Sie sind für Entwicklungstests gedacht. Für produktive Bereitstellungen sollten JWT-Token verwendet werden, da sie kryptografisch signiert und geprüft werden. Aus Implementierungssicht ist JWT zustandslos. Ein JWT-Token kann Metadaten wie Benutzernamen und Revision enthalten, sodass Server die Zuordnung zwischen Token und Metadaten nicht speichern müssen.

Warnung

Für simple-Token ist das Problem #18437 bekannt. Auf etcd-Servern werden Token in der API-Schicht aufgelöst, und simple-Token sind zustandsbehaftet. Der Vorgang ist nicht durch eine linearisierbare Prüfung geschützt. Daher kann ein etcd-Mitglied die vorherige Authentifizierungsanfrage noch nicht vollständig verarbeitet haben, wenn die nächste eintrifft. In diesem Fall kann es dem Client den Fehler “invalid auth token” zurückgeben. Auf einem Knoten mit guten Netzwerkbedingungen tritt dieses Problem gewöhnlich selten auf; bei hoher Latenz ist es jedoch möglich. Als Umgehungslösung können Anwendungen bei diesem Fehler einen Wiederholungsmechanismus einsetzen.

JWT-Token direkt setzen

Zusätzlich zum Standardablauf über den RPC Authenticate() unterstützt etcd das direkte Setzen von JWT-Token auf Client-Ebene. Dadurch können Anwendungen den gesamten Lebenszyklus von JWT-Token außerhalb von etcd verwalten, einschließlich Erzeugung, Validierung und Rotation.

Anwendungsfall und Ablauf

Dieser Ansatz ist sinnvoll, wenn:

  • Ein separates Token-Verwaltungssystem außerhalb von etcd die Erzeugung und den Lebenszyklus der JWT-Token übernimmt
  • Anwendungen bereits signierte JWT-Token über einen externen Mechanismus erhalten, etwa Umgebungsvariablen oder einen Konfigurationsdienst
  • Der Token-Lebenszyklus vollständig von der Client-Anwendung statt durch die automatische Token-Erzeugung von etcd verwaltet werden muss

Der typische Ablauf ist:

  1. Eine externe Instanz außerhalb von etcd erzeugt ein signiertes JWT-Token, das den Benutzernamen und weitere Claims enthält
  2. Die Anwendung erhält das signierte Token und konfiguriert damit den etcd-Client
  3. Der Client sendet das JWT-Token direkt mit den Anfragen, ohne Authenticate() aufzurufen
  4. Der etcd-Server prüft die Token-Signatur mit seinem konfigurierten öffentlichen Schlüssel und gewährt Zugriff anhand des Benutzernamens im Token
  5. Vor Ablauf des Tokens ruft die Anwendung ein neues Token von der externen Instanz ab
  6. Die Anwendung erstellt einen neuen Client mit dem aktualisierten Token; Token-Aktualisierungen erfordern eine Neuerstellung des Clients

Unterschiede zur Standardauthentifizierung

Beim Standardablauf mit Authenticate():

  • Der Client ruft Authenticate() mit Benutzername und Passwort auf
  • etcd erzeugt ein Token und gibt es zurück
  • Der Client verwendet dieses Token automatisch für nachfolgende Anfragen
  • Zum Erneuern des Tokens muss Authenticate() erneut aufgerufen werden

Beim direkten Setzen von JWT-Token:

  • Der Client wird mit einem bereits signierten JWT-Token initialisiert
  • Der Client ruft Authenticate() nicht auf
  • Das Token wird direkt in allen Anfragen verwendet
  • Die Client-Anwendung ist dafür verantwortlich, vor Ablauf neue Token zu beschaffen und den Lebenszyklus des Clients zu verwalten

AuthStatus ohne gültiges Token

Um Anwendungen mit eigener JWT-Token-Verwaltung zu unterstützen, ermöglicht der RPC AuthStatus Clients festzustellen, ob die Authentifizierung aktiviert ist, und die aktuelle authRevision abzurufen. Das ist für Wiederherstellungsszenarien wichtig, in denen ein Token abgelaufen ist und der Client die neueste Revision benötigt, um von seinem externen Token-Anbieter ein neues gültiges Token zu erhalten.

Ohne diese Möglichkeit könnte ein abgelaufenes Token verhindern, dass ein Client die aktuelle authRevision ermittelt. Dies könnte zu einer Blockade führen, in der kein neues Token erzeugt werden kann.

Unterschiede zwischen KVS-Modellen und Dateisystemmodellen

etcd v3 ist ein KVS und kein Dateisystem. Daher können Benutzern Berechtigungen für einen exakten Schlüsselnamen oder einen Schlüsselbereich wie ["start key", "end key") erteilt werden. Berechtigungen für nicht vorhandene Schlüssel sind somit möglich. Benutzer sollten auf unbeabsichtigt erteilte Berechtigungen achten. In dateisystemähnlichen Systemen wie Chubby oder ZooKeeper kann eine inode-ähnliche Datenstruktur die Berechtigungsinformationen enthalten. Dort können keine Berechtigungen für nicht vorhandene Schlüssel erteilt werden, abgesehen vom Fall der Sticky Bits.

Anders als dateisystemähnliche Systeme erfordert das Modell von etcd v3 mehrere Metadatenabfragen. Im ungünstigsten Fall entspricht der Suchaufwand der Summe aller Schlüssel und Intervalle, für die der Benutzer Berechtigungen hat. Dieser Aufwand lässt sich nicht vermeiden, weil sich der flache Schlüsselraum von v3 grundlegend vom Unix-Dateisystemmodell unterscheidet, bei dem jeder inode Berechtigungsmetadaten enthält. In der Praxis ist der Aufwand kein ernstes Problem, da die Metadaten klein genug sind, um vom Caching zu profitieren.

12.5 - etcd-API

Überblick über den grundlegenden Entwurf der etcd-API

Dieses Dokument gibt einen Überblick über den grundlegenden Entwurf der etcd-v3-APIs. Diese sind nicht mit der etcd-v2-API zu verwechseln, die seit etcd v3.5 veraltet ist. Der Überblick ist keineswegs vollständig. Er konzentriert sich auf die Grundideen, die zum Verständnis von etcd nötig sind, ohne durch seltenere API-Aufrufe abzulenken. Alle etcd-APIs sind in gRPC-Diensten definiert, die die vom etcd-Server verstandenen Remote Procedure Calls (RPCs) nach Funktionen gliedern. Eine vollständige Liste aller etcd-RPCs ist in Markdown in der gRPC-API-Übersicht dokumentiert.

gRPC-Dienste

Jede API-Anfrage an einen etcd-Server ist ein gRPC-Remote-Procedure-Call. Die RPCs von etcd werden nach ihrer Funktion in Dienste eingeteilt.

Für die Arbeit mit dem Schlüsselraum von etcd sind folgende Dienste wichtig:

  • KV - Erstellt, aktualisiert, liest und löscht Schlüssel-Wert-Paare.
  • Watch - Überwacht Änderungen an Schlüsseln.
  • Lease - Grundoperationen zum Verarbeiten von Keepalive-Nachrichten der Clients.

Den Cluster selbst verwalten folgende Dienste:

  • Auth - Rollenbasierter Authentifizierungsmechanismus zur Authentifizierung von Benutzern.
  • Cluster - Liefert Mitgliedschaftsinformationen und Konfigurationsfunktionen.
  • Maintenance - Erstellt Snapshots für die Wiederherstellung, defragmentiert den Speicher und liefert Statusinformationen pro Mitglied.

Anfragen und Antworten

Alle RPCs in etcd folgen demselben Format. Jeder RPC hat eine Funktion Name, die NameRequest als Argument entgegennimmt und NameResponse als Antwort zurückgibt. Beispielsweise lautet die Beschreibung des RPC Range:

service KV {
  Range(RangeRequest) returns (RangeResponse)
  ...
}

Antwortheader

Alle Antworten der etcd-API enthalten einen Antwortheader mit Clustermetadaten zur Antwort:

message ResponseHeader {
  uint64 cluster_id = 1;
  uint64 member_id = 2;
  int64 revision = 3;
  uint64 raft_term = 4;
}
  • Cluster_ID - Die ID des Clusters, der die Antwort erzeugt.
  • Member_ID - Die ID des Mitglieds, das die Antwort erzeugt.
  • Revision - Die Revision des Schlüssel-Wert-Speichers beim Erzeugen der Antwort.
  • Raft_Term - Der Raft-Term des Mitglieds beim Erzeugen der Antwort.

Eine Anwendung kann das Feld Cluster_ID oder Member_ID lesen, um sicherzustellen, dass sie mit dem beabsichtigten Cluster beziehungsweise Mitglied kommuniziert.

Anwendungen können über das Feld Revision die neueste Revision des Schlüssel-Wert-Speichers ermitteln. Das ist besonders nützlich, wenn sie eine historische Revision für eine Zeitreiseabfrage angeben und die zum Anfragezeitpunkt neueste Revision kennen möchten.

Mit Raft_Term können Anwendungen erkennen, wann der Cluster eine neue Leader-Wahl abgeschlossen hat.

Schlüssel-Wert-API

Die Schlüssel-Wert-API bearbeitet die in etcd gespeicherten Schlüssel-Wert-Paare. Der Großteil der Anfragen an etcd sind üblicherweise Schlüssel-Wert-Anfragen.

Grundoperationen des Systems

Schlüssel-Wert-Paar

Ein Schlüssel-Wert-Paar ist die kleinste Einheit, die die Schlüssel-Wert-API bearbeiten kann. Jedes Paar hat mehrere Felder, die im Protobuf-Format definiert sind:

message KeyValue {
  bytes key = 1;
  int64 create_revision = 2;
  int64 mod_revision = 3;
  int64 version = 4;
  bytes value = 5;
  int64 lease = 6;
}
  • Key - Schlüssel als Bytes. Ein leerer Schlüssel ist nicht zulässig.
  • Value - Wert als Bytes.
  • Version - Version ist die Version des Schlüssels. Eine Löschung setzt sie auf null zurück, und jede Änderung des Schlüssels erhöht sie.
  • Create_Revision - Revision der letzten Erstellung des Schlüssels.
  • Mod_Revision - Revision der letzten Änderung des Schlüssels.
  • Lease - Die ID der dem Schlüssel zugeordneten Lease. Ist lease 0, ist dem Schlüssel keine Lease zugeordnet.

Zusätzlich zu Schlüssel und Wert fügt etcd der Schlüsselnachricht Revisionsmetadaten hinzu. Diese Informationen ordnen Schlüssel nach Erstellungs- und Änderungszeitpunkt, was für die Nebenläufigkeitskontrolle bei verteilter Synchronisierung nützlich ist. Die verteilten gemeinsamen Sperren des etcd-Clients verwenden die Erstellungsrevision, um auf den Besitz einer Sperre zu warten. Entsprechend dient die Änderungsrevision dazu, Konflikte in der Lesemenge von Software Transactional Memory zu erkennen und auf Aktualisierungen bei der Leader-Wahl zu warten.

Revisionen

etcd verwaltet einen clusterweiten 64-Bit-Zähler, die Speicherrevision, der bei jeder Änderung des Schlüsselraums erhöht wird. Die Revision dient als globale logische Uhr und ordnet alle Speicheraktualisierungen sequenziell. Die durch eine neue Revision repräsentierte Änderung ist inkrementell: Einer Revision sind die Daten zugeordnet, die den Speicher geändert haben. Intern bedeutet eine neue Revision, die Änderungen mit der erhöhten Revision als Schlüssel in den B+-Baum des Backends zu schreiben.

Besonders nützlich sind Revisionen im Backend mit Mehrversions-Nebenläufigkeitskontrolle von etcd. Das MVCC-Modell erlaubt eine Sicht auf den Schlüssel-Wert-Speicher aus früheren Revisionen, da historische Schlüsselrevisionen erhalten bleiben. Clusteradministratoren können die Aufbewahrungsrichtlinie für diesen Verlauf zur gezielten Speicherverwaltung konfigurieren. Üblicherweise verwirft etcd alte Schlüsselrevisionen zeitgesteuert. Ein typischer etcd-Cluster bewahrt ersetzte Schlüsseldaten mehrere Stunden auf. Das ermöglicht auch die zuverlässige Behandlung langer Client-Verbindungsunterbrechungen statt nur kurzer Netzwerkausfälle: Watcher setzen einfach ab der letzten beobachteten historischen Revision fort. Ebenso können Leseanfragen mit einer Revision versehen werden, um Schlüssel aus der Sicht des Schlüsselraums zu dem Zeitpunkt zurückzugeben, an dem diese Revision bestätigt wurde.

Schlüsselbereiche

Das Datenmodell von etcd indiziert alle Schlüssel in einem flachen binären Schlüsselraum. Es unterscheidet sich damit von anderen Schlüssel-Wert-Speichern, die Schlüssel hierarchisch in Verzeichnissen organisieren. Schlüssel werden über Schlüsselintervalle [a, b) statt nach Verzeichnissen aufgelistet.

Diese Intervalle werden in etcd häufig als Bereiche bezeichnet. Bereichsoperationen sind leistungsfähiger als Verzeichnisoperationen. Wie ein hierarchischer Speicher unterstützen Intervalle einzelne Schlüsselabfragen über [a, a+1), etwa [‘a’, ‘a\x00’) zum Abrufen von ‘a’, und Verzeichnisabfragen durch Kodierung der Schlüssel nach Verzeichnistiefe. Darüber hinaus können Intervalle auch Präfixe abbilden: Das Intervall ['a', 'b') ruft beispielsweise alle Schlüssel mit dem Präfix ‘a’ ab.

Vereinbarungsgemäß werden Bereiche einer Anfrage durch die Felder key und range_end angegeben. Das Feld key ist der erste Schlüssel des Bereichs und sollte nicht leer sein. range_end ist der Schlüssel nach dem letzten Schlüssel des Bereichs. Ist range_end nicht angegeben oder leer, enthält der Bereich nur das Argument key. Ist range_end gleich key plus eins, etwa “aa”+1 == “ab” oder “a\xff”+1 == “b”, umfasst der Bereich alle Schlüssel mit dem Präfix key. Sind key und range_end beide ‘\0’, umfasst der Bereich alle Schlüssel. Ist range_end ‘\0’, umfasst der Bereich alle Schlüssel größer oder gleich dem Argument key.

Range

Schlüssel werden mit dem API-Aufruf Range aus dem Schlüssel-Wert-Speicher abgerufen. Er nimmt eine RangeRequest entgegen:

message RangeRequest {
  enum SortOrder {
	NONE = 0; // default, no sorting
	ASCEND = 1; // lowest target value first
	DESCEND = 2; // highest target value first
  }
  enum SortTarget {
	KEY = 0;
	VERSION = 1;
	CREATE = 2;
	MOD = 3;
	VALUE = 4;
  }

  bytes key = 1;
  bytes range_end = 2;
  int64 limit = 3;
  int64 revision = 4;
  SortOrder sort_order = 5;
  SortTarget sort_target = 6;
  bool serializable = 7;
  bool keys_only = 8;
  bool count_only = 9;
  int64 min_mod_revision = 10;
  int64 max_mod_revision = 11;
  int64 min_create_revision = 12;
  int64 max_create_revision = 13;
}
  • Key, Range_End - Der abzurufende Schlüsselbereich.
  • Limit - Die maximale Anzahl der für die Anfrage zurückgegebenen Schlüssel. Der Wert 0 bedeutet keine Begrenzung.
  • Revision - Der für den Bereich zu verwendende Zeitpunkt im Schlüssel-Wert-Speicher. Ist revision kleiner oder gleich null, bezieht sich der Bereich auf den neuesten Stand. Wurde die Revision kompaktiert, wird ErrCompacted zurückgegeben.
  • Sort_Order - Die Reihenfolge für sortierte Anfragen.
  • Sort_Target - Das Schlüssel-Wert-Feld, nach dem sortiert wird.
  • Serializable - Legt fest, dass die Bereichsanfrage serialisierbare, auf das Mitglied beschränkte Lesezugriffe verwendet. Standardmäßig ist Range linearisierbar und spiegelt den aktuellen Konsens des Clusters wider. Für bessere Leistung und Verfügbarkeit auf Kosten möglicherweise veralteter Leseergebnisse wird eine serialisierbare Bereichsanfrage lokal bearbeitet, ohne einen Konsens mit anderen Clusterknoten herstellen zu müssen.
  • Keys_Only - Gibt nur die Schlüssel, nicht die Werte zurück.
  • Count_Only - Gibt nur die Anzahl der Schlüssel im Bereich zurück.
  • Min_Mod_Revision - Die Untergrenze für Änderungsrevisionen von Schlüsseln; kleinere Änderungsrevisionen werden herausgefiltert.
  • Max_Mod_Revision - Die Obergrenze für Änderungsrevisionen von Schlüsseln; größere Änderungsrevisionen werden herausgefiltert.
  • Min_Create_Revision - Die Untergrenze für Erstellungsrevisionen von Schlüsseln; kleinere Erstellungsrevisionen werden herausgefiltert.
  • Max_Create_Revision - Die Obergrenze für Erstellungsrevisionen von Schlüsseln; größere Erstellungsrevisionen werden herausgefiltert.

Der Client erhält vom Aufruf Range eine Nachricht RangeResponse:

message RangeResponse {
  ResponseHeader header = 1;
  repeated mvccpb.KeyValue kvs = 2;
  bool more = 3;
  int64 count = 4;
}
  • Kvs - Die Liste der Schlüssel-Wert-Paare, die der Bereichsanfrage entsprechen. Wenn Count_Only gesetzt ist, ist Kvs leer.
  • More - Gibt bei gesetztem limit an, ob im angeforderten Bereich weitere Schlüssel zurückzugeben sind.
  • Count - Die Gesamtzahl der Schlüssel, die die Bereichsanfrage erfüllen.

Für große Schlüsselbereiche, deren vollständige Antwort nicht zwischengespeichert werden soll, siehe RangeStream .

RangeStream

RangeStream liefert dieselbe Ergebnismenge wie Range, der Server teilt die Antwort jedoch in eine Folge von Blöcken auf und überträgt sie als Stream an den Client. So muss keine Seite große Bereiche vollständig im Arbeitsspeicher zwischenspeichern. RangeStream akzeptiert dieselbe RangeRequest wie Range.

Der Client erhält vom Aufruf RangeStream einen Stream von RangeStreamResponse-Nachrichten:

message RangeStreamResponse {
  RangeResponse range_response = 1;
}

Belegung der Felder über die Blöcke hinweg:

  • Kvs - Jeder Block enthält einen disjunkten Teil des Ergebnisses. Werden die kvs aller Blöcke in ihrer Empfangsreihenfolge aneinandergehängt, ergibt sich dieselbe Schlüsselmenge wie bei einem einzelnen Range-Aufruf.
  • Header, More, Count - Werden nur im letzten Block gesetzt, und nur wenn der Stream ohne Fehler endet. In früheren Blöcken behalten diese Felder ihre Nullwerte. Wird proto.Merge auf die range_response jedes Blocks angewendet, entsteht eine RangeResponse, die der Antwort von Range entspricht.

Endet der Stream mit einem Fehler, enthält kein Block einen gültigen Wert für header, more oder count.

Alle Blöcke des Streams werden anhand derselben Revision bereitgestellt. Ist Revision in der Anfrage nicht gesetzt, erfasst der Server beim Start des Streams die neueste bestätigte Revision und verwendet sie für den restlichen Stream weiter.

RangeStream unterstützt weder benutzerdefinierte Sortierreihenfolgen noch Revisionsfilter (min_mod_revision, max_mod_revision, min_create_revision, max_create_revision). Anfragen, die eines davon verwenden, liefern Unimplemented. Auch der gRPC-Proxy von etcd unterstützt RangeStream nicht.

Es gibt zwei übliche Arten, einen RangeStream zu verarbeiten:

  1. Jeden Block unabhängig verarbeiten. Geeignet für Szenarien mit hohen Leistungsanforderungen, in denen der Client Schlüssel beim Eintreffen dekodieren und verarbeiten möchte, statt zuerst das gesamte Ergebnis zu sammeln. Der Client durchläuft die Blöcke und verarbeitet die jeweiligen kvs. Nachdem der Stream fehlerfrei beendet wurde, liest er header, more oder count aus dem letzten Block.
  2. Eine einzelne Antwort zusammensetzen. Geeignet, wenn der Client ein Ergebnis wie bei einem unären Range-Aufruf benötigt. Er führt die range_response jedes Blocks zu einer RangeResponse zusammen, etwa mit proto.Merge. Das Ergebnis enthält die vollständigen kvs sowie header, more und count aus dem letzten Block. Der Go-Client bietet dafür die Hilfsfunktion clientv3.GetStreamToGetResponse.

Put

Schlüssel werden mit dem Aufruf Put im Schlüssel-Wert-Speicher gespeichert. Er nimmt eine PutRequest entgegen:

message PutRequest {
  bytes key = 1;
  bytes value = 2;
  int64 lease = 3;
  bool prev_kv = 4;
  bool ignore_value = 5;
  bool ignore_lease = 6;
}
  • Key - Der Name des Schlüssels, der in den Schlüssel-Wert-Speicher geschrieben werden soll.
  • Value - Der Wert als Bytes, der dem Schlüssel im Schlüssel-Wert-Speicher zugeordnet werden soll.
  • Lease - Die Lease-ID, die dem Schlüssel im Schlüssel-Wert-Speicher zugeordnet werden soll. Der Lease-Wert 0 bedeutet keine Lease.
  • Prev_Kv - Wenn gesetzt, enthält die Antwort die Daten des Schlüssel-Wert-Paars vor der Aktualisierung durch diese Put-Anfrage.
  • Ignore_Value - Wenn gesetzt, wird der Schlüssel aktualisiert, ohne seinen aktuellen Wert zu ändern. Existiert der Schlüssel nicht, wird ein Fehler zurückgegeben.
  • Ignore_Lease - Wenn gesetzt, wird der Schlüssel aktualisiert, ohne seine aktuelle Lease zu ändern. Existiert der Schlüssel nicht, wird ein Fehler zurückgegeben.

Der Client erhält vom Aufruf Put eine Nachricht PutResponse:

message PutResponse {
  ResponseHeader header = 1;
  mvccpb.KeyValue prev_kv = 2;
}
  • Prev_Kv - Das durch Put überschriebene Schlüssel-Wert-Paar, wenn Prev_Kv in der PutRequest gesetzt war.

Schlüsselbereich löschen

Schlüsselbereiche werden mit dem Aufruf DeleteRange gelöscht. Er nimmt eine DeleteRangeRequest entgegen:

message DeleteRangeRequest {
  bytes key = 1;
  bytes range_end = 2;
  bool prev_kv = 3;
}
  • Key, Range_End - Der zu löschende Schlüsselbereich.
  • Prev_Kv - Wenn gesetzt, wird der Inhalt der gelöschten Schlüssel-Wert-Paare zurückgegeben.

Der Client erhält vom Aufruf DeleteRange eine Nachricht DeleteRangeResponse:

message DeleteRangeResponse {
  ResponseHeader header = 1;
  int64 deleted = 2;
  repeated mvccpb.KeyValue prev_kvs = 3;
}
  • Deleted - Anzahl der gelöschten Schlüssel.
  • Prev_Kv - Eine Liste aller durch die Operation DeleteRange gelöschten Schlüssel-Wert-Paare.

Transaktion

Eine Transaktion ist ein atomares If/Then/Else-Konstrukt über dem Schlüssel-Wert-Speicher. Sie bietet eine Grundoperation, die Anfragen zu atomaren Blöcken, also then/else, zusammenfasst und deren Ausführung anhand des Speicherinhalts bedingt, also if. Transaktionen können Schlüssel vor unbeabsichtigten gleichzeitigen Aktualisierungen schützen, Compare-and-swap-Operationen bilden und als Grundlage einer übergeordneten Nebenläufigkeitskontrolle dienen.

Eine Transaktion kann mehrere Anfragen atomar in einer einzigen Anfrage verarbeiten. Bei Änderungen des Schlüssel-Wert-Speichers bedeutet dies, dass die Speicherrevision für die Transaktion nur einmal erhöht wird und alle erzeugten Ereignisse dieselbe Revision haben. Derselbe Schlüssel darf innerhalb einer einzelnen Transaktion jedoch nicht mehrfach geändert werden.

Alle Transaktionen werden durch eine Konjunktion von Vergleichen abgesichert, ähnlich einer If-Anweisung. Jeder Vergleich prüft einen einzelnen Schlüssel im Speicher. Er kann prüfen, ob ein Wert fehlt oder vorhanden ist, ihn mit einem angegebenen Wert vergleichen oder die Revision beziehungsweise Version eines Schlüssels prüfen. Zwei verschiedene Vergleiche können denselben oder unterschiedliche Schlüssel betreffen. Alle Vergleiche werden atomar angewendet. Sind alle wahr, gilt die Transaktion als erfolgreich, und etcd wendet ihren then- beziehungsweise success-Anfrageblock an. Andernfalls gilt sie als fehlgeschlagen, und der else- beziehungsweise failure-Anfrageblock wird angewendet.

Jeder Vergleich wird als Nachricht Compare kodiert:

message Compare {
  enum CompareResult {
    EQUAL = 0;
    GREATER = 1;
    LESS = 2;
    NOT_EQUAL = 3;
  }
  enum CompareTarget {
    VERSION = 0;
    CREATE = 1;
    MOD = 2;
    VALUE= 3;
  }
  CompareResult result = 1;
  // target is the key-value field to inspect for the comparison.
  CompareTarget target = 2;
  // key is the subject key for the comparison operation.
  bytes key = 3;
  oneof target_union {
    int64 version = 4;
    int64 create_revision = 5;
    int64 mod_revision = 6;
    bytes value = 7;
  }
}
  • Result - Die Art der logischen Vergleichsoperation, etwa gleich oder kleiner als.
  • Target - Das zu vergleichende Schlüssel-Wert-Feld: Version, Erstellungsrevision, Änderungsrevision oder Wert des Schlüssels.
  • Key - Der Schlüssel für den Vergleich.
  • Target_Union - Die vom Benutzer angegebenen Daten für den Vergleich.

Nach dem Verarbeiten des Vergleichsblocks wendet die Transaktion einen Anfrageblock an. Ein Block ist eine Liste von RequestOp-Nachrichten:

message RequestOp {
  // request is a union of request types accepted by a transaction.
  oneof request {
    RangeRequest request_range = 1;
    PutRequest request_put = 2;
    DeleteRangeRequest request_delete_range = 3;
  }
}
  • Request_Range - Eine RangeRequest.
  • Request_Put - Eine PutRequest. Die Schlüssel müssen eindeutig sein. Sie darf keine Schlüssel mit anderen Put- oder Delete-Anfragen gemeinsam haben.
  • Request_Delete_Range - Eine DeleteRangeRequest. Sie darf keine Schlüssel mit Put- oder Delete-Anfragen gemeinsam haben.

Zusammengesetzt wird eine Transaktion mit dem API-Aufruf Txn ausgeführt, der eine TxnRequest entgegennimmt:

message TxnRequest {
  repeated Compare compare = 1;
  repeated RequestOp success = 2;
  repeated RequestOp failure = 3;
}
  • Compare - Eine Liste von Prädikaten, die eine Konjunktion von Bedingungen zur Absicherung der Transaktion repräsentiert.
  • Success - Eine Liste von Anfragen, die verarbeitet werden, wenn alle Vergleiche true ergeben.
  • Failure - Eine Liste von Anfragen, die verarbeitet werden, wenn ein Vergleich false ergibt.

Der Client erhält vom Aufruf Txn eine Nachricht TxnResponse:

message TxnResponse {
  ResponseHeader header = 1;
  bool succeeded = 2;
  repeated ResponseOp responses = 3;
}
  • Succeeded - Gibt an, ob Compare true oder false ergab.
  • Responses - Eine Liste von Antworten auf die Ergebnisse der Anwendung des Blocks Success, wenn succeeded true ist, beziehungsweise Failure, wenn succeeded false ist.

Die Liste Responses entspricht den Ergebnissen der angewendeten Liste RequestOp. Jede Antwort ist als ResponseOp kodiert:

message ResponseOp {
  oneof response {
    RangeResponse response_range = 1;
    PutResponse response_put = 2;
    DeleteRangeResponse response_delete_range = 3;
  }
}

Der in jeder inneren Antwort enthaltene ResponseHeader sollte in keiner Weise ausgewertet werden. Wenn Clients die neueste Revision benötigen, sollten sie immer den obersten ResponseHeader in TxnResponse prüfen.

Watch-API

Die API Watch bietet eine ereignisbasierte Schnittstelle zur asynchronen Überwachung von Schlüsseländerungen. Ein etcd-Watch wartet auf Änderungen, indem er ab einer angegebenen aktuellen oder historischen Revision fortlaufend beobachtet und Schlüsselaktualisierungen an den Client zurückstreamt.

Ereignisse

Jede Änderung an jedem Schlüssel wird durch Event-Nachrichten dargestellt. Eine Event-Nachricht enthält sowohl die Daten als auch die Art der Aktualisierung:

message Event {
  enum EventType {
    PUT = 0;
    DELETE = 1;
  }
  EventType type = 1;
  KeyValue kv = 2;
  KeyValue prev_kv = 3;
}
  • Type - Die Art des Ereignisses. PUT zeigt an, dass neue Daten unter dem Schlüssel gespeichert wurden. DELETE zeigt an, dass der Schlüssel gelöscht wurde.
  • KV - Der dem Ereignis zugeordnete KeyValue. Ein PUT-Ereignis enthält das aktuelle kv-Paar. Ein PUT-Ereignis mit kv.Version=1 zeigt die Erstellung eines Schlüssels an. Ein DELETE-Ereignis enthält den gelöschten Schlüssel, dessen Änderungsrevision auf die Revision der Löschung gesetzt ist.
  • Prev_KV - Das Schlüssel-Wert-Paar aus der Revision unmittelbar vor dem Ereignis. Um Bandbreite zu sparen, wird es nur gesetzt, wenn der Watch dies ausdrücklich aktiviert hat.

Watch-Streams

Watches sind lang laufende Anfragen und übertragen Ereignisdaten über gRPC-Streams. Ein Watch-Stream ist bidirektional: Der Client schreibt in den Stream, um Watches einzurichten, und liest daraus, um Watch-Ereignisse zu empfangen. Ein einzelner Stream kann viele verschiedene Watches multiplexen, indem er Ereignisse mit einer Kennung pro Watch versieht. Dieses Multiplexing verringert den Speicherbedarf und den Verbindungsaufwand im eigentlichen etcd-Cluster.

Garantien für Watch-Ereignisse sind unter Garantien der etcd-API beschrieben.

Ein Client erstellt einen Watch, indem er eine WatchCreateRequest über einen von Watch zurückgegebenen Stream sendet:

message WatchCreateRequest {
  bytes key = 1;
  bytes range_end = 2;
  int64 start_revision = 3;
  bool progress_notify = 4;

  enum FilterType {
    NOPUT = 0;
    NODELETE = 1;
  }
  repeated FilterType filters = 5;
  bool prev_kv = 6;
}
  • Key, Range_End - Der zu beobachtende Schlüsselbereich.
  • Start_Revision - Eine optionale Revision, ab der einschließlich beobachtet wird. Ist sie nicht angegeben, werden Ereignisse nach der Revision im Antwortheader der Watch-Erstellung gestreamt. Der gesamte verfügbare Ereignisverlauf kann ab der letzten Kompaktierungsrevision beobachtet werden.
  • Progress_Notify - Wenn gesetzt und keine aktuellen Ereignisse vorliegen, erhält der Watch regelmäßig eine WatchResponse ohne Ereignisse. Das ist nützlich, wenn Clients einen unterbrochenen Watcher ab einer kürzlich bekannt gewordenen Revision wiederherstellen möchten. Der etcd-Server entscheidet anhand der aktuellen Serverlast, wie häufig er Benachrichtigungen sendet.
  • Filters - Eine Liste von Ereignistypen, die serverseitig herausgefiltert werden sollen.
  • Prev_Kv - Wenn gesetzt, erhält der Watch die Schlüssel-Wert-Daten vor dem Ereignis. So lässt sich erkennen, welche Daten überschrieben wurden.

Als Antwort auf eine WatchCreateRequest oder bei einem neuen Ereignis für einen eingerichteten Watch erhält der Client eine WatchResponse:

message WatchResponse {
  ResponseHeader header = 1;
  int64 watch_id = 2;
  bool created = 3;
  bool canceled = 4;
  int64 compact_revision = 5;

  repeated mvccpb.Event events = 11;
}
  • Watch_ID - Die ID des Watches, zu dem die Antwort gehört.
  • Created - Wird auf true gesetzt, wenn die Antwort zu einer Anfrage zum Erstellen eines Watches gehört. Der Client sollte die ID speichern und die Ereignisse für den Watch im Stream erwarten. Alle an den erstellten Watcher gesendeten Ereignisse haben dieselbe watch_id.
  • Canceled - Wird auf true gesetzt, wenn die Antwort zu einer Anfrage zum Abbrechen eines Watches gehört. An den abgebrochenen Watcher werden keine weiteren Ereignisse gesendet.
  • Compact_Revision - Wird auf die kleinste in etcd verfügbare historische Revision gesetzt, wenn ein Watcher versucht, eine kompaktierte Revision zu beobachten. Dies geschieht beim Erstellen eines Watchers an einer kompaktierten Revision oder wenn er den Fortschritt des Schlüssel-Wert-Speichers nicht einholen kann. Der Watcher wird abgebrochen; das Erstellen neuer Watches mit derselben start_revision schlägt fehl.
  • Events - Eine geordnete Liste neuer Ereignisse für die angegebene Watch-ID.

Wenn der Client keine weiteren Ereignisse für einen Watch empfangen möchte, sendet er eine WatchCancelRequest:

message WatchCancelRequest {
   int64 watch_id = 1;
}
  • Watch_ID - Die ID des abzubrechenden Watches, damit keine weiteren Ereignisse übertragen werden.

Lease-API

Leases sind ein Mechanismus zur Erkennung, ob Clients noch aktiv sind. Der Cluster gewährt Leases mit einer Lebensdauer. Eine Lease läuft ab, wenn der etcd-Cluster innerhalb eines angegebenen TTL-Zeitraums kein keepAlive empfängt.

Um Leases mit dem Schlüssel-Wert-Speicher zu verknüpfen, kann jeder Schlüssel höchstens einer Lease zugeordnet werden. Läuft eine Lease ab oder wird sie widerrufen, werden alle ihr zugeordneten Schlüssel gelöscht. Jeder abgelaufene Schlüssel erzeugt ein Löschereignis im Ereignisverlauf.

Leases erhalten

Leases werden mit dem API-Aufruf LeaseGrant angefordert. Er nimmt eine LeaseGrantRequest entgegen:

message LeaseGrantRequest {
  int64 TTL = 1;
  int64 ID = 2;
}
  • TTL - Die als Richtwert angegebene Lebensdauer in Sekunden.
  • ID - Die angeforderte ID der Lease. Ist ID auf 0 gesetzt, wählt etcd eine ID aus.

Der Client erhält vom Aufruf LeaseGrant eine LeaseGrantResponse:

message LeaseGrantResponse {
  ResponseHeader header = 1;
  int64 ID = 2;
  int64 TTL = 3;
}
  • ID - Die Lease-ID der gewährten Lease.
  • TTL - Die vom Server gewählte Lebensdauer der Lease in Sekunden.
message LeaseRevokeRequest {
  int64 ID = 1;
}
  • ID - Die Lease-ID der zu widerrufenden Lease. Beim Widerruf werden alle zugeordneten Schlüssel gelöscht.

Keepalives

Leases werden über einen bidirektionalen Stream erneuert, der mit dem API-Aufruf LeaseKeepAlive erstellt wird. Möchte der Client eine Lease erneuern, sendet er eine LeaseKeepAliveRequest über den Stream:

message LeaseKeepAliveRequest {
  int64 ID = 1;
}
  • ID - Die Lease-ID der am Leben zu haltenden Lease.

Der Keepalive-Stream antwortet mit einer LeaseKeepAliveResponse:

message LeaseKeepAliveResponse {
  ResponseHeader header = 1;
  int64 ID = 2;
  int64 TTL = 3;
}
  • ID - Die Lease, die mit einer neuen TTL erneuert wurde.
  • TTL - Die neue verbleibende Lebensdauer der Lease in Sekunden.

12.6 - Dateien der persistenten Speicherung in etcd

Referenz der persistenten Speicherformate und Dateien

Dieses Dokument erläutert das Format der persistenten Speicherung in etcd: Benennung, Inhalt und Werkzeuge, mit denen Entwickler die Dateien untersuchen können. Künftig sollte es um Änderungen am Speichermodell erweitert werden. Es richtet sich an etcd-Entwickler und soll sie bei der Datenwiederherstellung unterstützen.

Voraussetzungen

Die folgenden Artikel liefern hilfreiche Hintergrundinformationen zu diesem Dokument:

Überblick

Langlebige Dateien

Dateiname Zweck
./member/snap/db
bbolt B+-Baum, der alle angewendeten Daten, Informationen zur Mitgliedschaft und Autorisierung sowie Metadaten speichert. Er kennt den zuletzt angewendeten WAL-Index ("consistent_index").
./member/snap/0000000000000002-0000000000049425.snap
./member/snap/0000000000000002-0000000000061ace.snap

Regelmäßige Snapshots des alten v2-Speichers, mit:

  • grundlegenden Mitgliedschaftsinformationen
  • etcd-Version

Seit etcd v3 ist dieser Inhalt gegenüber den /snap/db-Dateien redundant.

Regelmäßig (30s) werden diese Dateien bereinigt, wobei die letzten --max-snapshots=5 erhalten bleiben.

/member/snap/000000000007a178.snap.db

Ein vollständiger heruntergeladener bbolt-Snapshot vom etcd-Leader, falls das Replikat zu weit zurücklag.

Enthält dieselbe Art von Daten wie die Datei (./member/snap/db).

Die Datei wird in 2 Fällen verwendet:

  • Als Antwort auf die Aufforderung des Leaders zur Wiederherstellung aus dem Snapshot.
  • Beim Serverstart, wenn der letzte Snapshot, eine .snap.db-Datei, gefunden wird und einen neueren Index als consistent_index in der aktuellen Datei snap.db hat.
Hinweis: Regelmäßige Snapshots auf den einzelnen Replikaten werden nur als *.snap-Datei erzeugt, nicht als snap.db-Datei. Daher ist nicht garantiert, dass der neueste Snapshot im WAL eine *.snap.db-Datei besitzt. In diesem Fall wird jedoch erwartet, dass das Backend snap/db neuer ist als der Snapshot.

Die Datei wird nach Abschluss der Wiederherstellung nicht gelöscht (der gesamte Inhalt wurde dann in ./member/snap/db übernommen). Regelmäßig (30s) werden die Dateien bereinigt. Auch hier bleiben --max-snapshots=5 erhalten. Da diese Dateien O(GBs) groß sein können, besteht die Gefahr, dass der Datenträgerspeicher ausgeht.

./member/wal/000000000000000f-00000000000b38c7.wal
./member/wal/000000000000000e-00000000000a7fe3.wal
./member/wal/000000000000000d-000000000009c70c.wal

Write-Ahead-Logs von Raft, mit aktuellen von Raft akzeptierten Transaktionen, regelmäßigen Snapshots oder CRC-Einträgen.

Die neuesten --max-wals=5 Dateien bleiben erhalten. Jede dieser Dateien ist ~64*10^6 Bytes groß. Bei Überschreiten dieser fest codierten Größe wird eine neue Datei begonnen. Die Dateien können deshalb etwas größer werden; die vorab zugewiesene Datei 0.tmp schützt daher nicht vollständig vor einer Überschreitung des verfügbaren Datenträgerspeichers.

Bei zu seltenen Snapshots können mehr als --max-wals=5 Dateien vorhanden sein, da Sperren auf Dateisystemebene sie vor vorzeitiger Löschung schützen.

./member/wal/0.tmp (or .../1.tmp)
Vorab zugewiesener Speicherplatz für die nächste Write-Ahead-Log-Datei. Verhindert, dass Raft wegen fehlender WAL-Kapazität blockiert, ohne einen Alarm auslösen zu können.

Temporäre Dateien

Während der internen Verarbeitung von etcd können mehrere kurzlebige Dateien auftreten:

Datei Zweck
./member/snap/0000000000000002-000000000007a178.snap.broken

Snapshot-Dateien werden in „broken“ umbenannt, wenn sie nicht geladen werden können.

Der Versuch, die neueste Datei zu laden, erfolgt, wenn etcd gestartet wird.

Oder während der backup/migrate-Befehle von etcdctl.

./member/snap/tmp071677638 (random suffix)

Temporäre bbolt-Datei, die auf Replikaten als Antwort auf die msgSnap-Anfrage des Leaders erstellt wird, also auf dessen Aufforderung, den Speicher aus dem angegebenen Snapshot wiederherzustellen.

Nach erfolgreichem vollständigem Abruf des Inhalts wird die Datei umbenannt in: /member/snap/[SNAPSHOT-INDEX].snap.db. Stürzt der Server während des Herunterladens ab oder wird er beendet, bleiben die Dateien auf dem Datenträger und werden niemals automatisch bereinigt. Sie können erheblichen Umfang haben (GBs).

Siehe etcd/issues/12837. In etcd 3.5 behoben.

/member/snap/db.tmp.071677638 (random suffix)

Eine temporäre Datei, die während der Defragmentierung eine Kopie des Backend-Inhalts (/member/snap/db) enthält. Nach erfolgreichem Abschluss wird sie in /member/snap/db umbenannt und ersetzt das ursprüngliche Backend.

Beim Start des etcd-Servers werden diese Dateien bereinigt.

bbolt-B+-Baum: member/snap/db

Diese Datei enthält die Hauptdaten von etcd, angewendet bis zu einer bestimmten Position im Raft-Log (siehe consistent_index ).

Physischer Aufbau

Der Speicher von „better bolt“ ist physisch als B+-Baum organisiert. Die physischen Seiten des B-Baums werden niemals an Ort und Stelle geändert1. Stattdessen wird ihr Inhalt auf eine neue Seite kopiert, die aus der Liste freier Seiten stammt. Die alte Seite wird dieser Liste hinzugefügt, sobald keine offene Transaktion mehr auf sie zugreifen könnte. Dadurch sieht eine offene RO-Transaktion einen konsistenten historischen Speicherzustand. Die RW-Transaktion ist exklusiv und blockiert alle anderen RW-Transaktionen.
Große Werte werden auf mehreren zusammenhängenden Seiten gespeichert. Die Wiederverwendung von Seiten zusammen mit der nötigen Zuweisung zusammenhängender Seitenbereiche unterschiedlicher Größe kann zu einer zunehmenden Fragmentierung des bbolt-Speichers führen.

Die bbolt-Datei schrumpft niemals von selbst. Nur bei der Defragmentierung kann sie in eine neue Datei mit einem Puffer freier Seiten am Ende und verkleinerter Dateigröße umgeschrieben werden.

Logischer Aufbau

Der bbolt-Speicher ist in Buckets unterteilt. In jedem Bucket werden Schlüssel (Paare vom Typ byte[]->value byte[]) in lexikografischer Reihenfolge gespeichert. Die folgende Liste zeigt die von etcd verwendeten Buckets mit Stand Version 3.5 und ihre Schlüssel.

Bucket Schlüssel Beispielwert Beschreibung
alarm rpcpb.Alarm: {MemberID, Alarm: NONE|NOSPACE|CORRUPT} nil Zeigt an, dass bei einem Mitglied Probleme erkannt wurden.
auth "authRevision" "" (leer) oder BigEndian.PutUint64

Jede Änderung an Rollen oder Benutzern erhöht dieses Feld beim Bestätigen der Transaktion.

Der Wert dient ausschließlich zur optimistischen Sperrung während des Autorisierungsvorgangs.

authRoles [roleName] als Zeichenfolge authpb.Role serialisiert
authUsers [userName] als Zeichenfolge authpb.User serialisiert
cluster "clusterVersion" "3.5.0" (string) Minor-Version der durch Konsens vereinbarten gemeinsamen Speicherversion.
"downgrade" JSON:
{
  "target-version": "3.4.0"
  "enabled": true/false
}

Speichert die Absicht dauerhaft, die durch die neueste Anfrage Downgrade RPC konfiguriert wurde.

Seit v3.5

key

[revisionId], kodiert mit bytesToRev{main,sub}

Löschungen von Schlüssel-Wert-Paaren werden mit einem abschließenden 't' als „Tombstone“ serialisiert

mvccpb.KeyValue als serialisiertes Proto (key, create_rev, mod_rev, version, value, lease id)
lease leasepb.Lease als serialisiertes Proto (ID, TTL, RemainingTTL)

Hinweis: LeaseCheckpoint verlängert nur RemainingTTL. TTL stammt weiterhin vom ursprünglichen Grant.

Hinweis2: TTLs werden in Sekunden ab einem nicht definierten „jetzt“ gespeichert. Ein ständig abstürzender und neu startender Server gibt keine Leases frei!!!

members [memberId] hexadezimal als Zeichenfolge: "8e9e05c52164694d" Als JSON-Zeichenfolge serialisierte Member-Struktur:
{
  "id":10276657743932975437,
  "peerURLs":[
  "http://localhost:2380"],
  "name":"default",
  "clientURLs": ["http://localhost:2379"]
}
Durch Konsens vereinbarte Informationen zur Clustermitgliedschaft.
members_removed [memberId] hexadezimal als Zeichenfolge: "8e9e05c52164694d" []byte("removed")

IDs aller entfernten Mitglieder. Damit wird geprüft, dass ein entferntes Mitglied niemals unter derselben ID erneut hinzugefügt wird.

Das Feld wird derzeit (3.4) aus dem V2-Speicher und niemals aus V3 gelesen. Siehe https://github.com/etcd-io/etcd/pull/12820

meta "consistent_index" uint64-Bytes (BigEndian) Repräsentiert den Offset des letzten auf den bolt-DB-Speicher angewendeten WAL-Eintrags.
"scheduledCompactRev" bytesToRev{main,sub} kodiert. (16 Bytes) Dient zur erneuten Initialisierung der Kompaktierung, wenn nach einer Kompaktierungsanfrage ein Absturz aufgetreten ist.
"finishedCompactRev" bytesToRev{main,sub} kodiert. (16 Bytes) Revision, bis zu der der Speicher zuletzt erfolgreich kompaktiert wurde (https://github.com/etcd-io/etcd/blob/ae7862e8bc8007eb396099db4e0e04ac026c8df5/server/mvcc/kvstore_compaction.go#L54)
"confState" Seit etcd 3.5
"term" Seit etcd 3.5
"storage-version"

Werkzeuge

bbolt

bbolt bietet ein Befehlszeilenwerkzeug zum Untersuchen des Dateiinhalts.

Anwendungsbeispiele:

Alle Buckets einer bbolt-Datei auflisten:
% go run go.etcd.io/bbolt/cmd/bbolt buckets ./default.etcd/member/snap/db
Ein bestimmtes Schlüssel-Wert-Paar lesen:
% go run go.etcd.io/bbolt/cmd/bbolt get ./default.etcd/member/snap/db cluster clusterVersion

etcd-dump-db

etcd-dump-db kann den Inhalt des etcd-v3-Backends (bbolt) auflisten.

% go run go.etcd.io/etcd/v3/tools/etcd-dump-db  list-bucket default.etcd
alarm
auth
...

Weitere Beispiele: https://github.com/etcd-io/etcd/tree/master/tools/etcd-dump-db

WAL: Write-Ahead-Log

Das Write-Ahead-Log ist ein persistenter Raft-Speicher für Vorschläge. Zuerst speichert der Leader den Vorschlag in seinem Log und repliziert ihn anschließend gleichzeitig über das Raft-Protokoll an die Follower. Jeder Follower speichert den Vorschlag dauerhaft in seinem WAL, bevor er dem Leader die Replikation bestätigt.

Das in etcd verwendete WAL unterscheidet sich in 2 Punkten vom kanonischen Raft-Modell:

  • Es speichert nicht nur indizierte Einträge dauerhaft, sondern auch kleine Raft-Snapshots und HardState. So lässt sich der gesamte Raft-Zustand eines Mitglieds allein aus dem WAL wiederherstellen.
  • Es wird nur angehängt. Einträge werden nicht an Ort und Stelle überschrieben; ein später in der Datei angehängter Eintrag mit demselben Index ersetzt den vorherigen logisch.

Dateinamen

Die WAL-Dateien werden nach folgendem Muster benannt:

"%016x-%016x.wal", seq, index

Beispiel: ./member/wal/0000000000000010-00000000000bf1e6.wal

Die Dateinamen enthalten also hexadezimal kodiert:

  • Die fortlaufende Nummer der WAL-Datei
  • Den Index des ersten Eintrags oder Snapshots in der Datei. Insbesondere enthält die erste Datei „0000000000000000-0000000000000000.wal“ den anfänglichen Snapshot-Eintrag mit index=0.

Physischer Inhalt

Die WAL-Datei enthält eine Folge von „Frames “. Jeder Frame enthält:

  1. Eine in LittleEndian 2 kodierte uint64-Zahl mit der Länge des serialisierten walpb.Record (3).
  2. Auffüllung: Eine Anzahl von 0-Bytes, sodass die Größe des gesamten Frames ausgerichtet ist (mod 8)
  3. Serialisierte walpb.Record -Daten:
    1. type - Als int kodierte Aufzählung, die die Interpretation des folgenden data-Felds bestimmt
    2. data - Je nach type gewöhnlich ein serialisiertes Proto
    3. crc - CRC-32-Prüfsumme aller zusammengefassten „data“-Felder ohne type in allen Logeinträgen dieses Replikats seit Erstellung des WAL. CRC berücksichtigt ALLE Einträge, auch wenn sie nicht durch Raft bestätigt wurden.

Eine neue Datei beginnt, sobald die aktuelle Datei 64*10^6 Bytes überschreitet.

Logischer Inhalt

Auf logischer Ebene enthalten Write-Ahead-Log-Dateien:

  • Raftpb.Entry: Aktuelle vom Raft-Leader replizierte Vorschläge. Einige gelten als bestätigt, andere können noch logisch überschrieben werden.
  • Raftpb.HardState(term,commit,vote): Regelmäßige, sehr häufige Informationen über den Index eines bestätigten Logeintrags, der also auf die Mehrheit der Server repliziert wurde. Er wird garantiert nicht mehr geändert oder überschrieben und kann auf die Backends v2 und v3 angewendet werden. Enthalten sind außerdem ein „term“ als Hinweis auf wahlbezogene Änderungen sowie eine Stimme: das Mitglied, für das das aktuelle Replikat im aktuellen Term gestimmt hat.
  • walpb.Snapshot(term, index): Regelmäßige Snapshots des Raft-Zustands ohne DB-Inhalt, nur mit Snapshot-Logindex und Raft-Term
    • Der Inhalt des V2-Speichers liegt in separaten *.store-Dateien.
    • Der Inhalt des V3-Speichers wird in der bbolt-Datei verwaltet und bildet einen impliziten Snapshot, sobald die Einträge dort angewendet sind.
  • Ein crc32-Prüfsummeneintrag am Anfang jeder Datei, um die CRC-Prüfung für den Rest der Datei fortzusetzen.
  • etcdserverpb.Metadata(node_id, cluster_id) - Identifiziert den Cluster und das Replikat, für die das Log steht.

Jede WAL-Datei besteht in dieser Reihenfolge aus:

  1. CRC-32-Frame mit der fortlaufenden crc aller vorherigen Dateien, 0 für die erste Datei.

  2. Metadaten-Frame mit Cluster- und Replikat-IDs

  3. Nur für die erste WAL-Datei:

    • Leerer Snapshot-Frame (Index:0, Term: 0). Er stellt die Invariante sicher, dass allen Einträgen ein Snapshot vorausgeht.

    Für spätere WAL-Dateien (ab der 2.):

    • HardState-Frame.
  4. Mischung aus Entry-, HardState- und Snapshot-Einträgen

Das WAL kann mehrere Einträge mit demselben Index enthalten. Dies kann in den in Abbildung 7. der Raft-Veröffentlichung beschriebenen Fällen auftreten. Da an das etcd-WAL nur angehängt wird, werden Einträge durch Anhängen eines neuen Eintrags mit demselben Index überschrieben.

Insbesondere ersetzt die Leselogik alte Einträge durch neuere Einträge . Daher kann nur die jeweils letzte Version von Einträgen mit entry.index <= HardState.commit als endgültig gelten. Einträge mit index > HardState.commit können sich noch ändern.

Es wird erwartet, dass die Terms im WAL monoton sind.

Für die Indizes im WAL wird Folgendes erwartet:

  1. Sie beginnen bei einem Snapshot.
  2. Nach diesem Snapshot steigen sie fortlaufend, solange sie im selben Term bleiben.
  3. Bei einem Term-Wechsel kann der Index sinken, jedoch nur auf einen neuen Wert oberhalb des neuesten HardState.commit.
  4. Ein neuer Snapshot kann mit jedem Index >= HardState.commit auftreten und beginnt eine neue Indexfolge.
Dateien der persistenten Speicherung in etcd

Werkzeuge

etcd-dump-logs

WAL-Dateien von etcd können mit dem Werkzeug etcd-dump-logs gelesen werden:

% go install go.etcd.io/etcd/v3/tools/etcd-dump-logs@latest

% go run go.etcd.io/etcd/v3/tools/etcd-dump-logs --start-index=0 aname.etcd

Zu beachten:

  • Das Werkzeug zeigt nur Entries und nicht alle WAL-Einträge wie Snapshots und HardStates in den WAL-Dateien.
  • Es berücksichtigt automatisch das Überschreiben von Einträgen. Wurde ein Eintrag durch einen neueren mit demselben Index überschrieben, wird nur der endgültige Wert ausgegeben.
  • Es gibt auch unbestätigte Einträge vom Ende des LOG aus, ohne Informationen zu HardState.commitIndex. Daher ist nicht erkennbar, ob diese Einträge endgültig sind.

Snapshots des V2-Speichers: member/snap/{term}-{index}.snap

Dateinamen:

member/snap/{term}-{index}.snap

Die Dateinamen werden hier mit ("%016x-%016x.snap") erzeugt und verwenden 2 hexadezimal kodierte Bestandteile:

  • term -> Raft-Term, also der Zeitraum zwischen Wahlen, zum Zeitpunkt der Snapshot-Erstellung
  • index -> Index des zuletzt angewendeten Vorschlags zum Zeitpunkt der Snapshot-Erstellung

Erstellung

Die *.snap-Dateien werden von der Methode Snapshotter.SaveSnap erstellt.

Es gibt 2 Auslöser für die Erstellung dieser Dateien:

  • Ungefähr alle –snapshot-count=(standardmäßig 10,000 in v3.7.0) angewendeten Vorschläge wird eine neue Datei erstellt. Dies ist nur ein Näherungswert, da Vorschläge gebündelt eintreffen können, ein Snapshot erst am Ende eines solchen Pakets geprüft und der Snapshot-Vorgang schließlich asynchron eingeplant wird. Der Optionsname –snapshot-count ist recht irreführend, da er die Differenz der Indexwerte zwischen dem letzten Snapshot und dem zuletzt angewendeten Vorschlag steuert.
  • Raft fordert das Replikat auf, sich aus einem Snapshot wiederherzustellen. Während das Replikat den Snapshot über eine msgSnap-Nachricht empfängt, hält es ihn auch als kleinen Checkpoint im WAL fest. Damit ist garantiert, dass am Ende des WAL stets ein gültiger Snapshot gefolgt von Einträgen steht. Mögliche Lücken im WAL werden so vermieden.

Derzeit entsprechen die Dateien ungefähr3 im Verhältnis 1-1 den Snapshot-Einträgen im WAL. Mit der Stilllegung des v2-Speichers wird erwartet, dass diese Dateien überhaupt nicht mehr geschrieben werden, optional ab 3.5.x und verpflichtend ab 3.6.x.

Inhalt

Die Datei enthält das serialisierte snapdb.snapshot-Proto (uint32 crc, bytes data),

das im Feld ‘data’ einen Raftpb.Snapshot enthält:

(bytes data, SnapshotMetadata{index, term, conf } metadata),

Die verschachtelten Daten enthalten schließlich den JSON-serialisierten Inhalt des v2-Speichers .

Insbesondere enthalten sind:

  • Term
  • Index
  • Mitgliedschaftsdaten:
    • /0/members/8e9e05c52164694d/attributes -> {"name":"default","clientURLs":["http://localhost:2379"]}
    • /0/members/8e9e05c52164694d/RaftAttributes -> "{"peerURLs":["http://localhost:2380"]}"
  • Speicherversion: /0/version-> 3.5.0

Werkzeuge

protoc

Der folgende Befehl zeigt den Dateiinhalt an, wenn er im Stammverzeichnis von etcd ausgeführt wird:

cat default.etcd/member/snap/0000000000000002-0000000000049425.snap |
  protoc --decode=snappb.snapshot \
    server/etcdserver/api/snap/snappb/snap.proto \
    -I $(go list -f '{{.Dir}}' github.com/gogo/protobuf/proto)/.. \
    -I . \
    -I $(go list -m -f '{{.Dir}}' github.com/gogo/protobuf)/protobuf

Ebenso lässt sich das Feld ‘data’ extrahieren und als Raftpb.Snapshot dekodieren.

Beispiel für JSON-serialisierten v2-Speicherinhalt in *.snap-Dateien von etcd 3.4:

{
  "Root":{
    "Path":"/",
    "CreatedIndex":0,
    "ModifiedIndex":0,
    "ExpireTime":"0001-01-01T00:00:00Z",
    "Value":"",
    "Children":{
      "0":{
        "Path":"/0",
        "CreatedIndex":0,
        "ModifiedIndex":0,
        "ExpireTime":"0001-01-01T00:00:00Z",
        "Value":"",
        "Children":{
          "members":{
            "Path":"/0/members",
            "CreatedIndex":1,
            "ModifiedIndex":1,
            "ExpireTime":"0001-01-01T00:00:00Z",
            "Value":"",
            "Children":{
              "8e9e05c52164694d":{
                "Path":"/0/members/8e9e05c52164694d",
                "CreatedIndex":1,
                "ModifiedIndex":1,
                "ExpireTime":"0001-01-01T00:00:00Z",
                "Value":"",
                "Children":{
                  "attributes":{
                    "Path":"/0/members/8e9e05c52164694d/attributes",
                    "CreatedIndex":2,
                    "ModifiedIndex":2,
                    "ExpireTime":"0001-01-01T00:00:00Z",
                    "Value":"{\"name\":\"default\",\"clientURLs\":[\"http://localhost:2379\"]}",
                    "Children":null
                  },
                  "RaftAttributes":{
                    "Path":"/0/members/8e9e05c52164694d/RaftAttributes",
                    "CreatedIndex":1,
                    "ModifiedIndex":1,
                    "ExpireTime":"0001-01-01T00:00:00Z",
                    "Value":"{\"peerURLs\":[\"http://localhost:2380\"]}",
                    "Children":null
                  }
                }
              }
            }
          },
          "version":{
            "Path":"/0/version",
            "CreatedIndex":3,
            "ModifiedIndex":3,
            "ExpireTime":"0001-01-01T00:00:00Z",
            "Value":"3.5.0",
            "Children":null
          }
        }
      },
      "1":{
        "Path":"/1",
        "CreatedIndex":0,
        "ModifiedIndex":0,
        "ExpireTime":"0001-01-01T00:00:00Z",
        "Value":"",
        "Children":{


        }
      }
    }
  },
  "WatcherHub":{
    "EventHistory":{
      "Queue":{
        "Events":[
          {
            "action":"create",
            "node":{
              "key":"/0/members/8e9e05c52164694d/RaftAttributes",
              "value":"{\"peerURLs\":[\"http://localhost:2380\"]}",
              "modifiedIndex":1,
              "createdIndex":1
            }
          },
          {
            "action":"set",
            "node":{
              "key":"/0/members/8e9e05c52164694d/attributes",
              "value":"{\"name\":\"default\",\"clientURLs\":[\"http://localhost:2379\"]}",
              "modifiedIndex":2,
              "createdIndex":2
            }
          },
          {
            "action":"set",
            "node":{
              "key":"/0/version",
              "value":"3.5.0",
              "modifiedIndex":3,
              "createdIndex":3
            }
          }
        ]
      }
    }
  }
}

Änderungen

Dieser Abschnitt ist für die Beschreibung von Dateiformatänderungen zwischen etcd-Versionen vorgesehen.


  1. Die Metadatenseiten am Anfang der bbolt-Datei werden an Ort und Stelle geändert. ↩︎

  2. Inkonsistent, da die meisten uint-Werte in Big Endian geschrieben werden ↩︎

  3. Der anfängliche Snapshot mit index:0 am Anfang des WAL ist keiner *.snap-Datei zugeordnet. Zudem können alte *.snap-Dateien oder WAL-Dateien bereinigt werden. ↩︎

12.7 - Garantien der etcd-API

API-Garantien von etcd

etcd ist ein konsistenter und dauerhafter Schlüssel-Wert-Speicher. Der Zugriff erfolgt über gRPC-Dienste . etcd bietet die stärksten Konsistenz- und Dauerhaftigkeitsgarantien für ein verteiltes System. Diese Spezifikation führt die API-Garantien von etcd auf.

Betrachtete APIs

Die KV-API ermöglicht das direkte Lesen und Bearbeiten des Schlüssel-Wert-Speichers. Mit der Watch-API lassen sich Änderungen am Schlüssel-Wert-Speicher abonnieren. Mit der Lease-API lässt sich einem Schlüssel eine Lebensdauer zuweisen.

Die KV- und Watch-APIs erlauben den Zugriff nicht nur auf die neuesten Schlüsselversionen, sondern auch auf frühere Versionen innerhalb eines zusammenhängenden Verlaufsfensters, das durch eine Kompaktierungsoperation begrenzt wird.

Ein Aufruf der KV-API wirkt unmittelbar, während die Watch-API mit einer nicht begrenzten Verzögerung zurückkehrt. In einem korrekt arbeitenden etcd-Cluster sollten Watch-Ereignisse etwa 10ms nach ihrem Auftreten sichtbar werden. Es gibt jedoch keine Obergrenze; in gestörten Clustern kommen Ereignisse möglicherweise nie an.

KV-APIs

etcd gewährleistet Dauerhaftigkeit und strikte Serialisierbarkeit für alle KV-API-Aufrufe. Dies sind die stärksten Isolationsgarantien verteilter transaktionaler Datenbanksysteme.

Dauerhaftigkeit

Alle abgeschlossenen Operationen sind dauerhaft. Auch alle zugänglichen Daten sind dauerhaft gespeichert. Ein Lesezugriff gibt niemals Daten zurück, die noch nicht dauerhaft gespeichert wurden.

Strikte Serialisierbarkeit

Operationen des KV-Dienstes sind atomar und erfolgen in einer totalen Ordnung, die ihrer Echtzeitreihenfolge entspricht. Diese totale Ordnung ergibt sich aus der Revision . Weitere Informationen zur strikten Serialisierbarkeit .

Bei Transaktionen ohne verschachtelte TXNs entspricht die Ausführungsreihenfolge garantiert jener in der Operationsliste. Dadurch sind die GET-Antworten innerhalb der Transaktion stabil. Bei Transaktionen mit verschachtelten TXNs ist die Ausführungsreihenfolge nicht festgelegt.

Strikte Serialisierbarkeit impliziert weitere, schwächere Garantien, die möglicherweise leichter verständlich sind:

Atomarität

Alle API-Anfragen sind atomar: Eine Operation wird entweder vollständig oder gar nicht abgeschlossen. Bei Watch-Anfragen befinden sich alle von einer Operation erzeugten Ereignisse in einer Watch-Antwort. Ein Watch beobachtet niemals nur einen Teil der Ereignisse einer einzelnen Operation.

Linearisierbarkeit

Aus Sicht des Clients bietet Linearisierbarkeit nützliche Eigenschaften, die das Nachvollziehen des Verhaltens erleichtern. Die folgende klare Beschreibung stammt aus der Originalveröffentlichung : Linearisierbarkeit erweckt den Eindruck, dass jede von nebenläufigen Prozessen ausgeführte Operation zu einem Zeitpunkt zwischen ihrem Aufruf und ihrer Antwort augenblicklich wirksam wird.

Angenommen, ein Client schließt einen Schreibvorgang zum Zeitpunkt 1 (t1) ab. Ein Client, der zu t2 mit t2 > t1 einen Lesevorgang startet, sollte einen Wert erhalten, der mindestens so aktuell ist wie der zuvor zu t1 abgeschlossene Schreibvorgang. Der Lesevorgang wird möglicherweise aber erst zu t3 abgeschlossen. Linearisierbarkeit garantiert, dass er den neuesten Wert zu einem Zeitpunkt zwischen seinem Beginn zu t2 und seinem Abschluss zu t3 zurückgibt. Er berücksichtigt alle vor seinem Beginn abgeschlossenen Schreibvorgänge. Ein gleichzeitiger Schreibvorgang zwischen t2 und t3 kann berücksichtigt werden oder auch nicht; der zurückgegebene Wert muss beim Abschluss des Lesevorgangs nicht der neueste sein.

etcd gewährleistet standardmäßig Linearisierbarkeit für alle anderen Operationen. Sie hat jedoch ihren Preis, da linearisierte Anfragen den Raft-Konsensprozess durchlaufen müssen. Für geringere Latenzen und höheren Durchsatz bei Leseanfragen können Clients deren Konsistenzmodus auf serializable setzen. Dabei können gegenüber dem Quorum veraltete Daten gelesen werden, doch der Leistungsnachteil linearisierter Zugriffe durch ihre Abhängigkeit vom laufenden Konsens entfällt.

Watch-APIs

Watches bieten folgende Garantien für Ereignisse:

  • Geordnet - Ereignisse sind nach Revision geordnet. Ein Ereignis erscheint niemals in einem Watch, wenn es zeitlich vor einem bereits ausgegebenen Ereignis liegt. Bei Transaktionen ohne verschachtelte TXNs entspricht die Reihenfolge der erzeugten Ereignisse garantiert der Reihenfolge in der Operationsliste. Bei Transaktionen mit verschachtelten TXNs ist sie nicht festgelegt.
  • Eindeutig - Ein Ereignis erscheint niemals zweimal in einem Watch.
  • Zuverlässig - Innerhalb des verfügbaren Verlaufsfensters geht niemals eine Teilfolge einer Ereignisfolge verloren. Sind Ereignisse zeitlich als a < b < c geordnet und empfängt der Watch a und c, empfängt er garantiert auch b, sofern b im verfügbaren Verlaufsfenster liegt.
  • Atomar - Eine Ereignisliste umfasst garantiert vollständige Revisionen. Aktualisierungen mehrerer Schlüssel in derselben Revision werden nicht auf mehrere Ereignislisten aufgeteilt.
  • Fortsetzbar - Ein unterbrochener Watch kann durch einen neuen Watch fortgesetzt werden, der nach der letzten vor der Unterbrechung in einem Watch-Ereignis empfangenen Revision beginnt, sofern diese Revision noch im Verlaufsfenster liegt.
  • Mit Fortschrittsmarken - Fortschrittsbenachrichtigungen garantieren, dass alle Ereignisse bis zu einer Revision bereits ausgeliefert wurden.

etcd gewährleistet keine Linearisierbarkeit für Watch-Operationen. Von Benutzern wird erwartet, die Revision von Watch-Ereignissen zu prüfen, um ihre korrekte Reihenfolge gegenüber anderen Operationen sicherzustellen.

Lease-APIs

etcd bietet einen Lease-Mechanismus . Der wichtigste Anwendungsfall einer Lease ist die Implementierung verteilter Koordinationsmechanismen wie verteilter Sperren. Der Mechanismus selbst ist einfach: Eine Lease kann mit der Grant-API erstellt, mit der Put-API einem Schlüssel zugeordnet und mit der Revoke-API widerrufen werden. Sie läuft nach ihrer anhand der realen Uhrzeit gemessenen Lebensdauer (TTL) ab. Um korrekte verteilte Koordinationsmechanismen zu implementieren, müssen Benutzer jedoch die wesentlichen Eigenschaften der APIs und ihrer Verwendung kennen.

etcd-spezifische Definitionen

Abgeschlossene Operation

Eine etcd-Operation gilt als abgeschlossen, wenn sie durch Konsens bestätigt und damit von der Speicherengine von etcd „ausgeführt“, also dauerhaft gespeichert wurde. Der Client weiß, dass eine Operation abgeschlossen ist, sobald er eine Antwort vom etcd-Server erhält. Bei einer Zeitüberschreitung oder einer Netzwerkunterbrechung zwischen Client und etcd-Mitglied kann ihr Status für den Client jedoch ungewiss sein. etcd kann Operationen auch während einer Leader-Wahl abbrechen. In diesem Fall sendet etcd keine abort-Antworten auf ausstehende Client-Anfragen.

Revision

Einer etcd-Operation, die den Schlüssel-Wert-Speicher ändert, wird genau eine steigende Revision zugewiesen. Eine Transaktionsoperation kann den Speicher mehrfach ändern, erhält aber nur eine Revision. Das Revisionsattribut eines durch die Operation geänderten Schlüssel-Wert-Paars hat denselben Wert wie die Revision der Operation. Die Revision kann als logische Uhr des Schlüssel-Wert-Speichers dienen. Ein Paar mit einer größeren Revision wurde nach einem Paar mit einer kleineren Revision geändert. Zwei Schlüssel-Wert-Paare mit derselben Revision wurden durch eine Operation „gleichzeitig“ geändert.

12.8 - etcd im Vergleich mit anderen Schlüssel-Wert-Speichern

Geschichte und Verwendung von etcd im Vergleich mit anderen Werkzeugen

Der Name „etcd“ entstand aus zwei Ideen: dem Unix-Verzeichnis “/etc” und verteilten Systemen, auf Englisch „distributed systems“. Im Verzeichnis “/etc” liegen Konfigurationsdaten eines einzelnen Systems, während etcd Konfigurationsinformationen für große verteilte Systeme speichert. Aus „/etc“ und dem Anfangsbuchstaben von „distributed“ wird somit „etcd“.

etcd ist als allgemeine Grundlage für große verteilte Systeme ausgelegt. Diese Systeme tolerieren keinen Split-Brain-Betrieb und nehmen dafür Einschränkungen der Verfügbarkeit in Kauf. etcd speichert Metadaten konsistent und fehlertolerant. Ein etcd-Cluster soll einen Schlüssel-Wert-Speicher mit erstklassiger Stabilität, Zuverlässigkeit, Skalierbarkeit und Leistung bieten.

Verteilte Systeme verwenden etcd als konsistenten Schlüssel-Wert-Speicher für Konfigurationsverwaltung, Diensterkennung und die Koordination verteilter Arbeit. Viele Organisationen nutzen etcd für Produktivsysteme wie Container-Scheduler, Dienste zur Diensterkennung und verteilte Datenspeicherung. Häufige verteilte Entwurfsmuster mit etcd sind Leader-Wahlen , verteilte Sperren und die Überwachung der Erreichbarkeit von Rechnern.

Anwendungsfälle

  • Container Linux von CoreOS: Anwendungen auf Container Linux erhalten automatische Linux-Kernel-Updates ohne Ausfallzeit. Container Linux koordiniert Updates mit locksmith . Locksmith implementiert über etcd ein verteiltes Semaphor, das sicherstellt, dass zu jedem Zeitpunkt nur ein Teil des Clusters neu startet.
  • Kubernetes speichert Konfigurationsdaten für Diensterkennung und Clusterverwaltung in etcd. Die Konsistenz von etcd ist für die korrekte Einplanung und den Betrieb von Diensten entscheidend. Der Kubernetes-API-Server speichert den Clusterzustand dauerhaft in etcd. Er verwendet die Watch-API von etcd, um den Cluster zu überwachen und kritische Konfigurationsänderungen auszurollen.

Vergleichstabelle

Vielleicht erscheint etcd bereits passend. Wie bei jeder Technologieentscheidung ist jedoch Vorsicht geboten. Diese Dokumentation wurde vom etcd-Team verfasst. Obwohl ein unvoreingenommener Vergleich von Technik und Funktionen das Ziel ist, begünstigen Fachkenntnisse und Vorlieben der Autoren offensichtlich etcd. Nur nach Anweisung verwenden.

Die folgende Tabelle bietet einen schnellen Überblick über die Unterschiede zwischen etcd und seinen beliebtesten Alternativen. Weitere Erläuterungen und Einzelheiten zu jeder Spalte folgen in den Abschnitten nach der Tabelle.

etcd ZooKeeper Consul NewSQL (Cloud Spanner, CockroachDB, TiDB)
Grundoperationen für Nebenläufigkeit Lock-RPCs , Election-RPCs , Sperren per Befehlszeile , Wahlen per Befehlszeile , Rezepte in Go Externe Curator-Rezepte in Java Native Sperr-API Selten , wenn überhaupt
Linearisierbare Lesezugriffe Ja Nein Ja Manchmal
Mehrversions-Nebenläufigkeitskontrolle Ja Nein Nein Manchmal
Transaktionen Feldvergleiche, Lesen, Schreiben Versionsprüfungen, Schreiben Feldvergleich, Sperren, Lesen, Schreiben Im SQL-Stil
Änderungsbenachrichtigungen Historische und aktuelle Schlüsselintervalle Aktuelle Schlüssel und Verzeichnisse Aktuelle Schlüssel und Präfixe Trigger (manchmal)
Benutzerberechtigungen Rollenbasiert ACLs ACLs Unterschiedlich (GRANT pro Tabelle, Rollen pro Datenbank)
API für HTTP/JSON Ja Nein Ja Selten
Neukonfiguration der Mitgliedschaft Ja >3.5.0 Ja Ja
Maximal zuverlässig nutzbare Datenbankgröße Mehrere Gigabyte Hunderte Megabyte (manchmal mehrere Gigabyte) Hunderte MB Terabyte und mehr
Minimale Latenz zur Linearisierung von Lesezugriffen Netzwerk-RTT Keine Linearisierung von Lesezugriffen RTT + fsync Uhrzeitbarrieren (Atomuhr, NTP)

ZooKeeper

ZooKeeper löst dasselbe Problem wie etcd: die Koordination verteilter Systeme und die Speicherung von Metadaten. etcd kann jedoch auf Entwicklungs- und Betriebserfahrungen mit dem Entwurf und der Implementierung von ZooKeeper zurückgreifen. Diese Erfahrungen haben den Entwurf von etcd geprägt und dabei geholfen, große Systeme wie Kubernetes zu unterstützen. Zu den Verbesserungen von etcd gegenüber ZooKeeper gehören:

  • Dynamische Neukonfiguration der Clustermitgliedschaft
  • Stabile Lese- und Schreibzugriffe unter hoher Last
  • Ein Datenmodell mit Mehrversions-Nebenläufigkeitskontrolle
  • Zuverlässige Schlüsselüberwachung, die niemals unbemerkt Ereignisse verwirft
  • Lease-Grundoperationen, die Verbindungen von Sitzungen entkoppeln
  • APIs für sichere verteilte gemeinsame Sperren

Darüber hinaus unterstützt etcd unmittelbar zahlreiche Sprachen und Frameworks. ZooKeeper verwendet sein eigenes, ausschließlich dort eingesetztes Jute-RPC-Protokoll, das die unterstützten Sprachanbindungen begrenzt. Das Client-Protokoll von etcd basiert dagegen auf gRPC , einem verbreiteten RPC-Framework mit Anbindungen für Go, C++, Java und weitere Sprachen. gRPC lässt sich außerdem als JSON über HTTP serialisieren, sodass auch allgemeine Befehlszeilenwerkzeuge wie curl damit kommunizieren können. Dank dieser Auswahl lassen sich Systeme mit ihren nativen Werkzeugen auf etcd aufbauen, statt sie mit einem einzigen festen Technologiesatz um etcd herum zu entwickeln.

Unter Berücksichtigung von Funktionen, Unterstützung und Stabilität sind neue Anwendungen, die ZooKeeper als konsistenten Schlüssel-Wert-Speicher einsetzen wollen, gut beraten, stattdessen etcd zu wählen.

Consul

Consul ist ein umfassendes Framework zur Diensterkennung. Es bietet integrierte Health Checks, Ausfallerkennung und DNS-Dienste. Außerdem stellt Consul einen Schlüssel-Wert-Speicher mit RESTful-HTTP-APIs bereit. Beim Stand von Consul 1.0 skaliert dieser Speicher bei Schlüssel-Wert-Operationen weniger gut als Systeme wie etcd oder ZooKeeper. Systeme mit Millionen Schlüsseln leiden unter hohen Latenzen und Speicherdruck. Der Schlüssel-Wert-API fehlen insbesondere Mehrversionsschlüssel, bedingte Transaktionen und zuverlässige Streaming-Watches.

etcd und Consul lösen unterschiedliche Probleme. Für einen verteilten konsistenten Schlüssel-Wert-Speicher ist etcd die bessere Wahl. Für eine umfassende Diensterkennung im Cluster reichen die Funktionen von etcd nicht aus; dafür eignen sich Kubernetes, Consul oder SmartStack.

NewSQL (Cloud Spanner, CockroachDB, TiDB)

Sowohl etcd als auch NewSQL-Datenbanken wie Cockroach , TiDB und Google Spanner bieten starke Datenkonsistenzgarantien und Hochverfügbarkeit. Die deutlich unterschiedlichen Systementwurfsparameter führen jedoch zu deutlich unterschiedlichen Client-APIs und Leistungseigenschaften.

NewSQL-Datenbanken sind für horizontale Skalierung über Rechenzentren hinweg ausgelegt. Sie verteilen Daten üblicherweise auf mehrere konsistente Replikationsgruppen, sogenannte Shards, die weit auseinanderliegen können, und speichern Datenmengen im Terabyte-Bereich und darüber. Für verteilte Koordination eignet sich diese Skalierung schlecht: Das Warten auf Uhren verursacht hohe Latenzen, und Aktualisierungen werden mit weitgehend lokalen Abhängigkeitsgraphen erwartet. Die Daten sind in Tabellen organisiert und lassen sich mit SQL-artigen Abfragen mit umfangreicherer Semantik als bei etcd abfragen. Dafür steigt jedoch die Komplexität der Verarbeitung sowie der Planung und Optimierung von Abfragen.

Für Metadatenspeicherung oder die Koordination verteilter Anwendungen eignet sich etcd. Sollen mehr als einige GB Daten gespeichert werden oder sind vollständige SQL-Abfragen erforderlich, eignet sich eine NewSQL-Datenbank.

etcd für Metadaten verwenden

etcd repliziert alle Daten innerhalb einer einzigen konsistenten Replikationsgruppe. Für bis zu einige GB Daten mit konsistenter Reihenfolge ist dies der effizienteste Ansatz. Jede Änderung des Clusterzustands, die mehrere Schlüssel betreffen kann, erhält aus einem monoton steigenden Zähler eine global eindeutige ID, in etcd Revision genannt. Anhand dieser ID lässt sich die Reihenfolge bestimmen. Da es nur eine Replikationsgruppe gibt, muss die Änderungsanfrage zur Bestätigung nur das Raft-Protokoll durchlaufen. Durch die Begrenzung des Konsenses auf eine Replikationsgruppe erreicht etcd verteilte Konsistenz mit einem einfachen Protokoll bei geringer Latenz und hohem Durchsatz.

Die Replikation von etcd lässt sich mangels Daten-Sharding nicht horizontal skalieren. NewSQL-Datenbanken verteilen Daten dagegen üblicherweise auf mehrere konsistente Replikationsgruppen und speichern Datenmengen im Terabyte-Bereich und darüber. Um jeder Änderung eine global eindeutige, steigende ID zuzuweisen, muss jede Anfrage jedoch ein zusätzliches Koordinationsprotokoll zwischen den Replikationsgruppen durchlaufen. Dieser zusätzliche Schritt kann Konflikte um die globale ID verursachen und geordnete Anfragen zur Wiederholung zwingen. Das Ergebnis ist ein komplexerer Ansatz mit üblicherweise schlechterer Leistung als etcd bei strikter Reihenfolge.

Wenn eine Anwendung vor allem Metadaten oder deren Reihenfolge verarbeitet, etwa zur Prozesskoordination, eignet sich etcd. Benötigt sie einen großen Datenspeicher über mehrere Rechenzentren hinweg und ist nicht stark auf eine strikte globale Reihenfolge angewiesen, eignet sich eine NewSQL-Datenbank.

etcd für verteilte Koordination verwenden

etcd bietet direkt Grundoperationen für verteilte Koordination, darunter Ereignis-Watches, Leases, Wahlen und verteilte gemeinsame Sperren. Bei letzteren müssen Benutzer allerdings nicht offensichtliche Eigenschaften beachten, die unten erläutert werden. Diese Grundoperationen werden von den etcd-Entwicklern gepflegt und unterstützt. Sie externen Bibliotheken zu überlassen, würde die Verantwortung für die Entwicklung grundlegender verteilter Software abgeben und das System im Wesentlichen unvollständig lassen. NewSQL-Datenbanken erwarten üblicherweise, dass Drittanbieter solche Grundoperationen entwickeln. Ebenso verfügt ZooKeeper bekanntlich über eine separate, unabhängige Bibliothek mit Koordinationsrezepten. Consul bietet eine native Sperr-API, weist aber sogar entschuldigend darauf hin, dass sie „keine absolut sichere Methode “ sei.

Theoretisch lassen sich diese Grundoperationen auf jedem Speichersystem mit starker Konsistenz aufbauen. Die Algorithmen sind jedoch oft subtil: Schnell entsteht ein scheinbar funktionierender Sperralgorithmus, der plötzlich an gleichzeitig aufwachenden Wartenden, dem Thundering-Herd-Problem, oder Zeitabweichungen scheitert. Außerdem hängen weitere von etcd unterstützte Grundoperationen wie transaktionaler Speicher vom MVCC-Datenmodell ab; starke Konsistenz allein reicht nicht aus.

Für verteilte Koordination kann die Wahl von etcd Betriebsprobleme vermeiden helfen und Entwicklungsaufwand sparen.

Hinweise zur Verwendung von Sperren und Leases

etcd bietet Sperr-APIs , die auf dem Lease-Mechanismus und dessen Implementierung in etcd basieren. Die Grundidee: Ein Server gewährt einem anfragenden Client ein Token namens Lease und ordnet ihm eine TTL zu. Stellt der Server fest, dass mehr Zeit als die TTL vergangen ist, widerruft er die Lease. Solange der Client eine nicht widerrufene Lease hält, kann er beanspruchen, den Zugriff auf eine zugeordnete Ressource zu besitzen. Bei etcd ist diese Ressource ein Schlüssel im Schlüsselraum. Auf diesem Prinzip beruhen die Sperr-APIs von etcd. Für sich allein gewährleisten sie jedoch keinen gegenseitigen Ausschluss. Die Bezeichnung „lock“ hat historische Gründe . Wie unten beschrieben, können die Sperr-APIs den gegenseitigen Ausschluss jedoch optimieren.

Der wichtigste Aspekt des Lease-Mechanismus ist, dass die TTL als physisches Zeitintervall definiert ist. Server und Client messen den Zeitablauf jeweils mit ihrer eigenen Uhr. Daher kann der Server die Lease bereits widerrufen haben, während der Client weiterhin behauptet, sie zu besitzen.

Wie gewährleistet der Lease-Mechanismus dann den gegenseitigen Ausschluss der Sperren? Tatsächlich gewährleistet er selbst keinen gegenseitigen Ausschluss. Der Besitz einer Lease garantiert nicht, dass ihr Besitzer eine Sperre auf der Ressource hält.

Wenn etcd-Sperren den gegenseitigen Zugriff auf Schlüssel von etcd selbst steuern, wird der gegenseitige Ausschluss durch die Validierung von Versionsnummern implementiert. In anderen Systemen wie Consul wird dies manchmal Compare and Swap genannt. In etcd-RPCs wie Put oder Txn lassen sich erforderliche Bedingungen für Revisionsnummer und Lease-ID der Operationen angeben. Sind diese nicht erfüllt, kann die Operation fehlschlagen. Mit diesem Mechanismus stellt etcd verteilte Sperren für Clients bereit. Ein Client weiß also, dass er die Sperre eines Schlüssels erwirbt, wenn der etcd-Cluster seine Anfragen erfolgreich abschließt.

Die Literatur zu verteilten Sperren beschreibt ähnliche Entwürfe:

Warum bieten etcd und andere Systeme Leases, wenn sie gegenseitigen Ausschluss durch Versionsnummernvalidierung gewährleisten? Leases dienen als Optimierung, um die Anzahl abgebrochener Anfragen zu verringern.

Schlüssel in etcd lassen sich dank Leases und Versionsnummernvalidierung effizient sperren. Müssen Benutzer Ressourcen außerhalb von etcd schützen, müssen diese wie etcd-Schlüssel eine Versionsnummernvalidierung und konsistente Replikate bereitstellen. Die Sperrfunktion von etcd allein kann externe Ressourcen nicht schützen.

12.9 - Glossar

Begriffe in der etcd-Dokumentation, der Befehlszeile und dem Quellcode

Dieses Dokument definiert die verschiedenen Begriffe, die in der etcd-Dokumentation, der Befehlszeile und dem Quellcode verwendet werden.

Alarm

Der etcd-Server löst einen Alarm aus, wenn ein Eingriff des Betreibers erforderlich ist, damit der Cluster zuverlässig bleibt.

Authentifizierung

Die Authentifizierung verwaltet die Zugriffsberechtigungen von Benutzern auf etcd-Ressourcen.

Client

Ein Client verbindet sich mit dem etcd-Cluster, um Dienstanfragen zu stellen, etwa zum Abrufen von Schlüssel-Wert-Paaren, zum Schreiben von Daten oder zum Beobachten von Änderungen.

Cluster

Ein Cluster besteht aus mehreren Mitgliedern.

Der Knoten in jedem Mitglied folgt dem Raft-Konsensprotokoll, um Logs zu replizieren. Der Cluster empfängt Vorschläge von Mitgliedern, bestätigt sie und wendet sie auf den lokalen Speicher an.

Kompaktierung

Die Kompaktierung verwirft den gesamten etcd-Ereignisverlauf und die ersetzten Schlüssel vor einer bestimmten Revision. Sie dient dazu, Speicherplatz in der Backend-Datenbank von etcd zurückzugewinnen.

Wahl

Der etcd-Cluster hält im Rahmen des Raft-Konsensprotokolls Wahlen unter seinen Mitgliedern ab, um einen Leader zu bestimmen.

Endpunkt

Eine URL, die auf einen etcd-Dienst oder eine etcd-Ressource verweist.

Schlüssel

Ein benutzerdefinierter Bezeichner zum Speichern und Abrufen benutzerdefinierter Werte in etcd.

Schlüsselbereich

Eine Schlüsselmenge, die entweder einen einzelnen Schlüssel, ein lexikalisches Intervall für alle x mit a <= x < b oder alle Schlüssel größer als ein bestimmter Schlüssel enthält.

Schlüsselraum

Die Menge aller Schlüssel in einem etcd-Cluster.

Lease

Eine kurzlebige, verlängerbare Vereinbarung, die bei ihrem Ablauf die ihr zugeordneten Schlüssel löscht.

Mitglied

Ein logischer etcd-Server, der am Betrieb eines etcd-Clusters beteiligt ist.

Änderungsrevision

Die erste Revision, die den letzten Schreibvorgang für einen bestimmten Schlüssel enthält.

Peer

Ein Peer ist ein anderes Mitglied desselben Clusters.

Vorschlag

Ein Vorschlag ist eine Anfrage, etwa eine Schreibanfrage oder eine Anfrage zur Konfigurationsänderung, die das Raft-Protokoll durchlaufen muss.

Quorum

Die Anzahl aktiver Mitglieder, die für einen Konsens zur Änderung des Clusterzustands benötigt wird. etcd benötigt eine Mehrheit der Mitglieder, um ein Quorum zu erreichen.

Revision

Ein clusterweiter 64-Bit-Zähler, der bei 1 beginnt und bei jeder Änderung des Schlüsselraums erhöht wird.

Rolle

Eine Einheit von Berechtigungen für eine Menge von Schlüsselbereichen, die zur Zugriffskontrolle einer Menge von Benutzern zugewiesen werden kann.

Snapshot

Ein Backup des etcd-Clusterzustands zu einem bestimmten Zeitpunkt.

Speicher

Der physische Speicher, in dem der Schlüsselraum des Clusters abgelegt ist.

Term

Ein Term ist eine monoton steigende Ganzzahl, die im Raft-Algorithmus jeder Leader-Wahl zugeordnet wird. Pro Term kann es nur einen gewählten Leader geben. Bei einem Leader-Wechsel wird der Term erhöht.

Transaktion

Eine atomar ausgeführte Menge von Operationen. Alle in einer Transaktion geänderten Schlüssel haben dieselbe Änderungsrevision.

Schlüsselversion

Die Anzahl der Schreibvorgänge für einen Schlüssel seit seiner Erstellung, beginnend bei 1. Die Version eines nicht vorhandenen oder gelöschten Schlüssels ist 0.

Watcher

Ein Client öffnet einen Watcher, um Änderungen in einem bestimmten Schlüsselbereich zu beobachten.

13 - Entwicklerhandbuch

etcd-Handbuch für Entwickler

13.1 - Protokoll des Discovery-Dienstes

Andere etcd-Mitglieder während der Clusterinitialisierung finden
Hinweis

Diese Seite dokumentiert das ältere v2-Discovery-Protokoll, das in etcd 3.7 entfernt wurde. Für eine neue v3.7-Installation das v3-Discovery-Protokoll verwenden.

Das Protokoll des Discovery-Dienstes hilft einem neuen etcd-Mitglied, während der Clusterinitialisierung alle anderen Mitglieder über eine gemeinsame Discovery-URL zu finden.

Das Protokoll des Discovery-Dienstes wird nur während der Clusterinitialisierung verwendet. Es kann nicht zur Neukonfiguration im laufenden Betrieb oder zur Clusterüberwachung genutzt werden.

Das Protokoll verwendet ein neues Discovery-Token, um einen eindeutigen etcd-Cluster zu initialisieren. Ein Discovery-Token kann nur einen etcd-Cluster repräsentieren. Sobald das Discovery-Protokoll mit diesem Token startet, darf es nicht zur Initialisierung eines anderen etcd-Clusters verwendet werden, auch wenn der Vorgang auf halbem Weg fehlschlägt.

Der Rest dieses Artikels erläutert den Discovery-Ablauf anhand von Beispielen für einen selbst betriebenen Discovery-Cluster. Der öffentliche Discovery-Dienst discovery.etcd.io funktioniert ebenso, bietet jedoch eine zusätzliche Schicht, die unübersichtliche URLs verbirgt, UUIDs automatisch erzeugt und einen gewissen Schutz vor übermäßig vielen Anfragen bietet. Im Kern verwendet auch der öffentliche Discovery-Dienst einen etcd-Cluster als Datenspeicher, wie in diesem Dokument beschrieben.

Protokollablauf

Das Discovery-Protokoll nutzt einen internen etcd-Cluster, um die Initialisierung eines neuen Clusters zu koordinieren. Zuerst kommunizieren alle neuen Mitglieder mit dem Discovery-Dienst und helfen dabei, die erwartete Mitgliederliste zu erstellen. Anschließend initialisiert jedes neue Mitglied seinen Server anhand dieser Liste. Sie erfüllt dieselbe Funktion wie die Option -initial-cluster.

Im folgenden Beispielablauf wird jeder Protokollschritt zur Veranschaulichung im curl-Format dargestellt.

Das etcd-Discovery-Protokoll verwendet vereinbarungsgemäß das Schlüsselpräfix _etcd/registry. Wenn unter http://example.com ein etcd-Cluster für den Discovery-Dienst läuft, lautet die vollständige URL zum Discovery-Schlüsselraum http://example.com/v2/keys/_etcd/registry. Sie wird im Beispiel als URL-Präfix verwendet.

Ein neues Discovery-Token erstellen

Ein eindeutiges Token erzeugen, das den neuen Cluster identifiziert. In den folgenden Schritten dient es als eindeutiges Präfix im Discovery-Schlüsselraum. Mit uuidgen lässt es sich einfach erzeugen:

UUID=$(uuidgen)

Die erwartete Clustergröße angeben

Für das Discovery-Token muss eine Clustergröße angegeben werden. Anhand dieser Größe erkennt der Discovery-Dienst, wann er alle Mitglieder gefunden hat, die den Cluster anfänglich bilden sollen.

curl -X PUT http://example.com/v2/keys/_etcd/registry/${UUID}/_config/size -d value=${cluster_size}

Üblicherweise beträgt die Clustergröße 3, 5 oder 7. Weitere Einzelheiten enthält der Abschnitt zur optimalen Clustergröße .

etcd-Prozesse starten

Die Discovery-URL mit der Option -discovery angeben und die etcd-Prozesse starten. Jeder etcd-Prozess führt intern die folgenden Schritte aus, wenn die Option -discovery angegeben ist.

Selbstregistrierung

Zuerst registriert sich der etcd-Prozess unter der Discovery-URL als Mitglied. Dazu legt er die Mitglieds-ID als Schlüssel unter der Discovery-URL an.

curl -X PUT http://example.com/v2/keys/_etcd/registry/${UUID}/${member_id}?prevExist=false -d value="${member_name}=${member_peer_url_1}&${member_name}=${member_peer_url_2}"

Status prüfen

Er prüft die erwartete Clustergröße und den Registrierungsstatus unter der Discovery-URL und entscheidet dann über den nächsten Schritt.

curl -X GET http://example.com/v2/keys/_etcd/registry/${UUID}/_config/size
curl -X GET http://example.com/v2/keys/_etcd/registry/${UUID}

Wenn noch nicht genügend Mitglieder registriert sind, wartet er auf die übrigen Mitglieder.

Wenn die Anzahl registrierter Mitglieder die erwartete Größe N übersteigt, gelten die ersten N registrierten Mitglieder als Mitgliederliste des Clusters. Ist das Mitglied selbst in dieser Liste enthalten, ist der Discovery-Vorgang erfolgreich, und es ermittelt alle Peers anhand der Mitgliederliste. Ist es nicht enthalten, endet der Discovery-Vorgang mit der Fehlermeldung, dass der Cluster bereits voll ist.

In der etcd-Implementierung kann das Mitglied den Clusterstatus bereits vor seiner Registrierung prüfen. So kann es frühzeitig mit einem Fehler abbrechen, wenn der Cluster bereits voll ist.

Auf alle Mitglieder warten

Der Wartevorgang ist in der etcd-API-Dokumentation ausführlich beschrieben.

curl -X GET http://example.com/v2/keys/_etcd/registry/${UUID}?wait=true&waitIndex=${current_etcd_index}

Er wartet, bis alle Mitglieder gefunden sind.

Öffentlicher Discovery-Dienst

CoreOS Inc. betreibt unter https://discovery.etcd.io/ einen öffentlichen Discovery-Dienst mit einigen Funktionen, die die Nutzung erleichtern.

Schlüsselpräfix verbergen

Der öffentliche Discovery-Dienst leitet https://discovery.etcd.io/${UUID} zum dahinterliegenden etcd-Cluster auf den Schlüssel unter /v2/keys/_etcd/registry um. Er verbirgt das Registrierungsschlüsselpräfix, damit die Discovery-URL kurz und lesbar bleibt.

Neues Token abrufen

GET /new

Sent query:
	size=${cluster_size}
Possible status codes:
	200 OK
	400 Bad Request
200 Body:
	generated discovery url

Der Erzeugungsvorgang im Dienst folgt den Schritten von Ein neues Discovery-Token erstellen bis Die erwartete Clustergröße angeben .

Discovery-Status prüfen

GET /${UUID}

Der Status dieses Discovery-Tokens einschließlich der registrierten Rechner lässt sich durch Abfragen des Werts der UUID prüfen.

Open-Source-Repository

Das Repository befindet sich unter https://github.com/coreos/discovery.etcd.io . Damit lässt sich ein eigener Discovery-Dienst erstellen.

13.2 - Einen lokalen Cluster einrichten

Lokale Cluster für Tests und Entwicklung konfigurieren

Für Test- und Entwicklungsumgebungen ist die Konfiguration eines lokalen Clusters der schnellste und einfachste Weg. Für eine produktive Bereitstellung siehe den Abschnitt Cluster einrichten .

Lokaler eigenständiger Cluster

Einen Cluster starten

Mit folgendem Befehl wird ein eigenständiger etcd-Cluster bereitgestellt:

$ ./etcd
...

Wenn die Binärdatei etcd nicht im aktuellen Arbeitsverzeichnis liegt, befindet sie sich möglicherweise unter $GOPATH/bin/etcd oder /usr/local/bin/etcd. Den Befehl entsprechend ausführen.

Das laufende etcd-Mitglied nimmt unter localhost:2379 Client-Anfragen entgegen.

Mit dem Cluster arbeiten

Mit etcdctl lässt sich mit dem laufenden Cluster arbeiten:

  1. Ein beispielhaftes Schlüssel-Wert-Paar im Cluster speichern:

      $ ./etcdctl put foo bar
      OK

    Wenn OK ausgegeben wird, wurde das Schlüssel-Wert-Paar erfolgreich gespeichert.

  2. Den Wert von foo abrufen:

    $ ./etcdctl get foo
    bar

    Wenn bar zurückgegeben wird, funktioniert die Interaktion mit dem etcd-Cluster wie erwartet.

Lokaler Cluster mit mehreren Mitgliedern

Einen Cluster starten

Im Stammverzeichnis des etcd-Git-Repositorys liegt eine Procfile, mit der sich ein lokaler Cluster mit mehreren Mitgliedern einfach konfigurieren lässt. Zum Starten eines solchen Clusters in das Stammverzeichnis des etcd-Quellbaums wechseln und Folgendes ausführen:

  1. goreman installieren, um auf Procfile basierende Anwendungen zu steuern:

    $ go install github.com/mattn/goreman@latest
  2. Einen Cluster mit goreman und der mitgelieferten Procfile von etcd starten:

    $ goreman -f Procfile start

    Die Mitglieder starten. Sie nehmen Client-Anfragen unter localhost:2379, localhost:22379 beziehungsweise localhost:32379 entgegen.

Mit dem Cluster arbeiten

Mit etcdctl lässt sich mit dem laufenden Cluster arbeiten:

  1. Die Mitgliederliste ausgeben:

    $ etcdctl --write-out=table --endpoints=localhost:2379 member list

    Die Liste der etcd-Mitglieder wird wie folgt angezeigt:

    +------------------+---------+--------+------------------------+------------------------+
    |        ID        | STATUS  |  NAME  |       PEER ADDRS       |      CLIENT ADDRS      |
    +------------------+---------+--------+------------------------+------------------------+
    | 8211f1d0f64f3269 | started | infra1 | http://127.0.0.1:2380  | http://127.0.0.1:2379  |
    | 91bc3c398fb3c146 | started | infra2 | http://127.0.0.1:22380 | http://127.0.0.1:22379 |
    | fd422379fda50e48 | started | infra3 | http://127.0.0.1:32380 | http://127.0.0.1:32379 |
    +------------------+---------+--------+------------------------+------------------------+
  2. Ein beispielhaftes Schlüssel-Wert-Paar im Cluster speichern:

    $ etcdctl put foo bar
    OK

    Wenn OK ausgegeben wird, wurde das Schlüssel-Wert-Paar erfolgreich gespeichert.

Fehlertoleranz testen

Um die Fehlertoleranz von etcd zu testen, ein Mitglied beenden und versuchen, den Schlüssel abzurufen.

  1. Den Prozessnamen des Mitglieds ermitteln, das angehalten werden soll.

    Die Procfile enthält die Eigenschaften des Clusters mit mehreren Mitgliedern. Als Beispiel dient das Mitglied mit dem Prozessnamen etcd2.

  2. Das Mitglied anhalten:

    # kill etcd2
    $ goreman run stop etcd2
  3. Einen Schlüssel speichern:

    $ etcdctl put key hello
    OK
  4. Den im vorherigen Schritt gespeicherten Schlüssel abrufen:

    $ etcdctl get key
    hello
  5. Einen Schlüssel vom angehaltenen Mitglied abrufen:

    $ etcdctl --endpoints=localhost:22379 get key

    Der Befehl sollte wegen der fehlgeschlagenen Verbindung eine Fehlermeldung anzeigen:

    2017/06/18 23:07:35 grpc: Conn.resetTransport failed to create client transport: connection error: desc = "transport: dial tcp 127.0.0.1:22379: getsockopt: connection refused"; Reconnecting to "localhost:22379"
    Error:  grpc: timed out trying to connect
  6. Das angehaltene Mitglied neu starten:

    $ goreman run restart etcd2
  7. Den Schlüssel vom neu gestarteten Mitglied abrufen:

    $ etcdctl --endpoints=localhost:22379 get key
    hello

    Der Neustart des Mitglieds stellt die Verbindung wieder her. etcdctl kann den Schlüssel nun erfolgreich abrufen. Weitere Informationen zur Arbeit mit etcd enthält der Abschnitt Mit etcd arbeiten .

13.3 - Mit etcd arbeiten

etcdctl: ein Befehlszeilenwerkzeug zur Interaktion mit dem etcd-Server

Benutzer arbeiten mit etcd meist, indem sie den Wert eines Schlüssels schreiben oder lesen. Dieser Abschnitt beschreibt dies anhand von etcdctl, einem Befehlszeilenwerkzeug zur Interaktion mit dem etcd-Server. Die erläuterten Konzepte sollten auch für die gRPC-APIs und die APIs der Client-Bibliotheken gelten.

etcdctl v3.7 verwendet die v3-API. Die v2-API und die Versionsauswahl über ETCDCTL_API wurden entfernt.

Hinweis

Die folgenden Beispiele enthalten historische Befehlsausgaben; die angezeigten Versionsnummern können daher von Ihrer Installation abweichen. Frühere etcd-Versionen hielten v2- und v3-Schlüssel in getrennten Speichern. Migrieren Sie vorhandene v2-Daten vor dem Upgrade auf v3.7.

Versionen ermitteln

Die etcdctl-Version und die API-Version des Servers helfen dabei, die passenden Befehle für verschiedene etcd-Operationen zu bestimmen.

Mit folgendem Befehl lassen sich die Versionen ermitteln:

$ etcdctl version
etcdctl version: 3.1.0-alpha.0+git
API version: 3.1

Einen Schlüssel schreiben

Anwendungen speichern Schlüssel im etcd-Cluster, indem sie Werte unter diesen Schlüsseln schreiben. Jeder gespeicherte Schlüssel wird über das Raft-Protokoll auf alle Mitglieder des etcd-Clusters repliziert, um Konsistenz und Zuverlässigkeit zu gewährleisten.

Mit folgendem Befehl wird der Wert des Schlüssels foo auf bar gesetzt:

$ etcdctl put foo bar
OK

Ein Schlüssel kann durch Zuordnen einer Lease auch für einen festgelegten Zeitraum gesetzt werden.

Mit folgendem Befehl wird der Wert des Schlüssels foo1 für 10s auf bar1 gesetzt.

$ etcdctl put foo1 bar1 --lease=1234abcd
OK
Hinweis

Die Lease-ID 1234abcd im obigen Befehl ist die ID, die beim Erstellen der Lease mit 10s Laufzeit zurückgegeben wird. Diese ID kann anschließend dem Schlüssel zugeordnet werden.

Schlüssel lesen

Anwendungen können Schlüsselwerte aus einem etcd-Cluster lesen. Abfragen können einen einzelnen Schlüssel oder einen Schlüsselbereich lesen.

Angenommen, im etcd-Cluster sind folgende Schlüssel gespeichert:

foo = bar
foo1 = bar1
foo2 = bar2
foo3 = bar3

Mit folgendem Befehl wird der Wert des Schlüssels foo gelesen:

$ etcdctl get foo
foo
bar

Mit folgendem Befehl wird der Wert des Schlüssels foo im Hexadezimalformat gelesen:

$ etcdctl get foo --hex
\x66\x6f\x6f          # Key
\x62\x61\x72          # Value

Mit folgendem Befehl wird nur der Wert des Schlüssels foo gelesen:

$ etcdctl get foo --print-value-only
bar

Mit folgendem Befehl werden die Schlüssel von foo bis foo3 abgefragt:

$ etcdctl get foo foo3
foo
bar
foo1
bar1
foo2
bar2
Hinweis

foo3 ist ausgeschlossen, da der Bereich dem halboffenen Intervall [foo, foo3) entspricht, das foo3 nicht enthält.

Mit folgendem Befehl werden alle Schlüssel mit dem Präfix foo abgefragt:

$ etcdctl get --prefix foo
foo
bar
foo1
bar1
foo2
bar2
foo3
bar3

Mit folgendem Befehl werden alle Schlüssel mit dem Präfix foo abgefragt und die Ergebnisse auf 2 begrenzt:

$ etcdctl get --prefix --limit=2 foo
foo
bar
foo1
bar1

Mit folgendem Befehl werden alle Schlüssel mit dem Präfix foo über den RPC RangeStream abgefragt. Das Ergebnis ist mit dem eines unären Range-Aufrufs identisch:

$ etcdctl get --stream --prefix foo
foo
bar
foo1
bar1
foo2
bar2
foo3
bar3

--stream unterstützt weder --order noch --sort-by noch Revisionsfilter.

Frühere Schlüsselversionen lesen

Anwendungen möchten möglicherweise ersetzte Versionen eines Schlüssels lesen. Beispielsweise kann eine Anwendung durch Zugriff auf eine frühere Schlüsselversion zu einer alten Konfiguration zurückkehren. Oder sie kann durch den Schlüsselverlauf über mehrere Anfragen hinweg eine konsistente Sicht auf mehrere Schlüssel erhalten. Da jede Änderung am Schlüssel-Wert-Speicher des etcd-Clusters dessen globale Revision erhöht, kann eine Anwendung ersetzte Schlüssel durch Angabe einer älteren etcd-Revision lesen.

Angenommen, im etcd-Cluster sind bereits folgende Schlüssel gespeichert:

foo = bar         # revision = 2
foo1 = bar1       # revision = 3
foo = bar_new     # revision = 4
foo1 = bar1_new   # revision = 5

Das folgende Beispiel zeigt den Zugriff auf frühere Schlüsselversionen:

$ etcdctl get --prefix foo # access the most recent versions of keys
foo
bar_new
foo1
bar1_new

$ etcdctl get --prefix --rev=4 foo # access the versions of keys at revision 4
foo
bar_new
foo1
bar1

$ etcdctl get --prefix --rev=3 foo # access the versions of keys at revision 3
foo
bar
foo1
bar1

$ etcdctl get --prefix --rev=2 foo # access the versions of keys at revision 2
foo
bar

$ etcdctl get --prefix --rev=1 foo # access the versions of keys at revision 1

Schlüssel lesen, deren Bytewert größer oder gleich dem angegebenen Schlüssel ist

Anwendungen möchten möglicherweise Schlüssel lesen, deren Bytewert größer oder gleich dem des angegebenen Schlüssels ist.

Angenommen, im etcd-Cluster sind bereits folgende Schlüssel gespeichert:

a = 123
b = 456
z = 789

Mit folgendem Befehl werden Schlüssel gelesen, deren Bytewert größer oder gleich dem des Schlüssels b ist:

$ etcdctl get --from-key b
b
456
z
789

Schlüssel löschen

Anwendungen können einen einzelnen Schlüssel oder einen Schlüsselbereich aus einem etcd-Cluster löschen.

Angenommen, im etcd-Cluster sind bereits folgende Schlüssel gespeichert:

foo = bar
foo1 = bar1
foo3 = bar3
zoo = val
zoo1 = val1
zoo2 = val2
a = 123
b = 456
z = 789

Mit folgendem Befehl wird der Schlüssel foo gelöscht:

$ etcdctl del foo
1 # one key is deleted

Mit folgendem Befehl werden die Schlüssel von foo bis foo9 gelöscht:

$ etcdctl del foo foo9
2 # two keys are deleted

Mit folgendem Befehl wird der Schlüssel zoo gelöscht und das gelöschte Schlüssel-Wert-Paar zurückgegeben:

$ etcdctl del --prev-kv zoo
1   # one key is deleted
zoo # deleted key
val # the value of the deleted key

Mit folgendem Befehl werden Schlüssel mit dem Präfix zoo gelöscht:

$ etcdctl del --prefix zoo
2 # two keys are deleted

Mit folgendem Befehl werden Schlüssel gelöscht, deren Bytewert größer oder gleich dem des Schlüssels b ist:

$ etcdctl del --from-key b
2 # two keys are deleted

Schlüsseländerungen beobachten

Anwendungen können einen Schlüssel oder einen Schlüsselbereich beobachten, um sämtliche Aktualisierungen zu überwachen.

Mit folgendem Befehl wird der Schlüssel foo beobachtet:

$ etcdctl watch foo
# in another terminal: etcdctl put foo bar
PUT
foo
bar

Mit folgendem Befehl wird der Schlüssel foo im Hexadezimalformat beobachtet:

$ etcdctl watch foo --hex
# in another terminal: etcdctl put foo bar
PUT
\x66\x6f\x6f          # Key
\x62\x61\x72          # Value

Mit folgendem Befehl wird der Schlüsselbereich von foo bis foo9 beobachtet:

$ etcdctl watch foo foo9
# in another terminal: etcdctl put foo bar
PUT
foo
bar
# in another terminal: etcdctl put foo1 bar1
PUT
foo1
bar1

Mit folgendem Befehl werden Schlüssel mit dem Präfix foo beobachtet:

$ etcdctl watch --prefix foo
# in another terminal: etcdctl put foo bar
PUT
foo
bar
# in another terminal: etcdctl put fooz1 barz1
PUT
fooz1
barz1

Mit folgendem Befehl werden die beiden Schlüssel foo und zoo beobachtet:

$ etcdctl watch -i
$ watch foo
$ watch zoo
# in another terminal: etcdctl put foo bar
PUT
foo
bar
# in another terminal: etcdctl put zoo val
PUT
zoo
val

Historische Schlüsseländerungen beobachten

Anwendungen möchten möglicherweise historische Änderungen an Schlüsseln in etcd beobachten. Beispielsweise kann eine Anwendung alle Änderungen eines Schlüssels empfangen wollen. Solange sie mit etcd verbunden bleibt, genügt dafür watch. Fällt jedoch die Anwendung oder etcd aus, kann während des Ausfalls eine Änderung auftreten, die die Anwendung nicht in Echtzeit empfängt. Um die Zustellung der Aktualisierung zu garantieren, muss die Anwendung historische Schlüsseländerungen beobachten können. Dazu kann sie wie beim Lesen früherer Schlüsselversionen eine historische Revision für einen Watch angeben.

Angenommen, die folgende Folge von Operationen wurde ausgeführt:

$ etcdctl put foo bar         # revision = 2
OK
$ etcdctl put foo1 bar1       # revision = 3
OK
$ etcdctl put foo bar_new     # revision = 4
OK
$ etcdctl put foo1 bar1_new   # revision = 5
OK

Das folgende Beispiel zeigt die Beobachtung historischer Änderungen:

# watch for changes on key `foo` since revision 2
$ etcdctl watch --rev=2 foo
PUT
foo
bar
PUT
foo
bar_new
# watch for changes on key `foo` since revision 3
$ etcdctl watch --rev=3 foo
PUT
foo
bar_new

Das folgende Beispiel beobachtet erst ab der letzten historischen Änderung:

# watch for changes on key `foo` and return last revision value along with modified value
$ etcdctl watch --prev-kv foo
# in another terminal: etcdctl put foo bar_latest
PUT
foo         # key
bar_new     # last value of foo key before modification
foo         # key
bar_latest  # value of foo key after modification

Watch-Fortschritt

Anwendungen möchten möglicherweise den Fortschritt eines Watches prüfen, um die Aktualität seines Streams zu bestimmen. Wird ein Watch beispielsweise zur Aktualisierung eines Caches verwendet, kann es hilfreich sein zu wissen, ob der Cache gegenüber der Revision eines Quorum-Lesezugriffs veraltet ist.

In einer interaktiven Watch-Sitzung kann mit dem Befehl “progress” eine Fortschrittsanfrage gestellt werden. Sie fordert den etcd-Server auf, eine Fortschrittsbenachrichtigung im Watch-Stream zu senden:

$ etcdctl watch -i
$ watch a
$ progress
progress notify: 1
# in another terminal: etcdctl put x 0
# in another terminal: etcdctl put y 1
$ progress
progress notify: 3
Hinweis

Die Revisionsnummer in der Fortschrittsantwort stammt vom lokalen etcd-Serverknoten, mit dem der Watch-Stream verbunden ist. Ist dieser Knoten durch eine Netzwerkpartition abgetrennt und nicht Teil des Quorums, kann diese Revision niedriger sein als die Revision eines Quorum-Lesezugriffs auf einen nicht abgetrennten etcd-Serverknoten.

Kompaktierte Revisionen

Wie erwähnt, bewahrt etcd Revisionen auf, damit Anwendungen frühere Schlüsselversionen lesen können. Damit sich jedoch kein unbegrenzt großer Verlauf ansammelt, ist es wichtig, frühere Revisionen zu kompaktieren. Nach der Kompaktierung entfernt etcd historische Revisionen und gibt Ressourcen für die spätere Nutzung frei. Alle ersetzten Daten mit Revisionen vor der Kompaktierungsrevision sind dann nicht mehr verfügbar.

Mit folgendem Befehl werden die Revisionen kompaktiert:

$ etcdctl compact 5
compacted revision 5

# any revisions before the compacted one are not accessible
$ etcdctl get --rev=4 foo
Error:  rpc error: code = 11 desc = etcdserver: mvcc: required revision has been compacted
Hinweis

Die aktuelle Revision des etcd-Servers lässt sich mit einem get-Befehl im JSON-Format für einen beliebigen vorhandenen oder nicht vorhandenen Schlüssel ermitteln. Das folgende Beispiel verwendet mykey, das im etcd-Server nicht existiert:

$ etcdctl get mykey -w=json
{"header":{"cluster_id":14841639068965178418,"member_id":10276657743932975437,"revision":15,"raft_term":4}}

Leases gewähren

Anwendungen können vom etcd-Cluster Leases für Schlüssel anfordern. Wird ein Schlüssel einer Lease zugeordnet, ist seine Lebensdauer an die der Lease gebunden, die ihrerseits durch eine Time-to-live (TTL) bestimmt wird. Jede Lease hat eine Mindest-TTL, die die Anwendung bei der Anforderung angibt. Ihre tatsächliche TTL ist mindestens so groß wie die Mindest-TTL und wird vom etcd-Cluster gewählt. Sobald sie verstrichen ist, läuft die Lease ab, und alle zugeordneten Schlüssel werden gelöscht.

Mit folgendem Befehl wird eine Lease gewährt:

# grant a lease with 60 second TTL
$ etcdctl lease grant 60
lease 32695410dcc0ca06 granted with TTL(60s)

# attach key foo to lease 32695410dcc0ca06
$ etcdctl put --lease=32695410dcc0ca06 foo bar
OK

Leases widerrufen

Anwendungen widerrufen Leases anhand ihrer Lease-ID. Dabei werden alle der Lease zugeordneten Schlüssel gelöscht.

Angenommen, die folgende Folge von Operationen wurde ausgeführt:

$ etcdctl lease grant 60
lease 32695410dcc0ca06 granted with TTL(60s)
$ etcdctl put --lease=32695410dcc0ca06 foo bar
OK

Mit folgendem Befehl wird dieselbe Lease widerrufen:

$ etcdctl lease revoke 32695410dcc0ca06
lease 32695410dcc0ca06 revoked

$ etcdctl get foo
# empty response since foo is deleted due to lease revocation

Leases am Leben halten

Anwendungen können eine Lease am Leben halten, indem sie deren TTL erneuern und so ihren Ablauf verhindern.

Angenommen, die folgende Folge von Operationen wurde ausgeführt:

$ etcdctl lease grant 60
lease 32695410dcc0ca06 granted with TTL(60s)

Mit folgendem Befehl wird dieselbe Lease am Leben gehalten:

$ etcdctl lease keep-alive 32695410dcc0ca06
lease 32695410dcc0ca06 keepalived with TTL(60)
lease 32695410dcc0ca06 keepalived with TTL(60)
lease 32695410dcc0ca06 keepalived with TTL(60)
...

Lease-Informationen abrufen

Anwendungen möchten möglicherweise Informationen über Leases abrufen, um sie zu erneuern oder zu prüfen, ob eine Lease noch existiert oder bereits abgelaufen ist. Sie möchten möglicherweise auch wissen, welchen Schlüsseln eine bestimmte Lease zugeordnet ist.

Angenommen, die folgende Folge von Operationen wurde ausgeführt:

# grant a lease with 500 second TTL
$ etcdctl lease grant 500
lease 694d5765fc71500b granted with TTL(500s)

# attach key zoo1 to lease 694d5765fc71500b
$ etcdctl put zoo1 val1 --lease=694d5765fc71500b
OK

# attach key zoo2 to lease 694d5765fc71500b
$ etcdctl put zoo2 val2 --lease=694d5765fc71500b
OK

Mit folgendem Befehl werden Informationen zur Lease abgerufen:

$ etcdctl lease timetolive 694d5765fc71500b
lease 694d5765fc71500b granted with TTL(500s), remaining(258s)

Mit folgendem Befehl werden Informationen zur Lease einschließlich der ihr zugeordneten Schlüssel abgerufen:

$ etcdctl lease timetolive --keys 694d5765fc71500b
lease 694d5765fc71500b granted with TTL(500s), remaining(132s), attached keys([zoo2 zoo1])

# if the lease has expired or does not exist it will give the below response:
Error:  etcdserver: requested lease not found

13.4 - Warum ein gRPC-Gateway

Gründe für die Verwendung des gRPC-Gateways

etcd v3 verwendet gRPC als Nachrichtenprotokoll. Das etcd-Projekt enthält einen gRPC-basierten Go-Client und das Befehlszeilenwerkzeug etcdctl zur Kommunikation mit einem etcd-Cluster über gRPC. Für Sprachen ohne gRPC-Unterstützung stellt etcd ein JSON-gRPC-Gateway bereit. Dieses Gateway dient als RESTful-Proxy, der HTTP/JSON-Anfragen in gRPC-Nachrichten übersetzt.

Das gRPC-Gateway verwenden

Das Gateway akzeptiert eine JSON-Abbildung der Protocol-Buffer -Nachrichtendefinitionen von etcd. Die Felder key und value sind als Byte-Arrays definiert und müssen deshalb in JSON base64-kodiert sein. Die folgenden Beispiele verwenden curl, jeder andere HTTP/JSON-Client sollte jedoch ebenso funktionieren.

Hinweise

Der Endpunkt des gRPC-Gateways hat sich seit etcd v3.3 geändert:

  • etcd v3.2 und frühere Versionen verwenden ausschließlich [CLIENT-URL]/v3alpha/*.
  • etcd v3.3 verwendet [CLIENT-URL]/v3beta/* und behält [CLIENT-URL]/v3alpha/* bei.
  • etcd v3.4 verwendet [CLIENT-URL]/v3/* und behält [CLIENT-URL]/v3beta/* bei.
    • [CLIENT-URL]/v3alpha/* ist veraltet.
  • etcd v3.5 und spätere Versionen verwenden ausschließlich [CLIENT-URL]/v3/*.
    • [CLIENT-URL]/v3beta/* ist veraltet.

Das gRPC-Gateway unterstützt keine Authentifizierung über den TLS Common Name.

Schlüssel schreiben und lesen

Die Dienste /v3/kv/range und /v3/kv/put zum Lesen und Schreiben von Schlüsseln verwenden:

<<COMMENT
https://www.base64encode.org/
foo is 'Zm9v' in Base64
bar is 'YmFy'
COMMENT

curl -L http://localhost:2379/v3/kv/put \
  -X POST -d '{"key": "Zm9v", "value": "YmFy"}'
# {"header":{"cluster_id":"12585971608760269493","member_id":"13847567121247652255","revision":"2","raft_term":"3"}}

curl -L http://localhost:2379/v3/kv/range \
  -X POST -d '{"key": "Zm9v"}'
# {"header":{"cluster_id":"12585971608760269493","member_id":"13847567121247652255","revision":"2","raft_term":"3"},"kvs":[{"key":"Zm9v","create_revision":"2","mod_revision":"2","version":"1","value":"YmFy"}],"count":"1"}

# get all keys prefixed with "foo"
curl -L http://localhost:2379/v3/kv/range \
  -X POST -d '{"key": "Zm9v", "range_end": "Zm9w"}'
# {"header":{"cluster_id":"12585971608760269493","member_id":"13847567121247652255","revision":"2","raft_term":"3"},"kvs":[{"key":"Zm9v","create_revision":"2","mod_revision":"2","version":"1","value":"YmFy"}],"count":"1"}

Schlüssel beobachten

Den Dienst /v3/watch zum Beobachten von Schlüsseln verwenden:

curl -N http://localhost:2379/v3/watch \
  -X POST -d '{"create_request": {"key":"Zm9v"} }' &
# {"result":{"header":{"cluster_id":"12585971608760269493","member_id":"13847567121247652255","revision":"1","raft_term":"2"},"created":true}}

curl -L http://localhost:2379/v3/kv/put \
  -X POST -d '{"key": "Zm9v", "value": "YmFy"}' >/dev/null 2>&1
# {"result":{"header":{"cluster_id":"12585971608760269493","member_id":"13847567121247652255","revision":"2","raft_term":"2"},"events":[{"kv":{"key":"Zm9v","create_revision":"2","mod_revision":"2","version":"1","value":"YmFy"}}]}}

Transaktionen

Eine Transaktion mit /v3/kv/txn ausführen:

# target CREATE
curl -L http://localhost:2379/v3/kv/txn \
  -X POST \
  -d '{"compare":[{"target":"CREATE","key":"Zm9v","createRevision":"2"}],"success":[{"requestPut":{"key":"Zm9v","value":"YmFy"}}]}'
# {"header":{"cluster_id":"12585971608760269493","member_id":"13847567121247652255","revision":"3","raft_term":"2"},"succeeded":true,"responses":[{"response_put":{"header":{"revision":"3"}}}]}
# target VERSION
curl -L http://localhost:2379/v3/kv/txn \
  -X POST \
  -d '{"compare":[{"version":"4","result":"EQUAL","target":"VERSION","key":"Zm9v"}],"success":[{"requestRange":{"key":"Zm9v"}}]}'
# {"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"6","raft_term":"3"},"succeeded":true,"responses":[{"response_range":{"header":{"revision":"6"},"kvs":[{"key":"Zm9v","create_revision":"2","mod_revision":"6","version":"4","value":"YmF6"}],"count":"1"}}]}

Authentifizierung

Die Authentifizierung mit dem Dienst /v3/auth einrichten:

# create root user
curl -L http://localhost:2379/v3/auth/user/add \
  -X POST -d '{"name": "root", "password": "pass"}'
# {"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"1","raft_term":"2"}}

# create root role
curl -L http://localhost:2379/v3/auth/role/add \
  -X POST -d '{"name": "root"}'
# {"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"1","raft_term":"2"}}

# grant root role
curl -L http://localhost:2379/v3/auth/user/grant \
  -X POST -d '{"user": "root", "role": "root"}'
# {"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"1","raft_term":"2"}}

# enable auth
curl -L http://localhost:2379/v3/auth/enable -X POST -d '{}'
# {"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"1","raft_term":"2"}}

Mit /v3/auth/authenticate bei etcd authentifizieren, um ein Authentifizierungstoken zu erhalten:

# get the auth token for the root user
curl -L http://localhost:2379/v3/auth/authenticate \
  -X POST -d '{"name": "root", "password": "pass"}'
# {"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"1","raft_term":"2"},"token":"sssvIpwfnLAcWAQH.9"}

Den Header Authorization auf das Authentifizierungstoken setzen, um einen Schlüssel mit Authentifizierungsdaten abzurufen:

curl -L http://localhost:2379/v3/kv/put \
  -H 'Authorization: sssvIpwfnLAcWAQH.9' \
  -X POST -d '{"key": "Zm9v", "value": "YmFy"}'
# {"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"2","raft_term":"2"}}

Fehlerantworten

Das gRPC-Gateway übersetzt den gRPC-Status in HTTP-Statuscodes und einen JSON-Fehlerinhalt. Ab etcd v3.6 änderte die Aktualisierung auf grpc-gateway v2 die Fehlerbehandlung (siehe den Hinweis zur Fehlerbehandlung im v2-Migrationsleitfaden). Das Verhalten des Gateways entspricht nun google.rpc.Status (code, message, details), wie im API-Fehlermodell von Google beschrieben. Ältere grpc-gateway-Versionen enthielten außerdem ein error-Feld auf oberster Ebene. Dieses Feld wird in etcd v3.6 und neueren Versionen nicht unterstützt.

Clients sollten den HTTP-Statuscode als vorrangigen Hinweis auf Erfolg oder Fehlschlag behandeln. Schlägt eine Anfrage fehl, sollten Clients das Feld message als wichtigste Quelle für Fehlerinformationen verwenden und zusätzliche Details zur weiteren Einordnung heranziehen.

Swagger

Generierte Swagger -API-Definitionen stehen unter rpc.swagger.json bereit.

13.5 - gRPC-Namensauflösung und Discovery

go-grpc: gRPC-Endpunkte mit einem etcd-Backend auflösen

etcd stellt einen gRPC-Resolver für ein alternatives Namenssystem bereit, das Endpunkte aus etcd abruft, um gRPC-Dienste zu finden. Der zugrunde liegende Mechanismus beobachtet Änderungen an Schlüsseln, deren Präfix der Dienstname ist.

Diese Funktion ist experimentell, da sie vom Paket google.golang.org/grpc/resolver abhängt, das in grpc-go noch experimentell ist.

etcd-Discovery mit go-grpc verwenden

Der etcd-Client stellt einen gRPC-Resolver bereit, der gRPC-Endpunkte mit einem etcd-Backend auflöst. Der Resolver wird mit einem etcd-Client initialisiert:

import (
	clientv3 "go.etcd.io/etcd/client/v3"
	etcdnaming "go.etcd.io/etcd/client/v3/naming/resolver"

	"google.golang.org/grpc"
)

...

cli, err := clientv3.NewFromURL("http://localhost:2379")
if err != nil {
    // ...
}
r, err := etcdnaming.NewBuilder(cli)
if err != nil {
    // ...
}
conn, gerr := grpc.NewClient("my-service", grpc.WithResolvers(r), ...)

Dienstendpunkte verwalten

Der etcd-Resolver betrachtet alle Schlüssel unter dem Präfix des Auflösungsziels, gefolgt von einem “/” (z. B. “foo/bar/my-service/”), mit JSON-kodierten Werten (früher go-grpc naming.Update) als mögliche Dienstendpunkte. Durch Anlegen neuer Schlüssel werden Endpunkte zum Dienst hinzugefügt; durch Löschen der Schlüssel werden sie entfernt.

Einen Endpunkt hinzufügen

Neue Endpunkte lassen sich mit etcdctl zum Dienst hinzufügen:

ETCDCTL_API=3 etcdctl put foo/bar/my-service/1.2.3.4 '{"Addr":"1.2.3.4"}'

Die Methode endpoints.Manager des etcd-Clients kann ebenfalls neue Endpunkte mit einem zu Addr passenden Schlüssel registrieren:


em := endpoints.NewManager(client, "foo/bar/my-service")
err := em.AddEndpoint(context.TODO(),"foo/bar/my-service/e1", endpoints.Endpoint{Addr:"1.2.3.4"})

Um beim Verbindungsaufbau zu einem Dienst mit mehreren Endpunkten Round-Robin-Lastverteilung zu aktivieren, kann die Verbindung mit dem internen Round-Robin-Load-Balancer von grpc eingerichtet werden:


conn, gerr := grpc.NewClient("etcd:///foo", grpc.WithResolvers(etcdResolver),
grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy":"round_robin"}`))

Einen Endpunkt löschen

Hosts lassen sich mit etcdctl aus dem Dienst entfernen:

ETCDCTL_API=3 etcdctl del foo/bar/my-service/1.2.3.4

Die Methode endpoints.Manager des etcd-Clients unterstützt auch das Löschen von Endpunkten:

em := endpoints.NewManager(client, "foo/bar/my-service")
err := em.DeleteEndpoint(context.TODO(), "foo/bar/my-service/e1")

Einen Endpunkt mit einer Lease registrieren

Die Registrierung eines Endpunkts mit einer Lease stellt sicher, dass er aus dem Dienst entfernt wird, wenn der Host keinen Keepalive-Heartbeat mehr aufrechterhalten kann, etwa bei einem Ausfall des Rechners:

lease=`ETCDCTL_API=3 etcdctl lease grant 5 | cut -f2 -d' '`
ETCDCTL_API=3 etcdctl put --lease=$lease my-service/1.2.3.4 '{"Addr":"1.2.3.4"}'
ETCDCTL_API=3 etcdctl lease keep-alive $lease

In Go:

em := endpoints.NewManager(client, "foo/bar/my-service")
err := em.AddEndpoint(context.TODO(), "foo/bar/my-service/e1", endpoints.Endpoint{Addr:"1.2.3.4"})

Endpunkte atomar aktualisieren

Um mehrere Endpunkte in einer einzigen Transaktion zu ändern, kann endpoints.Manager direkt verwendet werden:

em := endpoints.NewManager(c, "foo")

err := em.Update(context.TODO(), []*endpoints.UpdateWithOpts{
    endpoints.NewDeleteUpdateOpts("foo/bar/my-service/e1", endpoints.Endpoint{Addr: "1.2.3.4"}),
	endpoints.NewAddUpdateOpts("foo/bar/my-service/e1", endpoints.Endpoint{Addr: "1.2.3.14"})})

13.6 - etcd in eine Go-Anwendung einbetten

Mit dem Go-Paket embed von etcd einen etcd-Server innerhalb Ihrer Anwendung ausführen

Das Go-Paket embed von etcd bietet eine einfache Möglichkeit, einen etcd-Server direkt in Ihre Anwendung einzubetten.

Weitere Einzelheiten enthält die Dokumentation des Pakets embed .

13.7 - Systemgrenzen

etcd-Grenzen: Anfragen und Speicher

Maximale Anfragegröße

etcd ist für kleine Schlüssel-Wert-Paare ausgelegt, wie sie für Metadaten typisch sind. Größere Anfragen funktionieren, können jedoch die Latenz anderer Anfragen erhöhen. Standardmäßig beträgt die maximale Größe einer Anfrage 1.5 MiB. Diese Grenze lässt sich über die Option --max-request-bytes des etcd-Servers konfigurieren.

Maximale Speichergröße

Die standardmäßige Speichergrenze beträgt 2 GiB und lässt sich über die Option --quota-backend-bytes konfigurieren. Für normale Umgebungen werden maximal 8 GiB empfohlen. etcd gibt beim Start eine Warnung aus, wenn der konfigurierte Wert diese Größe überschreitet.

13.8 - etcd-Funktionen

etcd-Funktionen verwenden

Dieses Dokument gibt einen Überblick über die Funktionen von etcd und das Verfahren, nach dem sie als veraltet eingestuft werden. Wie Funktionen in etcd entwickelt werden, erläutern diese Entwicklungsrichtlinien .

Die Funktionen von etcd werden in drei Stufen eingeteilt: experimentell, stabil und unsicher. Mit etcd --help lässt sich die Liste der Funktionen anzeigen.

Experimentell

Um frühzeitig Rückmeldungen zu erhalten, werden neue Funktionen üblicherweise als experimentelle Funktionen eingeführt. Sie sind am Optionsnamen zu erkennen, der mit --experimental beginnen sollte. Bei der Verwendung einer experimentellen Funktion sind folgende Punkte zu beachten:

  • Sie kann Fehler enthalten, da sie noch nicht ausreichend von Benutzern getestet wurde. Nach dem Aktivieren funktioniert sie möglicherweise nicht wie erwartet.
  • Sie ist standardmäßig deaktiviert.
  • Die Unterstützung einer solchen Funktion kann jederzeit ohne Ankündigung eingestellt werden
    • Sie kann in der nächsten Minor- oder Major-Version entfernt werden, ohne die Richtlinie zur Einstufung als veraltet einzuhalten, sofern sie nicht in die stabile Stufe übergeht.
    • Das Projektteam freut sich über Fehlermeldungen zu experimentellen Funktionen. Diese Probleme können jedoch eine geringere Priorität erhalten als Probleme mit stabilen Funktionen.
  • Eine experimentelle Funktionsoption wird als veraltet eingestuft , sobald die Funktion die stabile Stufe erreicht. Benutzer sollten möglichst bald auf die stabile Funktionsoption umsteigen.

Stabil

Dies ist die häufigste Stufe von Funktionen in etcd. Eine stabile Funktion zeichnet sich durch Folgendes aus:

  • Sie wird im Rahmen der unterstützten etcd-Versionen unterstützt.
  • Sie kann standardmäßig aktiviert sein.
  • Die Einstellung der Unterstützung muss der Richtlinie zur Einstufung als veraltet folgen.

Unsicher

Unsichere Funktionen sind selten und werden im Abschnitt Unsafe feature: der etcd-Nutzungsdokumentation aufgeführt. Sie sind standardmäßig deaktiviert. Sie sollten mit Vorsicht und gemäß der Dokumentation verwendet werden. Eine unsichere Funktion kann in der nächsten Minor- oder Major-Version entfernt werden, ohne die Richtlinie zur Einstufung als veraltet einzuhalten.

Funktionen als veraltet einstufen

Experimentell

Eine experimentelle Funktion wird als veraltet eingestuft, sobald sie die stabile Stufe erreicht.

  • Die Dokumentation der experimentellen Funktion zeigt einen Hinweis auf die Einstufung als veraltet und empfiehlt die entsprechende stabile Funktionsoption, z. B. DEPRECATED. Use <feature-name> instead.
  • Eine als veraltet eingestufte Funktion wird in der darauffolgenden Version entfernt.

Stabil

Im Zuge der Projektentwicklung kann es nötig werden, auch eine stabile Funktion als veraltet einzustufen und zu entfernen. In diesem Fall gilt:

  • Die Dokumentation der Funktion zeigt vor der Version, für die die Einstufung als veraltet geplant ist, eine Warnmeldung, z. B. To be deprecated in <release>.. Ist bereits eine neue Funktion als Ersatz für die mit To be deprecated gekennzeichnete Funktion geplant, wird auch darauf hingewiesen, z. B. Use <feature-name> instead..
  • Die Funktion wird in der geplanten Version als veraltet eingestuft. Ab dann zeigt ihre Dokumentation einen entsprechenden Hinweis und empfiehlt eine verwandte stabile Funktion, z. B. DEPRECATED. Use <feature-name> instead.
  • Eine als veraltet eingestufte Funktion wird in der darauffolgenden Version entfernt.

13.9 - API-Referenz

Vollständige Referenz der etcd-v3-API

Diese API-Referenz wird automatisch aus den angegebenen .proto-Dateien erzeugt.

Dienst Auth (api/etcdserverpb/rpc.proto)
Methode Anfragetyp Antworttyp Beschreibung
AuthEnable AuthEnableRequest AuthEnableResponse AuthEnable aktiviert die Authentifizierung.
AuthDisable AuthDisableRequest AuthDisableResponse AuthDisable deaktiviert die Authentifizierung.
AuthStatus AuthStatusRequest AuthStatusResponse AuthStatus zeigt den Authentifizierungsstatus an.
Authenticate AuthenticateRequest AuthenticateResponse Authenticate verarbeitet eine Authentifizierungsanfrage.
UserAdd AuthUserAddRequest AuthUserAddResponse UserAdd fügt einen neuen Benutzer hinzu. Der Benutzername darf nicht leer sein.
UserGet AuthUserGetRequest AuthUserGetResponse UserGet ruft ausführliche Benutzerinformationen ab.
UserList AuthUserListRequest AuthUserListResponse UserList ruft eine Liste aller Benutzer ab.
UserDelete AuthUserDeleteRequest AuthUserDeleteResponse UserDelete löscht einen angegebenen Benutzer.
UserChangePassword AuthUserChangePasswordRequest AuthUserChangePasswordResponse UserChangePassword ändert das Passwort eines angegebenen Benutzers.
UserGrantRole AuthUserGrantRoleRequest AuthUserGrantRoleResponse UserGrantRole weist einem angegebenen Benutzer eine Rolle zu.
UserRevokeRole AuthUserRevokeRoleRequest AuthUserRevokeRoleResponse UserRevokeRole entzieht einem angegebenen Benutzer eine Rolle.
RoleAdd AuthRoleAddRequest AuthRoleAddResponse RoleAdd fügt eine neue Rolle hinzu. Der Rollenname darf nicht leer sein.
RoleGet AuthRoleGetRequest AuthRoleGetResponse RoleGet ruft ausführliche Rolleninformationen ab.
RoleList AuthRoleListRequest AuthRoleListResponse RoleList ruft Listen aller Rollen ab.
RoleDelete AuthRoleDeleteRequest AuthRoleDeleteResponse RoleDelete löscht eine angegebene Rolle.
RoleGrantPermission AuthRoleGrantPermissionRequest AuthRoleGrantPermissionResponse RoleGrantPermission gewährt einer angegebenen Rolle eine Berechtigung für einen bestimmten Schlüssel oder Bereich.
RoleRevokePermission AuthRoleRevokePermissionRequest AuthRoleRevokePermissionResponse RoleRevokePermission entzieht einer angegebenen Rolle eine Berechtigung für einen Schlüssel oder Bereich.
Dienst Cluster (api/etcdserverpb/rpc.proto)
Methode Anfragetyp Antworttyp Beschreibung
MemberAdd MemberAddRequest MemberAddResponse MemberAdd fügt dem Cluster ein Mitglied hinzu.
MemberRemove MemberRemoveRequest MemberRemoveResponse MemberRemove entfernt ein vorhandenes Mitglied aus dem Cluster.
MemberUpdate MemberUpdateRequest MemberUpdateResponse MemberUpdate aktualisiert die Mitgliedskonfiguration.
MemberList MemberListRequest MemberListResponse MemberList listet alle Mitglieder des Clusters auf.
MemberPromote MemberPromoteRequest MemberPromoteResponse MemberPromote stuft ein Mitglied von einem nicht stimmberechtigten Raft-Learner zu einem stimmberechtigten Raft-Mitglied hoch.
Dienst KV (api/etcdserverpb/rpc.proto)
Methode Anfragetyp Antworttyp Beschreibung
Range RangeRequest RangeResponse Range ruft die Schlüssel im Bereich aus dem Schlüssel-Wert-Speicher ab.
Put PutRequest PutResponse Put schreibt den angegebenen Schlüssel in den Schlüssel-Wert-Speicher. Eine Put-Anfrage erhöht die Revision des Schlüssel-Wert-Speichers und erzeugt ein Ereignis im Ereignisverlauf.
DeleteRange DeleteRangeRequest DeleteRangeResponse DeleteRange löscht den angegebenen Bereich aus dem Schlüssel-Wert-Speicher. Eine Löschanfrage erhöht die Revision des Schlüssel-Wert-Speichers und erzeugt für jeden gelöschten Schlüssel ein Löschereignis im Ereignisverlauf.
Txn TxnRequest TxnResponse Txn verarbeitet mehrere Anfragen in einer einzigen Transaktion. Eine Txn-Anfrage erhöht die Revision des Schlüssel-Wert-Speichers und erzeugt für jede abgeschlossene Anfrage Ereignisse mit derselben Revision. Derselbe Schlüssel darf innerhalb einer Transaktion nicht mehrfach geändert werden.
Compact CompactionRequest CompactionResponse Compact kompaktiert den Ereignisverlauf im Schlüssel-Wert-Speicher von etcd. Der Schlüssel-Wert-Speicher sollte regelmäßig kompaktiert werden, da der Ereignisverlauf andernfalls unbegrenzt weiterwächst.
Dienst Lease (api/etcdserverpb/rpc.proto)
Methode Anfragetyp Antworttyp Beschreibung
LeaseGrant LeaseGrantRequest LeaseGrantResponse LeaseGrant erstellt eine Lease, die abläuft, wenn der Server innerhalb einer vorgegebenen Lebensdauer kein keepAlive empfängt. Läuft die Lease ab, laufen alle ihr zugeordneten Schlüssel ebenfalls ab und werden gelöscht. Jeder abgelaufene Schlüssel erzeugt ein Löschereignis im Ereignisverlauf.
LeaseRevoke LeaseRevokeRequest LeaseRevokeResponse LeaseRevoke widerruft eine Lease. Alle ihr zugeordneten Schlüssel laufen ab und werden gelöscht.
LeaseKeepAlive LeaseKeepAliveRequest LeaseKeepAliveResponse LeaseKeepAlive hält die Lease am Leben, indem es Keepalive-Anfragen vom Client zum Server und Keepalive-Antworten vom Server zum Client als Streams überträgt.
LeaseTimeToLive LeaseTimeToLiveRequest LeaseTimeToLiveResponse LeaseTimeToLive ruft Informationen zur Lease ab.
LeaseLeases LeaseLeasesRequest LeaseLeasesResponse LeaseLeases listet alle vorhandenen Leases auf.
Dienst Maintenance (api/etcdserverpb/rpc.proto)
Methode Anfragetyp Antworttyp Beschreibung
Alarm AlarmRequest AlarmResponse Alarm aktiviert, deaktiviert und erfragt Alarme zum Zustand des Clusters.
Status StatusRequest StatusResponse Status ruft den Status des Mitglieds ab.
Defragment DefragmentRequest DefragmentResponse Defragment defragmentiert die Backend-Datenbank eines Mitglieds, um Speicherplatz zurückzugewinnen.
Hash HashRequest HashResponse Hash berechnet den Hash des gesamten Backend-Schlüsselraums einschließlich der Buckets key, lease und weiterer Buckets im Speicher. Dies ist NUR für Tests vorgesehen! Im Produktivbetrieb mit laufenden Transaktionen darf man sich nicht darauf verlassen, da die Hash-Operation keine MVCC-Sperren hält. Für Konsistenzprüfungen des Buckets “key” stattdessen die API “HashKV” verwenden.
HashKV HashKVRequest HashKVResponse HashKV berechnet den Hash aller MVCC-Schlüssel bis zu einer angegebenen Revision. Es durchläuft nur den Bucket “key” im Backend-Speicher.
Snapshot SnapshotRequest SnapshotResponse Snapshot sendet einen Snapshot des gesamten Backends eines Mitglieds über einen Stream an einen Client.
MoveLeader MoveLeaderRequest MoveLeaderResponse MoveLeader fordert den aktuellen Leader-Knoten auf, seine Führungsrolle an den vorgesehenen Empfänger zu übertragen.
Downgrade DowngradeRequest DowngradeResponse Downgrade fordert ein Downgrade der Clusterversion an, prüft dessen Durchführbarkeit oder bricht es ab. Seit etcd 3.5 unterstützt.
Dienst Watch (api/etcdserverpb/rpc.proto)
Methode Anfragetyp Antworttyp Beschreibung
Watch WatchRequest WatchResponse Watch beobachtet aktuelle oder bereits vergangene Ereignisse. Ein- und Ausgabe sind Streams: Der Eingabestream dient zum Erstellen und Abbrechen von Watchern, der Ausgabestream überträgt Ereignisse. Ein Watch-RPC kann mehrere Schlüsselbereiche beobachten und Ereignisse für mehrere Watches gleichzeitig streamen. Der gesamte Ereignisverlauf kann ab der letzten Kompaktierungsrevision beobachtet werden.
Nachricht AlarmMember (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
memberID memberID ist die ID des Mitglieds, dem der ausgelöste Alarm zugeordnet ist. uint64
alarm alarm ist der Typ des ausgelösten Alarms. AlarmType
Nachricht AlarmRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
action action ist die Art der auszuführenden Alarmanfrage. Die Aktion kann Alarmzustände abrufen (GET), einen Alarm aktivieren (ACTIVATE) oder einen ausgelösten Alarm deaktivieren (DEACTIVATE). AlarmAction
memberID memberID ist die ID des Mitglieds, dem der Alarm zugeordnet ist. Ist memberID 0, umfasst die Alarmanfrage alle Mitglieder. uint64
alarm alarm ist der bei dieser Anfrage zu berücksichtigende Alarmtyp. AlarmType
Nachricht AlarmResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
alarms alarms ist eine Liste der Alarme, die der Alarmanfrage zugeordnet sind. (Slice von) AlarmMember
Nachricht AuthDisableRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
Nachricht AuthDisableResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
Nachricht AuthEnableRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
Nachricht AuthEnableResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
Nachricht AuthRoleAddRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
name name ist der Name der Rolle, die dem Authentifizierungssystem hinzugefügt werden soll. string
Nachricht AuthRoleAddResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
Nachricht AuthRoleDeleteRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
role string
Nachricht AuthRoleDeleteResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
Nachricht AuthRoleGetRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
role string
Nachricht AuthRoleGetResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
header ResponseHeader
perm (Slice von) authpb.Permission
Nachricht AuthRoleGrantPermissionRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
name name ist der Name der Rolle, der die Berechtigung erteilt wird. string
perm perm ist die Berechtigung, die der Rolle erteilt werden soll. authpb.Permission
Nachricht AuthRoleGrantPermissionResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
Nachricht AuthRoleListRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
Nachricht AuthRoleListResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
roles (Slice von) string
Nachricht AuthRoleRevokePermissionRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
role string
key bytes
range_end bytes
Nachricht AuthRoleRevokePermissionResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
Nachricht AuthStatusRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
Nachricht AuthStatusResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
enabled bool
authRevision authRevision ist die aktuelle Revision des Authentifizierungsspeichers uint64
Nachricht AuthUserAddRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
name string
password string
options authpb.UserAddOptions
hashedPassword string
Nachricht AuthUserAddResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
Nachricht AuthUserChangePasswordRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
name name ist der Name des Benutzers, dessen Passwort geändert wird. string
password password ist das neue Passwort des Benutzers. Dieses Feld wird in der API-Schicht entfernt. string
hashedPassword hashedPassword ist der Hashwert des neuen Passworts des Benutzers. Dieses Feld wird in der API-Schicht initialisiert. string
Nachricht AuthUserChangePasswordResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
Nachricht AuthUserDeleteRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
name name ist der Name des zu löschenden Benutzers. string
Nachricht AuthUserDeleteResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
Nachricht AuthUserGetRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
name string
Nachricht AuthUserGetResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
roles (Slice von) string
Nachricht AuthUserGrantRoleRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
user user ist der Name des Benutzers, dem eine angegebene Rolle zugewiesen werden sollte. string
role role ist der Name der Rolle, die dem Benutzer zugewiesen werden soll. string
Nachricht AuthUserGrantRoleResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
Nachricht AuthUserListRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
Nachricht AuthUserListResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
users (Slice von) string
Nachricht AuthUserRevokeRoleRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
name string
role string
Nachricht AuthUserRevokeRoleResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
Nachricht AuthenticateRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
name string
password string
Nachricht AuthenticateResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
token token ist ein autorisiertes Token, das in nachfolgenden RPCs verwendet werden kann string
Nachricht CompactionRequest (api/etcdserverpb/rpc.proto)

CompactionRequest kompaktiert den Schlüssel-Wert-Speicher bis zu einer angegebenen Revision. Alle ersetzten Schlüssel mit einer Revision unterhalb der Kompaktierungsrevision werden entfernt.

Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
revision revision ist die Revision des Schlüssel-Wert-Speichers für die Kompaktierungsoperation. int64
physical Wenn physical gesetzt ist, wartet der RPC, bis die Kompaktierung physisch auf die lokale Datenbank angewendet wurde und die kompaktierten Einträge vollständig aus der Backend-Datenbank entfernt sind. bool
Nachricht CompactionResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
Nachricht Compare (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
result result ist die logische Vergleichsoperation für diesen Vergleich. CompareResult
target target ist das Schlüssel-Wert-Feld, das für den Vergleich geprüft werden soll. CompareTarget
key key ist der Schlüssel, auf den die Vergleichsoperation angewendet wird. bytes
target_union oneof
version version ist die Version des angegebenen Schlüssels int64
create_revision create_revision ist die Erstellungsrevision des angegebenen Schlüssels int64
mod_revision mod_revision ist die Revision der letzten Änderung des angegebenen Schlüssels. int64
value value ist der Wert des angegebenen Schlüssels als Bytes. bytes
lease lease ist die Lease-ID des angegebenen Schlüssels. int64
range_end range_end vergleicht das angegebene target mit allen Schlüsseln im Bereich [key, range_end). Weitere Informationen zu Schlüsselbereichen enthält RangeRequest. bytes
Nachricht DefragmentRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
Nachricht DefragmentResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
Nachricht DeleteRangeRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
key key ist der erste zu löschende Schlüssel im Bereich. bytes
range_end range_end ist der Schlüssel nach dem letzten zu löschenden Schlüssel im Bereich [key, range_end). Ist range_end nicht angegeben, enthält der Bereich nur das Argument key. Ist range_end gleich dem angegebenen Schlüssel plus eins, umfasst der Bereich alle Schlüssel mit diesem Präfix, also dem angegebenen Schlüssel. Ist range_end ‘\0’, umfasst der Bereich alle Schlüssel größer oder gleich dem Argument key. bytes
prev_kv Ist prev_kv gesetzt, ruft etcd vor dem Löschen die vorherigen Schlüssel-Wert-Paare ab. Diese werden in der Löschantwort zurückgegeben. bool
Nachricht DeleteRangeResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
deleted deleted ist die Anzahl der durch die Bereichslöschanfrage gelöschten Schlüssel. int64
prev_kvs Ist prev_kv in der Anfrage gesetzt, werden die vorherigen Schlüssel-Wert-Paare zurückgegeben. (Slice von) mvccpb.KeyValue
Nachricht DowngradeInfo (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
enabled enabled gibt an, ob für den Cluster ein Downgrade aktiviert ist. bool
targetVersion targetVersion ist die Zielversion des Downgrades. string
Nachricht DowngradeRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
action action ist die Art der auszuführenden Downgrade-Anfrage. Die Aktion kann die Zielversion validieren (VALIDATE), die Clusterversion herabsetzen (DOWNGRADE) oder den laufenden Downgrade-Vorgang abbrechen (CANCEL). DowngradeAction
version version ist die Zielversion des Downgrades. string
Nachricht DowngradeResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
version version ist die aktuelle Clusterversion. string
Nachricht DowngradeVersionTestRequest (api/etcdserverpb/rpc.proto)

DowngradeVersionTestRequest wird nur für Tests verwendet. Die Version in dieser Anfrage wird als Version des WAL-Eintrags gelesen. Ist die Downgrade-Zielversion kleiner als diese Version, ist das Downgrade im laufenden Betrieb oder die Offline-Migration nicht sicher und sollte daher nicht zugelassen werden.

Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
ver string
Nachricht HashKVRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
revision revision ist die Revision des Schlüssel-Wert-Speichers für die Hash-Operation. int64
Nachricht HashKVResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
hash hash ist der Hashwert, der aus den MVCC-Schlüsseln des antwortenden Mitglieds bis zu einer angegebenen Revision berechnet wurde. uint32
compact_revision compact_revision ist die Kompaktierungsrevision des Schlüssel-Wert-Speichers zu Beginn der Hash-Berechnung. int64
hash_revision hash_revision ist die Revision, bis zu der der Hash berechnet wird. int64
Nachricht HashRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
Nachricht HashResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
hash hash ist der Hashwert, der aus dem KV-Backend des antwortenden Mitglieds berechnet wurde. uint32
Nachricht LeaseCheckpoint (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
ID ID ist die Lease-ID, für die ein Checkpoint erstellt werden soll. int64
remaining_TTL Remaining_TTL ist die verbleibende Zeit bis zum Ablauf der Lease. int64
Nachricht LeaseCheckpointRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
checkpoints (Slice von) LeaseCheckpoint
Nachricht LeaseCheckpointResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
Nachricht LeaseGrantRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
TTL TTL ist die empfohlene Lebensdauer in Sekunden. Für eine abgelaufene Lease wird -1 zurückgegeben. int64
ID ID ist die angeforderte ID der Lease. Ist ID auf 0 gesetzt, wählt der Lease-Geber eine ID aus. int64
Nachricht LeaseGrantResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
ID ID ist die Lease-ID der gewährten Lease. int64
TTL TTL ist die vom Server gewählte Lebensdauer der Lease in Sekunden. int64
error string
Nachricht LeaseKeepAliveRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
ID ID ist die Lease-ID der am Leben zu haltenden Lease. int64
Nachricht LeaseKeepAliveResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
ID ID ist die Lease-ID aus der Keepalive-Anfrage. int64
TTL TTL ist die neue Lebensdauer der Lease. int64
Nachricht LeaseLeasesRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
Nachricht LeaseLeasesResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
leases (Slice von) LeaseStatus
Nachricht LeaseRevokeRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
ID ID ist die Lease-ID der zu widerrufenden Lease. Wird die ID widerrufen, werden alle zugeordneten Schlüssel gelöscht. int64
Nachricht LeaseRevokeResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
Nachricht LeaseStatus (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
ID int64
Nachricht LeaseTimeToLiveRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
ID ID ist die Lease-ID der Lease. int64
keys keys wird auf true gesetzt, um alle dieser Lease zugeordneten Schlüssel abzufragen. bool
Nachricht LeaseTimeToLiveResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
ID ID ist die Lease-ID aus der Keepalive-Anfrage. int64
TTL TTL ist die verbleibende TTL der Lease in Sekunden; die Lease läuft in weniger als TTL+1 Sekunden ab. int64
grantedTTL GrantedTTL ist die bei der Erstellung oder Verlängerung der Lease anfänglich gewährte Zeit in Sekunden. int64
keys Keys ist die Liste der dieser Lease zugeordneten Schlüssel. (Slice von) bytes
Nachricht Member (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
ID ID ist die Mitglieds-ID dieses Mitglieds. uint64
name name ist der menschenlesbare Name des Mitglieds. Ist das Mitglied nicht gestartet, ist name eine leere Zeichenfolge. string
peerURLs peerURLs ist die Liste der URLs, die das Mitglied dem Cluster zur Kommunikation bereitstellt. (Slice von) string
clientURLs clientURLs ist die Liste der URLs, die das Mitglied Clients zur Kommunikation bereitstellt. Ist das Mitglied nicht gestartet, ist clientURLs leer. (Slice von) string
isLearner isLearner gibt an, ob das Mitglied ein Raft-Learner ist. bool
Nachricht MemberAddRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
peerURLs peerURLs ist die Liste der URLs, die das hinzugefügte Mitglied zur Kommunikation mit dem Cluster verwendet. (Slice von) string
isLearner isLearner gibt an, ob das hinzugefügte Mitglied ein Raft-Learner ist. bool
Nachricht MemberAddResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
member member enthält die Mitgliedsinformationen des hinzugefügten Mitglieds. Member
members members ist eine Liste aller Mitglieder nach dem Hinzufügen des neuen Mitglieds. (Slice von) Member
Nachricht MemberListRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
linearizable bool
Nachricht MemberListResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
members members ist eine Liste aller dem Cluster zugeordneten Mitglieder. (Slice von) Member
Nachricht MemberPromoteRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
ID ID ist die Mitglieds-ID des hochzustufenden Mitglieds. uint64
Nachricht MemberPromoteResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
members members ist eine Liste aller Mitglieder nach der Hochstufung des Mitglieds. (Slice von) Member
Nachricht MemberRemoveRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
ID ID ist die Mitglieds-ID des zu entfernenden Mitglieds. uint64
Nachricht MemberRemoveResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
members members ist eine Liste aller Mitglieder nach dem Entfernen des Mitglieds. (Slice von) Member
Nachricht MemberUpdateRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
ID ID ist die Mitglieds-ID des zu aktualisierenden Mitglieds. uint64
peerURLs peerURLs ist die neue Liste der URLs, die das Mitglied zur Kommunikation mit dem Cluster verwendet. (Slice von) string
Nachricht MemberUpdateResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
members members ist eine Liste aller Mitglieder nach der Aktualisierung des Mitglieds. (Slice von) Member
Nachricht MoveLeaderRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
targetID targetID ist die Knoten-ID des neuen Leaders. uint64
Nachricht MoveLeaderResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
Nachricht PutRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
key key ist der Schlüssel als Bytes, der in den Schlüssel-Wert-Speicher geschrieben werden soll. bytes
value value ist der Wert als Bytes, der dem Schlüssel im Schlüssel-Wert-Speicher zugeordnet werden soll. bytes
lease lease ist die Lease-ID, die dem Schlüssel im Schlüssel-Wert-Speicher zugeordnet werden soll. Der Lease-Wert 0 bedeutet, dass keine Lease zugeordnet ist. int64
prev_kv Ist prev_kv gesetzt, ruft etcd vor der Änderung das vorherige Schlüssel-Wert-Paar ab. Dieses wird in der Put-Antwort zurückgegeben. bool
ignore_value Ist ignore_value gesetzt, aktualisiert etcd den Schlüssel mit seinem aktuellen Wert. Wenn der Schlüssel nicht existiert, wird ein Fehler zurückgegeben. bool
ignore_lease Ist ignore_lease gesetzt, aktualisiert etcd den Schlüssel mit seiner aktuellen Lease. Wenn der Schlüssel nicht existiert, wird ein Fehler zurückgegeben. bool
Nachricht PutResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
prev_kv Ist prev_kv in der Anfrage gesetzt, wird das vorherige Schlüssel-Wert-Paar zurückgegeben. mvccpb.KeyValue
Nachricht RangeRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
key key ist der erste Schlüssel des Bereichs. Ist range_end nicht angegeben, sucht die Anfrage nur nach key. bytes
range_end range_end ist die obere Grenze des angeforderten Bereichs [key, range_end). Ist range_end ‘\0’, umfasst der Bereich alle Schlüssel >= key. Ist range_end key plus eins, etwa “aa”+1 == “ab” oder “a\xff”+1 == “b”, ruft die Bereichsanfrage alle Schlüssel mit dem Präfix key ab. Sind key und range_end beide ‘\0’, gibt die Bereichsanfrage alle Schlüssel zurück. bytes
limit limit begrenzt die Anzahl der für die Anfrage zurückgegebenen Schlüssel. Der Wert 0 bedeutet keine Begrenzung. int64
revision revision ist der für den Bereich zu verwendende Zeitpunkt im Schlüssel-Wert-Speicher. Ist revision kleiner oder gleich null, bezieht sich der Bereich auf den neuesten Stand des Schlüssel-Wert-Speichers. Wurde die Revision bereits kompaktiert, wird ErrCompacted zurückgegeben. int64
sort_order sort_order ist die Reihenfolge der zurückgegebenen sortierten Ergebnisse. SortOrder
sort_target sort_target ist das Schlüssel-Wert-Feld, nach dem sortiert wird. SortTarget
serializable serializable legt fest, dass die Bereichsanfrage serialisierbare, auf das Mitglied beschränkte Lesezugriffe verwendet. Bereichsanfragen sind standardmäßig linearisierbar. Linearisierbare Anfragen haben eine höhere Latenz und einen geringeren Durchsatz als serialisierbare Anfragen, spiegeln aber den aktuellen Konsens des Clusters wider. Für bessere Leistung auf Kosten möglicherweise veralteter Leseergebnisse wird eine serialisierbare Bereichsanfrage lokal bearbeitet, ohne einen Konsens mit anderen Clusterknoten herstellen zu müssen. bool
keys_only Wenn keys_only gesetzt ist, werden nur die Schlüssel und nicht die Werte zurückgegeben. bool
count_only Wenn count_only gesetzt ist, wird nur die Anzahl der Schlüssel im Bereich zurückgegeben. bool
min_mod_revision min_mod_revision ist die Untergrenze für die Änderungsrevisionen der zurückgegebenen Schlüssel. Alle Schlüssel mit kleineren Änderungsrevisionen werden herausgefiltert. int64
max_mod_revision max_mod_revision ist die Obergrenze für die Änderungsrevisionen der zurückgegebenen Schlüssel. Alle Schlüssel mit größeren Änderungsrevisionen werden herausgefiltert. int64
min_create_revision min_create_revision ist die Untergrenze für die Erstellungsrevisionen der zurückgegebenen Schlüssel. Alle Schlüssel mit kleineren Erstellungsrevisionen werden herausgefiltert. int64
max_create_revision max_create_revision ist die Obergrenze für die Erstellungsrevisionen der zurückgegebenen Schlüssel. Alle Schlüssel mit größeren Erstellungsrevisionen werden herausgefiltert. int64
Nachricht RangeResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
kvs kvs ist die Liste der Schlüssel-Wert-Paare, die der Bereichsanfrage entsprechen. Bei einer Anfrage nach count ist kvs leer. (Slice von) mvccpb.KeyValue
more more gibt an, ob im angeforderten Bereich weitere Schlüssel zurückzugeben sind. bool
count count wird auf Anfrage auf die tatsächliche Anzahl der Schlüssel im Bereich gesetzt. Anders als Kvs bleibt es von Begrenzungen und Filtern wie Min/Max, Create/Modify und Revisions unbeeinflusst und gibt die vollständige Anzahl im angegebenen Bereich wieder. int64
Nachricht RequestOp (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
request request ist eine Vereinigung der von einer Transaktion akzeptierten Anfragetypen. oneof
request_range RangeRequest
request_put PutRequest
request_delete_range DeleteRangeRequest
request_txn TxnRequest
Nachricht ResponseHeader (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
cluster_id cluster_id ist die ID des Clusters, der die Antwort gesendet hat. uint64
member_id member_id ist die ID des Mitglieds, das die Antwort gesendet hat. uint64
revision revision ist die Revision des Schlüssel-Wert-Speichers zum Zeitpunkt der Anwendung der Anfrage. Bei Aufrufen ohne Zugriff auf den Schlüssel-Wert-Speicher ist sie nicht gesetzt und daher 0. Bei Watch-Fortschrittsantworten zeigt header.revision den Fortschritt an. Alle künftig in diesem Stream empfangenen Ereignisse haben garantiert eine höhere Revisionsnummer als header.revision. int64
raft_term raft_term ist der Raft-Term zum Zeitpunkt der Anwendung der Anfrage. uint64
Nachricht ResponseOp (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
response response ist eine Vereinigung der von einer Transaktion zurückgegebenen Antworttypen. oneof
response_range RangeResponse
response_put PutResponse
response_delete_range DeleteRangeResponse
response_txn TxnResponse
Nachricht SnapshotRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
Nachricht SnapshotResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header header enthält die aktuellen Informationen zum Schlüssel-Wert-Speicher. Der erste Header im Snapshot-Stream gibt den Zeitpunkt des Snapshots an. ResponseHeader
remaining_bytes remaining_bytes ist die Anzahl der Blob-Bytes, die nach dieser Nachricht noch gesendet werden uint64
blob blob enthält den nächsten Teil des Snapshots im Snapshot-Stream. bytes
version Im Snapshot gespeicherte Version des Speicherschemas. Sie wird aus dem lokalen Backend des Mitglieds gelesen und kann von dessen Binärversion abweichen. Gibt an, welche etcd-Speicherversion beim Wiederherstellen des Snapshots unterstützt werden muss. string
Nachricht StatusRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
Nachricht StatusResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
version version ist die Binärversion des antwortenden etcd-Mitglieds. Die Version des Speicherschemas wird separat in storageVersion angegeben. string
dbSize dbSize ist die physisch zugewiesene Größe der Backend-Datenbank des antwortenden Mitglieds in Bytes. int64
leader leader ist die Mitglieds-ID, die das antwortende Mitglied für den aktuellen Leader hält. uint64
raftIndex raftIndex ist der aktuelle bestätigte Raft-Index des antwortenden Mitglieds. uint64
raftTerm raftTerm ist der aktuelle Raft-Term des antwortenden Mitglieds. uint64
raftAppliedIndex raftAppliedIndex ist der aktuelle angewendete Raft-Index des antwortenden Mitglieds. uint64
errors errors enthält Alarm- und Zustandsinformationen sowie den Status. (Slice von) string
dbSizeInUse dbSizeInUse ist die logisch verwendete Größe der Backend-Datenbank des antwortenden Mitglieds in Bytes. int64
isLearner isLearner gibt an, ob das Mitglied ein Raft-Learner ist. bool
storageVersion storageVersion ist die Version der db-Datei. Sie kann gegenüber der angestrebten Clusterversion verzögert aktualisiert werden. string
dbSizeQuota dbSizeQuota ist das konfigurierte etcd-Speicherkontingent in Bytes, also der über die Option –quota-backend-bytes an die etcd-Instanz übergebene Wert int64
downgradeInfo downgradeInfo gibt an, ob ein Downgrade-Vorgang läuft. DowngradeInfo
Nachricht TxnRequest (api/etcdserverpb/rpc.proto)

Aus dem Google-PaxosDB-Papier: Unsere Implementierung beruht auf einer leistungsfähigen Grundoperation namens MultiOp. Alle anderen Datenbankoperationen außer der Iteration sind als einzelner MultiOp-Aufruf implementiert. Eine MultiOp wird atomar angewendet und besteht aus drei Komponenten: 1. Einer Liste von Prüfungen namens guard. Jede Prüfung in guard prüft einen einzelnen Datenbankeintrag. Sie kann prüfen, ob ein Wert fehlt oder vorhanden ist, oder ihn mit einem angegebenen Wert vergleichen. Zwei verschiedene Prüfungen in guard können denselben oder unterschiedliche Datenbankeinträge betreffen. Alle Prüfungen in guard werden ausgeführt, und MultiOp gibt die Ergebnisse zurück. Sind alle Prüfungen wahr, führt MultiOp t op aus (siehe Punkt 2 unten), andernfalls f op (siehe Punkt 3 unten). 2. Einer Liste von Datenbankoperationen namens t op. Jede Operation ist eine Einfüge-, Lösch- oder Suchoperation und betrifft einen einzelnen Datenbankeintrag. Zwei verschiedene Operationen können denselben oder unterschiedliche Datenbankeinträge betreffen. Diese Operationen werden ausgeführt, wenn guard true ergibt. 3. Einer Liste von Datenbankoperationen namens f op. Wie t op, wird jedoch ausgeführt, wenn guard false ergibt.

Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
compare compare ist eine Liste von Prädikaten, die eine Konjunktion von Bedingungen repräsentiert. Sind die Vergleiche erfolgreich, werden die success-Anfragen der Reihe nach verarbeitet, und die Antwort enthält deren Antworten in derselben Reihenfolge. Schlagen die Vergleiche fehl, werden die failure-Anfragen der Reihe nach verarbeitet, und die Antwort enthält deren Antworten in derselben Reihenfolge. (Slice von) Compare
success success ist eine Liste von Anfragen, die angewendet werden, wenn compare true ergibt. (Slice von) RequestOp
failure failure ist eine Liste von Anfragen, die angewendet werden, wenn compare false ergibt. (Slice von) RequestOp
Nachricht TxnResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
succeeded succeeded wird auf true gesetzt, wenn compare true ergab, andernfalls auf false. bool
responses responses ist eine Liste von Antworten auf die Ergebnisse der Anwendung von success, falls succeeded true ist, beziehungsweise failure, falls succeeded false ist. (Slice von) ResponseOp
Nachricht WatchCancelRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
watch_id watch_id ist die ID des abzubrechenden Watchers, damit keine weiteren Ereignisse übertragen werden. int64
Nachricht WatchCreateRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
key key ist der Schlüssel, der zur Beobachtung registriert werden soll. bytes
range_end range_end ist das Ende des zu beobachtenden Bereichs [key, range_end). Ist range_end nicht angegeben, wird nur das Argument key beobachtet. Ist range_end gleich ‘\0’, werden alle Schlüssel größer oder gleich dem Argument key beobachtet. Ist range_end gleich dem angegebenen Schlüssel plus eins, werden alle Schlüssel mit diesem Präfix, also dem angegebenen Schlüssel, beobachtet. bytes
start_revision start_revision ist eine optionale Revision, ab der einschließlich beobachtet wird. Ohne start_revision beginnt die Beobachtung „jetzt“. int64
progress_notify Wenn progress_notify gesetzt ist und keine aktuellen Ereignisse vorliegen, sendet der etcd-Server regelmäßig eine WatchResponse ohne Ereignisse an den neuen Watcher. Das ist nützlich, wenn Clients einen unterbrochenen Watcher ab einer kürzlich bekannt gewordenen Revision wiederherstellen möchten. Der etcd-Server kann anhand der aktuellen Last entscheiden, wie häufig er Benachrichtigungen sendet. bool
filters filters filtert die Ereignisse serverseitig, bevor sie an den Watcher zurückgesendet werden. (Slice von) FilterType
prev_kv Ist prev_kv gesetzt, erhält der erstellte Watcher den vorherigen KV vor dem Ereignis. Wurde der vorherige KV bereits kompaktiert, wird nichts zurückgegeben. bool
watch_id Wird watch_id angegeben und ist ungleich null, wird sie diesem Watcher zugewiesen. Da das Erstellen eines Watchers in etcd kein synchroner Vorgang ist, lässt sich damit beim Erstellen mehrerer Watcher im selben Stream die richtige Reihenfolge sicherstellen. Wird ein Watcher mit einer im Stream bereits verwendeten ID erstellt, wird ein Fehler zurückgegeben. int64
fragment fragment ermöglicht das Aufteilen großer Revisionen auf mehrere Watch-Antworten. bool
Nachricht WatchProgressRequest (api/etcdserverpb/rpc.proto)

Fordert an, dass der Fortschrittsstatus eines Watch-Streams so bald wie möglich im Watch-Antwortstream gesendet wird.

Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
Nachricht WatchRequest (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
request_union request_union ist eine Anfrage zum Erstellen eines neuen Watchers oder zum Abbrechen eines vorhandenen Watchers. oneof
create_request WatchCreateRequest
cancel_request WatchCancelRequest
progress_request WatchProgressRequest
Nachricht WatchResponse (api/etcdserverpb/rpc.proto)
Feld Beschreibung Typ
(versionpb.etcd_version_msg) option
header ResponseHeader
watch_id watch_id ist die ID des Watchers, zu dem die Antwort gehört. int64
created created wird auf true gesetzt, wenn die Antwort zu einer Anfrage zum Erstellen eines Watches gehört. Der Client sollte watch_id speichern und die Ereignisse für den erstellten Watcher im selben Stream erwarten. Alle an diesen Watcher gesendeten Ereignisse enthalten dieselbe watch_id. bool
canceled canceled wird auf true gesetzt, wenn die Antwort zu einer Anfrage zum Abbrechen eines Watches gehört oder start_revision bereits kompaktiert wurde. An den abgebrochenen Watcher werden keine weiteren Ereignisse gesendet. bool
compact_revision compact_revision wird auf den kleinsten Index gesetzt, wenn ein Watcher versucht, einen bereits kompaktierten Index zu beobachten. Dies geschieht beim Erstellen eines Watchers an einer kompaktierten Revision oder wenn der Watcher den Fortschritt des Schlüssel-Wert-Speichers nicht einholen kann. Der Client sollte den Watcher als abgebrochen behandeln und nicht erneut versuchen, einen Watcher mit derselben start_revision zu erstellen. int64
cancel_reason cancel_reason gibt den Grund für den Abbruch des Watchers an. string
fragment fragment ist true, wenn eine große Watch-Antwort auf mehrere Antworten aufgeteilt wurde. bool
events (Slice von) mvccpb.Event
Nachricht Event (api/mvccpb/kv.proto)
Feld Beschreibung Typ
type type ist die Art des Ereignisses. Ist type ein PUT, wurden neue Daten unter dem Schlüssel gespeichert. Ist type ein DELETE, wurde der Schlüssel gelöscht. EventType
kv kv enthält den KeyValue für das Ereignis. Ein PUT-Ereignis enthält das aktuelle kv-Paar. Ein PUT-Ereignis mit kv.Version=1 zeigt die Erstellung eines Schlüssels an. Ein DELETE/EXPIRE-Ereignis enthält den gelöschten Schlüssel, dessen Änderungsrevision auf die Revision der Löschung gesetzt ist. KeyValue
prev_kv prev_kv enthält das Schlüssel-Wert-Paar vor dem Ereignis. KeyValue
Nachricht KeyValue (api/mvccpb/kv.proto)
Feld Beschreibung Typ
key key ist der Schlüssel als Bytes. Ein leerer Schlüssel ist nicht zulässig. bytes
create_revision create_revision ist die Revision der letzten Erstellung dieses Schlüssels. int64
mod_revision mod_revision ist die Revision der letzten Änderung dieses Schlüssels. int64
version version ist die Version des Schlüssels. Eine Löschung setzt die Version auf null zurück, und jede Änderung des Schlüssels erhöht seine Version. int64
value value ist der unter dem Schlüssel gespeicherte Wert als Bytes. bytes
lease lease ist die ID der dem Schlüssel zugeordneten Lease. Wenn diese Lease abläuft, wird der Schlüssel gelöscht. Ist lease 0, ist dem Schlüssel keine Lease zugeordnet. int64
Nachricht Lease (server/lease/leasepb/lease.proto)
Feld Beschreibung Typ
ID int64
TTL int64
RemainingTTL int64
Nachricht LeaseInternalRequest (server/lease/leasepb/lease.proto)
Feld Beschreibung Typ
LeaseTimeToLiveRequest etcdserverpb.LeaseTimeToLiveRequest
Nachricht LeaseInternalResponse (server/lease/leasepb/lease.proto)
Feld Beschreibung Typ
LeaseTimeToLiveResponse etcdserverpb.LeaseTimeToLiveResponse
Nachricht Permission (api/authpb/auth.proto)

Permission ist eine einzelne Entität

Feld Beschreibung Typ
permType Type
key bytes
range_end bytes
Nachricht Role (api/authpb/auth.proto)

Role ist ein einzelner Eintrag im Bucket authRoles

Feld Beschreibung Typ
name bytes
keyPermission (Slice von) Permission
Nachricht User (api/authpb/auth.proto)

User ist ein einzelner Eintrag im Bucket authUsers

Feld Beschreibung Typ
name bytes
password bytes
roles (Slice von) string
options UserAddOptions
Nachricht UserAddOptions (api/authpb/auth.proto)
Feld Beschreibung Typ
no_password bool

13.10 - API-Referenz: Nebenläufigkeit

Referenz der APIs für Nebenläufigkeit in etcd

Diese API-Referenz wird automatisch aus den angegebenen .proto-Dateien erzeugt.

Dienst Lock (server/etcdserver/api/v3lock/v3lockpb/v3lock.proto)

Der Lock-Dienst stellt clientseitige Sperrfunktionen als gRPC-Schnittstelle bereit.

Methode Anfragetyp Antworttyp Beschreibung
Lock LockRequest LockResponse Lock erwirbt eine verteilte gemeinsame Sperre für einen bestimmten Sperrnamen. Bei Erfolg gibt es einen eindeutigen Schlüssel zurück, der so lange existiert, wie der Aufrufer die Sperre hält. Mit diesem Schlüssel und Transaktionen lässt sich zuverlässig sicherstellen, dass etcd nur aktualisiert wird, während der Aufrufer die Sperre besitzt. Die Sperre wird gehalten, bis Unlock für den Schlüssel aufgerufen wird oder die dem Besitzer zugeordnete Lease abläuft.
Unlock UnlockRequest UnlockResponse Unlock nimmt einen von Lock zurückgegebenen Schlüssel entgegen und gibt die Sperre frei. Anschließend wird der nächste auf die Sperre wartende Lock-Aufrufer geweckt und erhält die Sperre.
Nachricht LockRequest (server/etcdserver/api/v3lock/v3lockpb/v3lock.proto)
Feld Beschreibung Typ
name name ist der Bezeichner der zu erwerbenden verteilten gemeinsamen Sperre. bytes
lease lease ist die ID der Lease, die dem Besitz der Sperre zugeordnet wird. Läuft die Lease ab oder wird sie widerrufen, während sie die Sperre hält, wird die Sperre automatisch freigegeben. Aufrufe von Lock mit derselben Lease werden als einmaliger Erwerb behandelt; zweimaliges Sperren mit derselben Lease hat keine zusätzliche Wirkung. int64
Nachricht LockResponse (server/etcdserver/api/v3lock/v3lockpb/v3lock.proto)
Feld Beschreibung Typ
header etcdserverpb.ResponseHeader
key key ist ein Schlüssel, der in etcd existiert, solange der Lock-Aufrufer die Sperre besitzt. Benutzer sollten diesen Schlüssel nicht ändern, da die Sperre sonst ein undefiniertes Verhalten zeigen kann. bytes
Nachricht UnlockRequest (server/etcdserver/api/v3lock/v3lockpb/v3lock.proto)
Feld Beschreibung Typ
key key ist der von Lock vergebene Schlüssel, der den Besitz der Sperre repräsentiert. bytes
Nachricht UnlockResponse (server/etcdserver/api/v3lock/v3lockpb/v3lock.proto)
Feld Beschreibung Typ
header etcdserverpb.ResponseHeader
Dienst Election (server/etcdserver/api/v3election/v3electionpb/v3election.proto)

Der Election-Dienst stellt clientseitige Wahlfunktionen als gRPC-Schnittstelle bereit.

Methode Anfragetyp Antworttyp Beschreibung
Campaign CampaignRequest CampaignResponse Campaign wartet darauf, bei einer Wahl die Führung zu übernehmen, und gibt bei Erfolg einen LeaderKey zurück, der die Führungsrolle repräsentiert. Der LeaderKey kann anschließend verwendet werden, um neue Werte für die Wahl zu veröffentlichen, API-Anfragen durch Transaktionen vom fortbestehenden Besitz der Führungsrolle abhängig zu machen und von der Führungsrolle zurückzutreten.
Proclaim ProclaimRequest ProclaimResponse Proclaim ersetzt den vom Leader veröffentlichten Wert durch einen neuen Wert.
Leader LeaderRequest LeaderResponse Leader gibt den aktuell für die Wahl veröffentlichten Wert zurück, sofern vorhanden.
Observe LeaderRequest LeaderResponse Observe überträgt die von den gewählten Leadern veröffentlichten Werte in ihrer Reihenfolge als Stream.
Resign ResignRequest ResignResponse Resign gibt die Führungsrolle der Wahl frei, sodass andere Kandidaten sie übernehmen können.
Nachricht CampaignRequest (server/etcdserver/api/v3election/v3electionpb/v3election.proto)
Feld Beschreibung Typ
name name ist der Bezeichner der Wahl, für die die Kandidatur gilt. bytes
lease lease ist die ID der Lease, die der Führungsrolle der Wahl zugeordnet ist. Läuft die Lease vor dem Rücktritt ab oder wird sie widerrufen, geht die Führungsrolle auf den nächsten Kandidaten über, sofern vorhanden. int64
value value ist der anfänglich veröffentlichte Wert, der gesetzt wird, wenn der Kandidat die Wahl gewinnt. bytes
Nachricht CampaignResponse (server/etcdserver/api/v3election/v3electionpb/v3election.proto)
Feld Beschreibung Typ
header etcdserverpb.ResponseHeader
leader leader beschreibt die Ressourcen, die zum Halten der Führungsrolle der Wahl verwendet werden. LeaderKey
Nachricht LeaderKey (server/etcdserver/api/v3election/v3electionpb/v3election.proto)
Feld Beschreibung Typ
name name ist der Wahlbezeichner, der dem Schlüssel für die Führungsrolle entspricht. bytes
key key ist ein opaker Schlüssel, der den Besitz der Führungsrolle der Wahl repräsentiert. Wird der Schlüssel gelöscht, geht die Führungsrolle verloren. bytes
rev rev ist die Erstellungsrevision des Schlüssels. In Transaktionen lässt sich damit der Besitz der Führungsrolle prüfen, indem die Erstellungsrevision des Schlüssels mit rev verglichen wird. int64
lease lease ist die Lease-ID des gewählten Leaders. int64
Nachricht LeaderRequest (server/etcdserver/api/v3election/v3electionpb/v3election.proto)
Feld Beschreibung Typ
name name ist der Wahlbezeichner für die Informationen zur Führungsrolle. bytes
Nachricht LeaderResponse (server/etcdserver/api/v3election/v3electionpb/v3election.proto)
Feld Beschreibung Typ
header etcdserverpb.ResponseHeader
kv kv ist das Schlüssel-Wert-Paar, das die neueste Aktualisierung des Leaders repräsentiert. mvccpb.KeyValue
Nachricht ProclaimRequest (server/etcdserver/api/v3election/v3electionpb/v3election.proto)
Feld Beschreibung Typ
leader leader repräsentiert den Besitz der Führungsrolle der Wahl. LeaderKey
value value ist eine Aktualisierung, die den aktuellen Wert des Leaders überschreiben soll. bytes
Nachricht ProclaimResponse (server/etcdserver/api/v3election/v3electionpb/v3election.proto)
Feld Beschreibung Typ
header etcdserverpb.ResponseHeader
Nachricht ResignRequest (server/etcdserver/api/v3election/v3electionpb/v3election.proto)
Feld Beschreibung Typ
leader leader ist die Führungsrolle, die durch den Rücktritt aufgegeben werden soll. LeaderKey
Nachricht ResignResponse (server/etcdserver/api/v3election/v3electionpb/v3election.proto)
Feld Beschreibung Typ
header etcdserverpb.ResponseHeader
Nachricht Event (api/mvccpb/kv.proto)
Feld Beschreibung Typ
type type ist die Art des Ereignisses. Ist type ein PUT, wurden neue Daten unter dem Schlüssel gespeichert. Ist type ein DELETE, wurde der Schlüssel gelöscht. EventType
kv kv enthält den KeyValue für das Ereignis. Ein PUT-Ereignis enthält das aktuelle kv-Paar. Ein PUT-Ereignis mit kv.Version=1 zeigt die Erstellung eines Schlüssels an. Ein DELETE/EXPIRE-Ereignis enthält den gelöschten Schlüssel, dessen Änderungsrevision auf die Revision der Löschung gesetzt ist. KeyValue
prev_kv prev_kv enthält das Schlüssel-Wert-Paar vor dem Ereignis. KeyValue
Nachricht KeyValue (api/mvccpb/kv.proto)
Feld Beschreibung Typ
key key ist der Schlüssel als Bytes. Ein leerer Schlüssel ist nicht zulässig. bytes
create_revision create_revision ist die Revision der letzten Erstellung dieses Schlüssels. int64
mod_revision mod_revision ist die Revision der letzten Änderung dieses Schlüssels. int64
version version ist die Version des Schlüssels. Eine Löschung setzt die Version auf null zurück, und jede Änderung des Schlüssels erhöht seine Version. int64
value value ist der unter dem Schlüssel gespeicherte Wert als Bytes. bytes
lease lease ist die ID der dem Schlüssel zugeordneten Lease. Wenn diese Lease abläuft, wird der Schlüssel gelöscht. Ist lease 0, ist dem Schlüssel keine Lease zugeordnet. int64

14 - Betriebshandbuch

Anleitungen zur Installation, Wartung und Fehlerbehebung von etcd

14.1 - Anleitungen zur Authentifizierung

Anleitung zur Authentifizierung und rollenbasierten Zugriffskontrolle in etcd

14.1.1 - Authentifizierung

Anleitung zur Authentifizierung in einem etcd-Cluster

auth,user,role für die Authentifizierung:

export ETCDCTL_API=3
ENDPOINTS=localhost:2379

etcdctl --endpoints=${ENDPOINTS} role add root
etcdctl --endpoints=${ENDPOINTS} role get root

etcdctl --endpoints=${ENDPOINTS} user add root
etcdctl --endpoints=${ENDPOINTS} user grant-role root root
etcdctl --endpoints=${ENDPOINTS} user get root

etcdctl --endpoints=${ENDPOINTS} role add role0
etcdctl --endpoints=${ENDPOINTS} role grant-permission role0 readwrite foo
etcdctl --endpoints=${ENDPOINTS} user add user0
etcdctl --endpoints=${ENDPOINTS} user grant-role user0 role0

etcdctl --endpoints=${ENDPOINTS} auth enable
# now all client requests go through auth

etcdctl --endpoints=${ENDPOINTS} --user=user0:123 put foo bar
etcdctl --endpoints=${ENDPOINTS} get foo
# permission denied, user name is empty because the request does not issue an authentication request
etcdctl --endpoints=${ENDPOINTS} --user=user0:123 get foo
# user0 can read the key foo
etcdctl --endpoints=${ENDPOINTS} --user=user0:123 get foo1

Hinweis:

Dies ist lediglich ein Entwurf, der um weitere Informationen zur Authentifizierung ergänzt und aktualisiert werden muss. Der obige Text ist nur ein Codebeispiel.

14.1.2 - Rollenbasierte Zugriffskontrolle

Eine grundlegende Anleitung zur Authentifizierung und rollenbasierten Zugriffskontrolle

Überblick

Die Authentifizierung wurde in etcd 2.1 eingeführt. Die etcd-v3-API hat die API und die Benutzeroberfläche der Authentifizierungsfunktion geringfügig angepasst, um dem neuen Datenmodell besser gerecht zu werden. Diese Anleitung hilft dabei, eine grundlegende Authentifizierung und rollenbasierte Zugriffskontrolle in etcd v3 einzurichten.

Besondere Benutzer und Rollen

Es gibt einen besonderen Benutzer, root, und eine besondere Rolle, root.

Benutzer root

Der Benutzer root, der uneingeschränkten Zugriff auf etcd hat, muss vor der Aktivierung der Authentifizierung angelegt werden. Der Benutzer root ist für Verwaltungsaufgaben vorgesehen: die Verwaltung von Rollen und gewöhnlichen Benutzern. Der Benutzer root muss die Rolle root haben und darf alles in etcd ändern.

Rolle root

Die Rolle root kann neben dem root-Benutzer jedem Benutzer zugewiesen werden. Ein Benutzer mit der Rolle root hat sowohl globalen Lese- und Schreibzugriff als auch die Berechtigung, die Authentifizierungskonfiguration des Clusters zu ändern. Darüber hinaus gewährt die Rolle root Rechte für die allgemeine Clusterwartung, einschließlich der Änderung der Clustermitgliedschaft, der Defragmentierung des Speichers und der Erstellung von Snapshots.

Benutzer verwalten

Der Unterbefehl user von etcdctl übernimmt alle Aufgaben rund um Benutzerkonten.

Benutzer lassen sich wie folgt auflisten:

$ etcdctl user list

Ein Benutzer lässt sich einfach so anlegen:

$ etcdctl user add myusername

Beim Anlegen eines neuen Benutzers wird ein neues Passwort abgefragt. Mit der Option --interactive=false kann das Passwort über die Standardeingabe übergeben werden. Auch --new-user-password kann zur Übergabe des Passworts verwendet werden.

Ein Benutzer, der sich nicht mit einem Passwort authentifizieren kann, lässt sich ebenfalls anlegen:

$ etcdctl user add myusername --no-password

Ein solcher Benutzer kann sich nur über den TLS Common Name authentifizieren .

Hinweis

etcd unterstützt keine Authentifizierung mit einem leeren Passwort über --user username:. Beispielsweise kann sich ein mit leerem Passwort angelegter Benutzer wie etcdctl user add anonymous:'' nicht über Anfragen mit Benutzername und Passwort authentifizieren; Anfragen wie etcdctl --user anonymous: get foo schlagen mit user name is empty fehl.

Einem Benutzer lassen sich Rollen wie folgt zuweisen und entziehen:

$ etcdctl user grant-role myusername foo
$ etcdctl user revoke-role myusername bar

Die Einstellungen des Benutzers lassen sich wie folgt anzeigen:

$ etcdctl user get myusername

Das Passwort eines Benutzers lässt sich wie folgt ändern:

$ etcdctl user passwd myusername

Bei der Passwortänderung wird erneut ein neues Passwort abgefragt. Mit der Option --interactive=false kann das Passwort über die Standardeingabe übergeben werden.

Ein Konto löschen:

$ etcdctl user delete myusername

Rollen verwalten

Der Unterbefehl role von etcdctl übernimmt alle Aufgaben rund um die Zugriffskontrolle für einzelne Rollen, die Benutzern zugewiesen wurden.

Rollen auflisten:

$ etcdctl role list

Eine neue Rolle anlegen:

$ etcdctl role add myrolename

Eine Rolle hat kein Passwort; sie definiert lediglich eine neue Menge von Zugriffsrechten.

Rollen erhalten Zugriff auf einen einzelnen Schlüssel oder einen Schlüsselbereich.

Der Bereich kann als Intervall [start-key, end-key) angegeben werden, wobei start-key in alphabetischer, lexikografischer Reihenfolge kleiner als end-key sein sollte.

Der Zugriff kann zum Lesen, zum Schreiben oder für beides gewährt werden, wie in den folgenden Beispielen:

# Give read access to a key /foo
$ etcdctl role grant-permission myrolename read /foo

# Give read access to keys with a prefix /foo/. The prefix is equal to the range [/foo/, /foo0)
$ etcdctl role grant-permission myrolename --prefix=true read /foo/

# Give write-only access to the key at /foo/bar
$ etcdctl role grant-permission myrolename write /foo/bar

# Give full access to keys in a range of [key1, key5)
$ etcdctl role grant-permission myrolename readwrite key1 key5

# Give full access to keys with a prefix /pub/
$ etcdctl role grant-permission myrolename --prefix=true readwrite /pub/

Die gewährten Rechte lassen sich jederzeit anhand der Rolle anzeigen:

$ etcdctl role get myrolename

Der Entzug von Berechtigungen folgt demselben Prinzip:

$ etcdctl role revoke-permission myrolename /foo/bar

Ebenso das vollständige Löschen einer Rolle:

$ etcdctl role delete myrolename

Authentifizierung aktivieren

Für die Aktivierung der Authentifizierung sind mindestens die folgenden Schritte erforderlich. Der Administrator kann Benutzer und Rollen nach Belieben vor oder nach der Aktivierung der Authentifizierung einrichten.

Sicherstellen, dass der root-Benutzer angelegt ist:

$ etcdctl user add root
Password of root:

Authentifizierung aktivieren:

$ etcdctl auth enable

Danach läuft etcd mit aktivierter Authentifizierung. Um sie aus beliebigem Grund zu deaktivieren, dient der entsprechende Gegenbefehl:

$ etcdctl --user root:rootpw auth disable

Schutzumfang der Authentifizierung

Wenn die Authentifizierung mit etcdctl auth enable aktiviert wird, schützt sie die Operationen der V3-gRPC-API (get, put, delete, watch usw.).

Die HTTP-Endpunkte /metrics und /health verwenden einen separaten Handler und werden nicht durch die V3-RBAC-Authentifizierung geschützt. Dadurch können Prometheus und Load-Balancer Metriken ohne gRPC-Authentifizierung abrufen, während die Schlüssel-Wert-Daten weiterhin geschützt sind.

Diese Endpunkte zur Überwachung lassen sich wie folgt absichern:

  • mTLS mit --cert-file, --key-file und --client-cert-auth aktivieren
  • Oder die Metriken mit --listen-metrics-urls an eine private Schnittstelle binden
  • Oder den Zugriff durch Netzwerkrichtlinien/Firewallregeln beschränken

Mit etcdctl authentifizieren

etcdctl unterstützt zur Authentifizierung eine ähnliche Option wie curl.

$ etcdctl --user user:password get foo

Das Passwort kann interaktiv abgefragt werden:

$ etcdctl --user user get foo

Das Passwort kann auch mit der Befehlszeilenoption --password übergeben werden:

$ etcdctl --user user --password password get foo

Ansonsten bleiben alle etcdctl-Befehle unverändert. Benutzer und Rollen können weiterhin angelegt und geändert werden; dafür ist jedoch die Authentifizierung durch einen Benutzer mit der root-Rolle erforderlich.

TLS Common Name verwenden

Ab Version v3.2 wird beim Start eines etcd-Servers mit der Option --client-cert-auth=true das Feld Common Name (CN) im TLS-Zertifikat des Clients als etcd-Benutzer verwendet. In diesem Fall authentifiziert der Common Name den Benutzer, und der Client benötigt kein Passwort. Wenn sowohl 1. --client-cert-auth=true übergeben wird und der Client einen CN bereitstellt als auch 2. der Client Benutzername und Passwort übergibt, hat die Authentifizierung mit Benutzername und Passwort Vorrang. Diese Funktion kann nicht mit gRPC-proxy und gRPC-gateway verwendet werden. gRPC-proxy terminiert TLS vom Client, sodass alle Clients ein Zertifikat des Proxys gemeinsam nutzen. gRPC-gateway verwendet intern eine TLS-Verbindung, um HTTP-Anfragen in gRPC-Anfragen umzuwandeln, und unterliegt daher derselben Einschränkung. Die Clients können ihren CN deshalb nicht korrekt an den Server übermitteln. gRPC-proxy meldet einen Fehler und beendet sich, wenn ein angegebenes Zertifikat einen nicht leeren CN enthält. gRPC-proxy gibt einen Fehler zurück, der auf den nicht leeren CN im Zertifikat des Clients hinweist.

Hinweise zur Passwortstärke

etcdctl und die etcd-API erzwingen beim Anlegen von Benutzern oder beim Ändern ihrer Passwörter keine bestimmte Passwortlänge. Die Durchsetzung solcher Anforderungen liegt in der Verantwortung des Administrators. Um Sicherheitsrisiken durch schwache Passwörter zu vermeiden, können die Authentifizierung über den TLS Common Name und Benutzer verwendet werden, die mit der Option --no-password angelegt wurden.

14.2 - Konfigurationsoptionen

Konfigurationsdateien, Optionen und Umgebungsvariablen von etcd

etcd lässt sich auf folgende Arten konfigurieren:

Warnung

Achtung: Werden verschiedene Konfigurationsarten kombiniert, gelten die folgenden Regeln.

  • Befehlszeilenoptionen haben Vorrang vor Umgebungsvariablen.
  • Wird eine Konfigurationsdatei angegeben, werden alle Befehlszeilenoptionen und Umgebungsvariablen ignoriert.

Befehlszeilenoptionen

Die Optionen werden im Folgenden im Format --flag-name DEFAULT_VALUE dargestellt.

Hinweis

Diese importierte Referenz enthält einige ältere v2-Optionen als Kontext für die Migration. In etcd 3.7 sind --enable-v2 und der v2-Proxy-Modus nicht verfügbar. Die veraltete Option --v2-deprecation ignoriert Benutzereingaben und erzwingt ihren Standardwert. Vor der Verwendung älterer Optionen die Ausgabe von etcd --help für die installierte Version prüfen.

Die folgende Optionsliste ist aufgrund laufender Entwicklungsänderungen möglicherweise nicht aktuell. Die neuesten verfügbaren Optionen lassen sich mit etcd --help oder in der etcd-Hilfe nachschlagen.

Hinweis

Hinweis: Einzelheiten zu neuen, aktualisierten und als veraltet markierten Optionen in v3.7 stehen in CHANGELOG-3.7.md .

Mitglied

--name 'default'
  Human-readable name for this member.
--data-dir '${name}.etcd'
  Path to the data directory.
--wal-dir ''
  Path to the dedicated wal directory.
--snapshot-count '10000'
  Number of committed transactions to trigger a snapshot to disk.
--heartbeat-interval '100'
  Time (in milliseconds) of a heartbeat interval.
--election-timeout '1000'
  Time (in milliseconds) for an election to timeout. See tuning documentation for details.
--initial-election-tick-advance 'true'
  Whether to fast-forward initial election ticks on boot for faster election.
--listen-peer-urls 'http://localhost:2380'
  List of URLs to listen on for peer traffic.
--listen-client-urls 'http://localhost:2379'
  List of URLs to listen on for client grpc traffic and http as long as --listen-client-http-urls is not specified.
--listen-client-http-urls ''
  List of URLs to listen on for http only client traffic. Enabling this flag removes http services from --listen-client-urls.
--max-snapshots '5'
  Maximum number of snapshot files to retain (0 is unlimited).
--max-wals '5'
  Maximum number of wal files to retain (0 is unlimited).
--memory-mlock
  Enable to enforce etcd pages (in particular bbolt) to stay in RAM.
--quota-backend-bytes '0'
  Raise alarms when backend size exceeds the given quota (0 defaults to low space quota).
--backend-bbolt-freelist-type 'map'
  BackendFreelistType specifies the type of freelist that boltdb backend uses(array and map are supported types).
--backend-batch-interval ''
  BackendBatchInterval is the maximum time before commit the backend transaction.
--backend-batch-limit '0'
  BackendBatchLimit is the maximum operations before commit the backend transaction.
--max-txn-ops '128'
  Maximum number of operations permitted in a transaction.
--max-request-bytes '1572864'
  Maximum client request size in bytes the server will accept.
--grpc-keepalive-min-time '5s'
  Minimum duration interval that a client should wait before pinging server.
--grpc-keepalive-interval '2h'
  Frequency duration of server-to-client ping to check if a connection is alive (0 to disable).
--grpc-keepalive-timeout '20s'
  Additional duration of wait before closing a non-responsive connection (0 to disable).
--socket-reuse-port 'false'
  Enable to set socket option SO_REUSEPORT on listeners allowing rebinding of a port already in use.
--socket-reuse-address 'false'
  Enable to set socket option SO_REUSEADDR on listeners allowing binding to an address in TIME_WAIT state.

Clusterbildung

--initial-advertise-peer-urls 'http://localhost:2380'
  List of this member's peer URLs to advertise to the rest of the cluster.
--initial-cluster 'default=http://localhost:2380'
  Initial cluster configuration for bootstrapping.
--initial-cluster-state 'new'
  Initial cluster state ('new' or 'existing').
--initial-cluster-token 'etcd-cluster'
  Initial cluster token for the etcd cluster during bootstrap.
  Specifying this can protect you from unintended cross-cluster interaction when running multiple clusters.
--advertise-client-urls 'http://localhost:2379'
  List of this member's client URLs to advertise to the public.
  The client URLs advertised should be accessible to machines that talk to etcd cluster. etcd client libraries parse these URLs to connect to the cluster.
--discovery ''
  Discovery URL used to bootstrap the cluster.
--discovery-fallback 'proxy'
  Expected behavior ('exit' or 'proxy') when discovery services fails.
  "proxy" supports v2 API only.
--discovery-proxy ''
  HTTP proxy to use for traffic to discovery service.
--discovery-srv ''
  DNS srv domain used to bootstrap the cluster.
--discovery-srv-name ''
  Suffix to the dns srv name queried when bootstrapping.
--strict-reconfig-check 'true'
  Reject reconfiguration requests that would cause quorum loss.
--pre-vote 'true'
  Enable the raft Pre-Vote algorithm to prevent disruption when a node that has been partitioned away rejoins the cluster.
--auto-compaction-retention '0'
  Auto compaction retention length. 0 means disable auto compaction.
--auto-compaction-mode 'periodic'
  Interpret 'auto-compaction-retention' one of: periodic|revision. 'periodic' for duration based retention, defaulting to hours if no time unit is provided (e.g. '5m'). 'revision' for revision number based retention.
--enable-v2 'false'
  Accept etcd V2 client requests. Deprecated and to be decommissioned in v3.6.
--v2-deprecation 'not-yet'
  Phase of v2store deprecation. Allows to opt-in for higher compatibility mode.
  Supported values:
    'not-yet'                // Issues a warning if v2store have meaningful content (default in v3.5)
    'write-only'             // Custom v2 state is not allowed (default in v3.6 and v3.7)
    'write-only-skip-check'  // Custom v2 state is not supported and, if present, will be ignored (available in v3.5.32+, v3.6.13+, and v3.7.0+). Use this option at your own risk.
    'write-only-drop-data'   // Custom v2 state will get DELETED ! (planned default in v3.8)
    'gone'                   // v2store is not maintained any longer.

Sicherheit

--cert-file ''
  Path to the client server TLS cert file.
--key-file ''
  Path to the client server TLS key file.
--client-cert-auth 'false'
  Enable client cert authentication.
  It's recommended to enable client cert authentication to prevent attacks from unauthenticated clients (e.g. CVE-2023-44487), especially when running etcd as a public service.
--client-crl-file ''
  Path to the client certificate revocation list file.
--client-cert-allowed-hostname ''
  Comma-separated list of SAN hostnames for client cert authentication.
--trusted-ca-file ''
  Path to the client server TLS trusted CA cert file.
  Note setting this parameter will also automatically enable client cert authentication no matter what value is set for `--client-cert-auth`.
--auto-tls 'false'
  Client TLS using generated certificates.
--peer-cert-file ''
  Path to the peer server TLS cert file.
--peer-key-file ''
  Path to the peer server TLS key file.
--peer-client-cert-auth 'false'
  Enable peer client cert authentication.
  It's recommended to enable peer client cert authentication to prevent attacks from unauthenticated forged peers (e.g. CVE-2023-44487).
--peer-trusted-ca-file ''
  Path to the peer server TLS trusted CA file.
--peer-cert-allowed-cn ''
  Comma-separated list of allowed CNs for inter-peer TLS authentication.
--peer-cert-allowed-hostname ''
  Comma-separated list of allowed SAN hostnames for inter-peer TLS authentication.
--peer-auto-tls 'false'
  Peer TLS using self-generated certificates if --peer-key-file and --peer-cert-file are not provided.
--self-signed-cert-validity '1'
  The validity period of the client and peer certificates that are automatically generated by etcd when you specify ClientAutoTLS and PeerAutoTLS, the unit is year, and the default is 1.
--peer-crl-file ''
  Path to the peer certificate revocation list file.
--cipher-suites ''
  Comma-separated list of supported TLS cipher suites between client/server and peers (empty will be auto-populated by Go).
--cors '*'
  Comma-separated whitelist of origins for CORS, or cross-origin resource sharing, (empty or * means allow all).
--host-whitelist '*'
  Acceptable hostnames from HTTP client requests, if server is not secure (empty or * means allow all).
--tls-min-version 'TLS1.2'
  Minimum TLS version supported by etcd.
--tls-max-version ''
  Maximum TLS version supported by etcd (empty will be auto-populated by Go).

Authentifizierung

--auth-token 'simple'
  Specify a v3 authentication token type and its options ('simple' or 'jwt').
--bcrypt-cost 10
  Specify the cost / strength of the bcrypt algorithm for hashing auth passwords. Valid values are between 4 and 31.
--auth-token-ttl 300
  Time (in seconds) of the auth-token-ttl.

Profiling und Überwachung

--enable-pprof 'false'
  Enable runtime profiling data via HTTP server. Address is at client URL + "/debug/pprof/"
--metrics 'basic'
  Set level of detail for exported metrics, specify 'extensive' to include server side grpc histogram metrics.
--listen-metrics-urls ''
  List of URLs to listen on for the metrics and health endpoints.

Protokollierung

--logger 'zap'
  Currently only supports 'zap' for structured logging.
--log-outputs 'default'
  Specify 'stdout' or 'stderr' to skip journald logging even when running under systemd, or list of comma separated output targets.
--log-level 'info'
  Configures log level. Only supports debug, info, warn, error, panic, or fatal.
--log-format 'json'
  Configures log format. Only supports json, console.
--enable-log-rotation 'false'
  Enable log rotation of a single log-outputs file target.
--log-rotation-config-json '{"maxsize": 100, "maxage": 0, "maxbackups": 0, "localtime": false, "compress": false}'
  Configures log rotation if enabled with a JSON logger config. MaxSize(MB), MaxAge(days,0=no limit), MaxBackups(0=no limit), LocalTime(use computers local time), Compress(gzip)".
--warning-unary-request-duration '300ms'
  Set time duration after which a warning is logged if a unary request takes more than this duration.
Hinweis

Hinweis: Mehrere --experimental-*-Optionen wurden in v3.7 in stabile Optionen überführt oder umbenannt. Veraltete Optionen unbedingt durch die unten aufgeführten stabilen Entsprechungen ersetzen.

Verteiltes Tracing

--enable-distributed-tracing 'false'
  Enable distributed tracing.
--distributed-tracing-address 'localhost:4317'
  Distributed tracing collector address.
--distributed-tracing-service-name 'etcd'
  Distributed tracing service name, must be the same across all etcd instances.
--distributed-tracing-instance-id ''
  Distributed tracing instance ID, must be unique for each etcd instance.
--distributed-tracing-sampling-rate '0'
  Number of samples to collect per million spans for distributed tracing.

v2-Proxy

Warnung

Der v2-Proxy wurde vor v3.7 entfernt. Die folgenden Optionen bleiben nur als historische Migrationsreferenz erhalten und dürfen nicht an einen etcd-v3.7-Server übergeben werden.

--proxy 'off'
  Proxy mode setting ('off', 'readonly' or 'on').
--proxy-failure-wait 5000
  Time (in milliseconds) an endpoint will be held in a failed state.
--proxy-refresh-interval 30000
  Time (in milliseconds) of the endpoints refresh interval.
--proxy-dial-timeout 1000
  Time (in milliseconds) for a dial to timeout.
--proxy-write-timeout 5000
  Time (in milliseconds) for a write to timeout.
--proxy-read-timeout 0
  Time (in milliseconds) for a read to timeout.

Funktionen

--corrupt-check-time '0s'
  Duration of time between cluster corruption check passes.
--compact-hash-check-time '1m'
  Duration of time between leader checks followers compaction hashes.
--compaction-batch-limit 1000
  CompactionBatchLimit sets the maximum revisions deleted in each compaction batch.
--peer-skip-client-san-verification 'false'
  Skip verification of SAN field in client certificate for peer connections.
--watch-progress-notify-interval '10m'
  Duration of periodical watch progress notification.
--warning-apply-duration '100ms'
  Warning is generated if requests take more than this duration.
--bootstrap-defrag-threshold-megabytes
  Enable the defrag during etcd server bootstrap on condition that it will free at least the provided threshold of disk space. Needs to be set to non-zero value to take effect.
--max-learners '1'
  Set the max number of learner members allowed in the cluster membership.
--compaction-sleep-interval
  Sets the sleep interval between each compaction batch.
--downgrade-check-time
  Duration of time between two downgrade status checks.
--snapshot-catchup-entries
  Number of entries for a slow follower to catch up after compacting the raft storage entries.

Funktionsschalter

--feature-gates=AllAlpha=true|false
  Enables or disables all alpha features. Default is false.
--feature-gates=AllBeta=true|false
  Enables or disables all beta features. Default is false.
--feature-gates=CompactHashCheck=true
  Enables leader to periodically check follower compaction hashes.
  Replaces: --experimental-compact-hash-check-enabled
--feature-gates=InitialCorruptCheck=true
  Enables corruption check before serving client/peer traffic.
  Replaces: --experimental-initial-corrupt-check
--feature-gates=LeaseCheckpoint=true
  ExperimentalEnableLeaseCheckpoint enables primary lessor to persist lease remainingTTL to prevent indefinite auto-renewal of long lived leases.
  Replaces: --experimental-enable-lease-checkpoint
--feature-gates=LeaseCheckpointPersist=true
  Enable persisting remainingTTL to prevent indefinite auto-renewal of long lived leases. Always enabled in v3.6. Should be used to ensure smooth upgrade from v3.5 clusters with this feature enabled.
  Replaces: --experimental-enable-lease-checkpoint-persist
--feature-gates=SetMemberLocalAddr=true
  Allows setting a member’s local address.
--feature-gates=StopGRPCServiceOnDefrag=true
  Enable etcd gRPC service to stop serving client requests on defragmentation.
  Replaces: --experimental-stop-grpc-service-on-defrag
--feature-gates=TxnModeWriteWithSharedBuffer=true
  Enable the write transaction to use a shared buffer in its readonly check operations.
  Replaces: --experimental-txn-mode-write-with-shared-buffer

Unsichere Funktionen

Warnung

Warnung: Die Verwendung unsicherer Funktionen kann die Garantien des Konsensprotokolls außer Kraft setzen!

--force-new-cluster 'false'
  Force to create a new one-member cluster.
--unsafe-no-fsync 'false'
  Disables fsync, unsafe, will cause data loss.

Konfigurationsdatei

Eine etcd-Konfigurationsdatei besteht aus einer YAML-Map. Ihre Schlüssel sind die Namen der Befehlszeilenoptionen und ihre Werte die jeweiligen Optionswerte. Um diese Datei zu verwenden, ihren Pfad als Wert der Option --config-file oder der Umgebungsvariablen ETCD_CONFIG_FILE angeben.

Ein Beispiel bietet die etcd.conf.yml-Beispieldatei .

Hinweis

Zeitdauerfelder wie --grpc-keepalive-min-time, --grpc-keepalive-interval, --grpc-keepalive-timeout, --backend-batch-interval, --corrupt-check-time, --compact-hash-check-time, --compaction-sleep-interval, --watch-progress-notify-interval, --warning-apply-duration, --warning-unary-request-duration und --downgrade-check-time akzeptieren als Befehlszeilenoptionen menschenlesbare Zeichenfolgen (z. B. 10m, 5s), in einer Konfigurationsdatei jedoch nur ganzzahlige Werte in Nanosekunden. Dies ist eine bekannte Einschränkung der Go-Standardbibliothek , bei der time.Duration als einfache Ganzzahl deserialisiert wird.

Beispiel für ein Intervall von 10 Minuten für Watch-Fortschrittsmeldungen in einer Konfigurationsdatei:

# Correct: 10 minutes in nanoseconds
watch-progress-notify-interval: 600000000000

# Incorrect: will produce an unmarshal error
watch-progress-notify-interval: '10m'

14.3 - Sicherheitsmodell für den Datentransport

Daten während der Übertragung schützen

etcd unterstützt automatisches TLS sowie die Authentifizierung über Clientzertifikate sowohl für die Kommunikation zwischen Clients und Servern als auch zwischen Peers (Servern bzw. innerhalb des Clusters). etcd aktiviert weder die RBAC-basierte Authentifizierung noch die Authentifizierung auf der Transportschicht standardmäßig, um den Einstieg in die Datenbank zu erleichtern. Eine Änderung dieses Standards würde außerdem die Kompatibilität des seit 2013 bestehenden Projekts brechen. Ein etcd-Cluster ohne aktivierte Sicherheitsfunktionen kann seine Daten beliebigen Clients zugänglich machen.

Für den Einstieg werden zunächst ein CA-Zertifikat und ein signiertes Schlüsselpaar für ein Mitglied benötigt. Es wird empfohlen, für jedes Clustermitglied ein neues Schlüsselpaar zu erstellen und zu signieren.

Das Werkzeug cfssl bietet eine einfache Schnittstelle zur Zertifikatserzeugung; ein Beispiel für seine Verwendung steht hier . Alternativ hilft diese Anleitung zum Erzeugen selbstsignierter Schlüsselpaare .

Die folgende Optionsliste ist aufgrund laufender Entwicklungsänderungen möglicherweise nicht aktuell. Die neuesten verfügbaren Optionen lassen sich mit etcd --help oder in der etcd-Hilfe nachschlagen.

Grundlegende Einrichtung

etcd akzeptiert mehrere zertifikatsbezogene Konfigurationsoptionen, entweder als Befehlszeilenoptionen oder als Umgebungsvariablen:

Kommunikation zwischen Client und Server:

--cert-file=<path>: Zertifikat für SSL/TLS-Verbindungen zu etcd. Ist diese Option gesetzt, kann advertise-client-urls das HTTPS-Schema verwenden.

--key-file=<path>: Schlüssel für das Zertifikat. Muss unverschlüsselt sein.

--client-cert-auth: Ist diese Option gesetzt, prüft etcd alle eingehenden HTTPS-Anfragen auf ein von der vertrauenswürdigen CA signiertes Clientzertifikat. Anfragen ohne gültiges Clientzertifikat schlagen fehl. Ist die Authentifizierung aktiviert, liefert das Zertifikat die Anmeldedaten für den im Feld Common Name angegebenen Benutzernamen.

--trusted-ca-file=<path>: Vertrauenswürdige Zertifizierungsstelle.

--auto-tls: Automatisch erzeugte, selbstsignierte Zertifikate für TLS-Verbindungen mit Clients verwenden.

Peer-Kommunikation (zwischen Servern bzw. innerhalb des Clusters):

Die Peer-Optionen funktionieren genauso wie die Optionen für die Kommunikation zwischen Client und Server:

--peer-cert-file=<path>: Zertifikat für SSL/TLS-Verbindungen zwischen Peers. Es wird sowohl beim Lauschen auf der Peer-Adresse als auch beim Senden von Anfragen an andere Peers verwendet.

--peer-key-file=<path>: Schlüssel für das Zertifikat. Muss unverschlüsselt sein.

--peer-client-cert-auth: Ist diese Option gesetzt, prüft etcd alle eingehenden Peer-Anfragen aus dem Cluster auf gültige Clientzertifikate, die von der angegebenen CA signiert wurden.

--peer-trusted-ca-file=<path>: Vertrauenswürdige Zertifizierungsstelle.

--peer-auto-tls: Automatisch erzeugte, selbstsignierte Zertifikate für TLS-Verbindungen zwischen Peers verwenden.

Wird ein Zertifikat für Client-Server- oder Peer-Verbindungen angegeben, muss auch der Schlüssel gesetzt sein. Alle diese Konfigurationsoptionen sind ebenfalls über Umgebungsvariablen wie ETCD_TRUSTED_CA_FILE, ETCD_PEER_TRUSTED_CA_FILE usw. verfügbar.

Gemeinsame Optionen:

--cipher-suites: Kommagetrennte Liste unterstützter TLS-Cipher-Suites zwischen Server und Client sowie zwischen Peers (bei leerem Wert automatisch von Go befüllt).

--tls-min-version=<version> Legt die niedrigste von etcd unterstützte TLS-Version fest.

--tls-max-version=<version> Legt die höchste von etcd unterstützte TLS-Version fest. Ohne Angabe wird die höchste von Go unterstützte Version verwendet.

keyUsage und extendedKeyUsage in TLS-Zertifikaten

Beim Erzeugen von X.509-Zertifikaten zur Absicherung des etcd-Datentransports sollten die Zertifikate je nach ihrer Rolle passende Felder für keyUsage und extendedKeyUsage enthalten. etcd verwendet zur Zertifikatsprüfung die Go-Bibliotheken crypto/tls und crypto/x509, die diese Verwendungszwecke beim TLS-Handshake durchsetzen.

Die folgende Tabelle fasst die empfohlenen Verwendungszwecke für gängige Zertifikatsrollen zusammen:

Zertifikatsrolle keyUsage extendedKeyUsage
Server (Client-Server-Verbindung) digitalSignature, keyEncipherment serverAuth
Client digitalSignature, keyEncipherment clientAuth
Peer (Server-Server-Verbindung) digitalSignature, keyEncipherment serverAuth, clientAuth

Hinweise:

  • Ist --peer-client-cert-auth aktiviert, werden Peer-Zertifikate für gegenseitiges TLS zwischen etcd-Mitgliedern verwendet und benötigen daher sowohl serverAuth als auch clientAuth.
  • Clientzertifikate für --client-cert-auth sollten clientAuth enthalten.

Beispiel 1: Transportsicherheit zwischen Client und Server mit HTTPS

Dafür ein CA-Zertifikat (ca.crt) und ein signiertes Schlüsselpaar (server.crt, server.key) bereithalten.

etcd schrittweise für einfache HTTPS-Transportsicherheit konfigurieren:

$ etcd --name infra0 --data-dir infra0 \
  --cert-file=/path/to/server.crt --key-file=/path/to/server.key \
  --advertise-client-urls=https://127.0.0.1:2379 --listen-client-urls=https://127.0.0.1:2379

Der Start sollte problemlos gelingen. Die Konfiguration lässt sich anschließend durch HTTPS-Kommunikation mit etcd testen:

$ curl --cacert /path/to/ca.crt https://127.0.0.1:2379/v2/keys/foo -XPUT -d value=bar -v

Der Befehl sollte einen erfolgreichen Handshake anzeigen. Da selbstsignierte Zertifikate mit einer eigenen Zertifizierungsstelle verwendet werden, muss die CA mit der Option --cacert an curl übergeben werden. Alternativ kann das CA-Zertifikat zum Verzeichnis der vertrauenswürdigen Systemzertifikate hinzugefügt werden, gewöhnlich /etc/pki/tls/certs oder /etc/ssl/certs.

Benutzer von OSX 10.9+: curl 7.30.0 auf OSX 10.9+ versteht keine auf der Befehlszeile übergebenen Zertifikate. Stattdessen die Testdatei ca.crt direkt in den Schlüsselbund importieren oder curl die Option -k übergeben, um Fehler zu ignorieren. Für einen Test ohne -k den Befehl open ./tests/fixtures/ca/ca.crt ausführen und den Anweisungen folgen. Dieses Zertifikat nach dem Test unbedingt entfernen! Falls eine andere Lösung bekannt ist, teilen Sie uns diese mit.

Beispiel 2: Authentifizierung zwischen Client und Server mit HTTPS-Clientzertifikaten

Bisher kann der etcd-Client die Serveridentität prüfen und Transportsicherheit herstellen. Mit Clientzertifikaten lässt sich darüber hinaus unbefugter Zugriff auf etcd verhindern.

Die Clients übermitteln ihre Zertifikate an den Server. Dieser prüft, ob das Zertifikat von der angegebenen CA signiert wurde, und entscheidet, ob er die Anfrage bedient.

Dafür werden dieselben Dateien wie im ersten Beispiel benötigt, außerdem ein von derselben Zertifizierungsstelle signiertes Schlüsselpaar für den Client (client.crt, client.key).

$ etcd --name infra0 --data-dir infra0 \
  --client-cert-auth --trusted-ca-file=/path/to/ca.crt --cert-file=/path/to/server.crt --key-file=/path/to/server.key \
  --advertise-client-urls https://127.0.0.1:2379 --listen-client-urls https://127.0.0.1:2379

Nun dieselbe Anfrage wie oben an diesen Server senden:

$ curl --cacert /path/to/ca.crt https://127.0.0.1:2379/v2/keys/foo -XPUT -d value=bar -v

Der Server sollte die Anfrage ablehnen:

...
routines:SSL3_READ_BYTES:sslv3 alert bad certificate
...

Damit sie erfolgreich ist, muss das von der CA signierte Clientzertifikat an den Server übergeben werden:

$ curl --cacert /path/to/ca.crt --cert /path/to/client.crt --key /path/to/client.key \
  -L https://127.0.0.1:2379/v2/keys/foo -XPUT -d value=bar -v

Die Ausgabe sollte Folgendes enthalten:

...
SSLv3, TLS handshake, CERT verify (15):
...
TLS handshake, Finished (20)

Außerdem die Antwort des Servers:

{
    "action": "set",
    "node": {
        "createdIndex": 12,
        "key": "/foo",
        "modifiedIndex": 12,
        "value": "bar"
    }
}

Cipher-Suites angeben, um schwache TLS-Cipher-Suites zu sperren.

Der TLS-Handshake schlägt fehl, wenn das Client Hello ungültige Cipher-Suites anfordert.

Zum Beispiel:

$ etcd \
  --cert-file ./server.crt \
  --key-file ./server.key \
  --trusted-ca-file ./ca.crt \
  --cipher-suites TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

Clientanfragen müssen dann eine der auf dem Server angegebenen Cipher-Suites verwenden:

# valid cipher suite
$ curl \
  --cacert /path/to/ca.crt \
  --cert /path/to/client.crt \
  --key /path/to/client.key \
  -L [CLIENT-URL]/metrics \
  --ciphers ECDHE-RSA-AES128-GCM-SHA256

# request succeeds
etcd_server_version{server_version="3.2.22"} 1
...
# invalid cipher suite
$ curl \
  --cacert /path/to/ca.crt \
  --cert /path/to/client.crt \
  --key /path/to/client.key \
  -L [CLIENT-URL]/metrics \
  --ciphers ECDHE-RSA-DES-CBC3-SHA

# request fails with
(35) error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure

Beispiel 3: Transportsicherheit und Clientzertifikate in einem Cluster

etcd unterstützt dasselbe Modell für die Peer-Kommunikation, also die Kommunikation zwischen etcd-Mitgliedern eines Clusters.

Angenommen, ca.crt sowie zwei Mitglieder mit eigenen, von dieser CA signierten Schlüsselpaaren (member1.crt & member1.key, member2.crt & member2.key) sind vorhanden. Dann wird etcd wie folgt gestartet:

DISCOVERY_URL=... # from https://discovery.etcd.io/new

# member1
$ etcd --name infra1 --data-dir infra1 \
  --peer-client-cert-auth --peer-trusted-ca-file=/path/to/ca.crt --peer-cert-file=/path/to/member1.crt --peer-key-file=/path/to/member1.key \
  --initial-advertise-peer-urls=https://10.0.1.10:2380 --listen-peer-urls=https://10.0.1.10:2380 \
  --discovery ${DISCOVERY_URL}

# member2
$ etcd --name infra2 --data-dir infra2 \
  --peer-client-cert-auth --peer-trusted-ca-file=/path/to/ca.crt --peer-cert-file=/path/to/member2.crt --peer-key-file=/path/to/member2.key \
  --initial-advertise-peer-urls=https://10.0.1.11:2380 --listen-peer-urls=https://10.0.1.11:2380 \
  --discovery ${DISCOVERY_URL}

Die etcd-Mitglieder bilden einen Cluster. Die gesamte Kommunikation zwischen dessen Mitgliedern wird verschlüsselt und anhand der Clientzertifikate authentifiziert. Die Ausgabe von etcd zeigt, dass die für Verbindungen verwendeten Adressen HTTPS nutzen.

Beispiel 4: Automatische Transportsicherheit mit selbstsignierten Zertifikaten

Warnung

Werden ClientAutoTLS und PeerAutoTLS angegeben, sind die von etcd automatisch erzeugten Client- und Peer-Zertifikate nur 1 Jahr gültig. Mit der Option –self-signed-cert-validity lässt sich die Gültigkeitsdauer der Zertifikate in Jahren festlegen.

Für Fälle, in denen die Kommunikation verschlüsselt, aber nicht authentifiziert werden muss, kann etcd seine Nachrichten mit automatisch erzeugten, selbstsignierten Zertifikaten verschlüsseln. Dies vereinfacht die Bereitstellung, da Zertifikate und Schlüssel nicht außerhalb von etcd verwaltet werden müssen. etcd mit den Optionen --auto-tls und --peer-auto-tls so konfigurieren, dass es selbstsignierte Zertifikate für Client- und Peer-Verbindungen verwendet:

DISCOVERY_URL=... # from https://discovery.etcd.io/new

# member1
$ etcd --name infra1 --data-dir infra1 \
  --auto-tls --peer-auto-tls \
  --initial-advertise-peer-urls=https://10.0.1.10:2380 --listen-peer-urls=https://10.0.1.10:2380 \
  --discovery ${DISCOVERY_URL}

# member2
$ etcd --name infra2 --data-dir infra2 \
  --auto-tls --peer-auto-tls \
  --initial-advertise-peer-urls=https://10.0.1.11:2380 --listen-peer-urls=https://10.0.1.11:2380 \
  --discovery ${DISCOVERY_URL}

Selbstsignierte Zertifikate authentifizieren keine Identität, daher gibt curl einen Fehler zurück:

curl: (60) SSL certificate problem: Invalid certificate chain

Um die Prüfung der Zertifikatskette zu deaktivieren, curl mit der Option -k aufrufen:

$ curl -k https://127.0.0.1:2379/v2/keys/foo -Xput -d value=bar -v

Hinweise zu DNS SRV

Seit v3.1.0 (außer v3.2.9) authentifiziert die Initialisierung über SRV-Erkennung ServerName anhand der Stammdomäne aus der Option --discovery-srv. Dies soll Zertifikatsangriffe nach dem Man-in-the-Middle-Prinzip verhindern, indem ein passender Stammdomänenname im Feld Subject Alternative Name (SAN) des Zertifikats verlangt wird. Beispielsweise authentifiziert etcd --discovery-srv=etcd.local Peers und Clients nur dann, wenn die bereitgestellten Zertifikate die Stammdomäne etcd.local als Eintrag im Feld Subject Alternative Name (SAN) enthalten.

Hinweise zum etcd-Proxy

Hinweis

Dieser Abschnitt beschreibt den historischen v2-Proxy, der inzwischen entfernt wurde. Für etcd 3.7 den v3-gRPC-Proxy verwenden.

Bei einer abgesicherten Clientverbindung terminiert der etcd-Proxy TLS vom Client und verwendet für die Kommunikation mit etcd-Mitgliedern seinen eigenen Schlüssel und sein eigenes Zertifikat aus --peer-key-file und --peer-cert-file.

Der Proxy kommuniziert mit etcd-Mitgliedern sowohl über deren --advertise-client-urls als auch über deren --advertise-peer-urls. Er leitet Clientanfragen an die bekannt gegebenen Client-URLs der Mitglieder weiter und synchronisiert die anfängliche Clusterkonfiguration über deren bekannt gegebene Peer-URLs.

Ist für ein etcd-Mitglied die Clientauthentifizierung aktiviert, muss der Administrator sicherstellen, dass das in --peer-cert-file des Proxys angegebene Peer-Zertifikat für diese Authentifizierung gültig ist. Ist auch die Peerauthentifizierung aktiviert, muss das Peer-Zertifikat des Proxys dafür ebenfalls gültig sein.

Hinweise zur TLS-Authentifizierung

Seit v3.2.0 werden TLS-Zertifikate bei jeder Clientverbindung neu geladen . Dadurch lassen sich ablaufende Zertifikate ersetzen, ohne die etcd-Server zu stoppen: Die alten Zertifikate werden einfach mit neuen überschrieben. Das Aktualisieren bei jeder Verbindung sollte keinen allzu großen Zusatzaufwand verursachen, könnte aber künftig durch eine Caching-Schicht verbessert werden. Beispieltests stehen hier .

Seit v3.2.0 lehnt der Server eingehende Peer-Zertifikate mit falschem IP-SAN ab . Enthält ein Peer-Zertifikat beispielsweise IP-Adressen im Feld Subject Alternative Name (SAN), authentifiziert der Server einen Peer nur, wenn dessen entfernte IP-Adresse einer dieser Adressen entspricht. Dies soll den Beitritt unbefugter Endpunkte zum Cluster verhindern. Der CSR von Peer B (mit cfssl) könnte beispielsweise so aussehen:

{
  "CN": "etcd peer",
  "hosts": [
    "*.example.default.svc",
    "*.example.default.svc.cluster.local",
    "10.138.0.27"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "US",
      "L": "CA",
      "ST": "San Francisco"
    }
  ]
}

Die tatsächliche IP-Adresse von Peer B ist dabei 10.138.0.2, nicht 10.138.0.27. Versucht Peer B dem Cluster beizutreten, lehnt Peer A ihn mit dem Fehler x509: certificate is valid for 10.138.0.27, not 10.138.0.2 ab, weil Bs entfernte IP-Adresse nicht mit der Adresse im Feld Subject Alternative Name (SAN) übereinstimmt.

Seit v3.2.0 löst der Server TLS-DNSNames bei der Prüfung von SAN auf . Enthält ein Peer-Zertifikat im Feld Subject Alternative Name (SAN) nur DNS-Namen und keine IP-Adressen, authentifiziert der Server den Peer nur, wenn die Vorwärtsauflösung dieser Namen (dig b.com) eine zur entfernten IP-Adresse passende Adresse ergibt. Der CSR von Peer B (mit cfssl) könnte beispielsweise so aussehen:

{
  "CN": "etcd peer",
  "hosts": [
    "b.com"
  ],

Die entfernte IP-Adresse von Peer B ist dabei 10.138.0.2. Versucht B dem Cluster beizutreten, löst Peer A den eingehenden Host b.com auf, um die Liste seiner IP-Adressen zu erhalten (z. B. mit dig b.com). Enthält die Liste die IP-Adresse 10.138.0.2 nicht, lehnt A den Peer B mit dem Fehler tls: 10.138.0.2 does not match any of DNSNames ["b.com"] ab.

Seit v3.2.2 akzeptiert der Server Verbindungen bei passender IP-Adresse ohne Prüfung der DNS-Einträge . Enthält ein Peer-Zertifikat im Feld Subject Alternative Name (SAN) sowohl IP-Adressen als auch DNS-Namen und stimmt die entfernte IP-Adresse mit einer dieser IP-Adressen überein, akzeptiert der Server die Verbindung ohne weitere Prüfung der DNS-Namen. Der CSR von Peer B (mit cfssl) könnte beispielsweise so aussehen:

{
  "CN": "etcd peer",
  "hosts": [
    "invalid.domain",
    "10.138.0.2"
  ],

Die entfernte IP-Adresse von Peer B ist dabei 10.138.0.2, und invalid.domain ist ein ungültiger Host. Versucht B dem Cluster beizutreten, authentifiziert Peer A ihn erfolgreich, da das Feld Subject Alternative Name (SAN) eine gültige, passende IP-Adresse enthält. Weitere Einzelheiten stehen in Issue #8206 .

Seit v3.2.5 unterstützt der Server die Rückwärtsauflösung für DNS-SAN mit Platzhaltern . Enthält ein Peer-Zertifikat im Feld Subject Alternative Name (SAN) nur DNS-Namen und keine IP-Adressen, führt der Server zunächst eine Rückwärtsauflösung der entfernten IP-Adresse durch, um die zugehörigen Namen zu erhalten (z. B. nslookup IPADDR). Er akzeptiert die Verbindung, wenn einer dieser Namen exakt oder über einen Platzhalter mit einem DNS-Namen des Peer-Zertifikats übereinstimmt. Andernfalls führt er für jeden DNS-Eintrag des Peer-Zertifikats eine Vorwärtsauflösung durch (z. B. example.default.svc bei einem Eintrag *.example.default.svc). Er akzeptiert die Verbindung dann nur, wenn die aufgelösten Adressen des Hosts die entfernte IP-Adresse des Peers enthalten. Der CSR von Peer B (mit cfssl) könnte beispielsweise so aussehen:

{
  "CN": "etcd peer",
  "hosts": [
    "*.example.default.svc",
    "*.example.default.svc.cluster.local"
  ],

Die entfernte IP-Adresse von Peer B ist dabei 10.138.0.2. Versucht B dem Cluster beizutreten, löst Peer A die IP-Adresse 10.138.0.2 rückwärts auf, um die Liste der Hostnamen zu erhalten. Anschließend vergleicht er diese Hostnamen exakt oder über Platzhalter mit den DNS-Namen im Feld Subject Alternative Name (SAN) von Bs Zertifikat. Schlägt sowohl die Rückwärts- als auch die Vorwärtsauflösung fehl, gibt er den Fehler "tls: "10.138.0.2" does not match any of DNSNames ["*.example.default.svc","*.example.default.svc.cluster.local"] zurück. Weitere Einzelheiten stehen in Issue #8268 .

v3.3.0 ergänzt die Option etcd --peer-cert-allowed-cn , um eine CN-basierte Authentifizierung (Common Name) für Verbindungen zwischen Peers zu unterstützen. Bei der TLS-Initialisierung von Kubernetes werden dynamische Zertifikate für etcd-Mitglieder und andere Systemkomponenten erzeugt (z. B. API-Server, kubelet usw.). Separate CAs für jede Komponente ermöglichen eine strengere Zugriffskontrolle für den etcd-Cluster, sind aber häufig aufwendig zu pflegen. Mit –peer-cert-allowed-cn kann ein Knoten auch bei gemeinsam genutzten CAs nur mit passendem Common Name beitreten. Der Abgleich ist ein exakter Zeichenfolgenvergleich mit dem Feld Common Name (CN) des Zertifikats; Platzhalter und Präfixvergleiche werden nicht unterstützt. Für die Filterung anhand von Hostnamen mit –peer-cert-allowed-hostname oder –client-cert-allowed-hostname wird die Go-Funktion x509.Certificate.VerifyHostname() verwendet. Sie unterstützt sowohl exakte Hostnamen als auch Platzhaltereinträge (z. B. *.example.com). Beispielsweise wird jedes Mitglied eines Clusters mit 3 Knoten mit folgenden CSRs (mit cfssl) eingerichtet:

{
  "CN": "etcd.local",
  "hosts": [
    "m1.etcd.local",
    "127.0.0.1",
    "localhost"
  ],
{
  "CN": "etcd.local",
  "hosts": [
    "m2.etcd.local",
    "127.0.0.1",
    "localhost"
  ],
{
  "CN": "etcd.local",
  "hosts": [
    "m3.etcd.local",
    "127.0.0.1",
    "localhost"
  ],

Wird --peer-cert-allowed-cn etcd.local angegeben, werden nur Peers mit passenden Common Names authentifiziert. Knoten mit anderen CNs in ihren CSRs oder einem anderen --peer-cert-allowed-cn werden abgelehnt:

$ etcd --peer-cert-allowed-cn m1.etcd.local

I | embed: rejected connection from "127.0.0.1:48044" (error "CommonName authentication failed", ServerName "m1.etcd.local")
I | embed: rejected connection from "127.0.0.1:55702" (error "remote error: tls: bad certificate", ServerName "m3.etcd.local")

Jeder Prozess sollte wie folgt gestartet werden:

etcd --peer-cert-allowed-cn etcd.local

I | pkg/netutil: resolving m3.etcd.local:32380 to 127.0.0.1:32380
I | pkg/netutil: resolving m2.etcd.local:22380 to 127.0.0.1:22380
I | pkg/netutil: resolving m1.etcd.local:2380 to 127.0.0.1:2380
I | etcdserver: published {Name:m3 ClientURLs:[https://m3.etcd.local:32379]} to cluster 9db03f09b20de32b
I | embed: ready to serve client requests
I | etcdserver: published {Name:m1 ClientURLs:[https://m1.etcd.local:2379]} to cluster 9db03f09b20de32b
I | embed: ready to serve client requests
I | etcdserver: published {Name:m2 ClientURLs:[https://m2.etcd.local:22379]} to cluster 9db03f09b20de32b
I | embed: ready to serve client requests
I | embed: serving client requests on 127.0.0.1:32379
I | embed: serving client requests on 127.0.0.1:22379
I | embed: serving client requests on 127.0.0.1:2379

v3.2.19 und v3.3.4 beheben das erneute Laden von TLS, wenn das SAN-Feld des Zertifikats nur IP-Adressen und keine Domänennamen enthält . Ein Mitglied könnte beispielsweise mit folgenden CSRs (mit cfssl) eingerichtet sein:

{
  "CN": "etcd.local",
  "hosts": [
    "127.0.0.1"
  ],

In Go ruft der Server (*tls.Config).GetCertificate zum erneuten Laden von TLS genau dann auf, wenn sein Feld (*tls.Config).Certificates leer ist oder (*tls.ClientHelloInfo).ServerName nicht leer ist und eine gültige SNI vom Client enthält. Früher befüllte etcd (*tls.Config).Certificates beim ersten TLS-Handshake des Clients immer, sodass es nicht leer war. Daher musste der Client stets eine passende SNI liefern, um die TLS-Prüfung zu bestehen und (*tls.Config).GetCertificate zum erneuten Laden der TLS-Dateien auszulösen.

Bei einem Zertifikat, dessen SAN-Feld keine Domänennamen, sondern nur IP-Adressen enthält , wird jedoch *tls.ClientHelloInfo mit leerem Feld ServerName angefordert. Dadurch wird beim ersten TLS-Handshake kein erneutes Laden ausgelöst. Das ist problematisch, wenn abgelaufene Zertifikate im laufenden Betrieb ersetzt werden müssen.

Nun wird (*tls.Config).Certificates beim ersten TLS-Handshake des Clients leer angelegt, um zunächst (*tls.Config).GetCertificate auszulösen und anschließend die übrigen Zertifikate bei jeder neuen TLS-Verbindung zu laden, selbst wenn die SNI des Clients leer ist, etwa bei Zertifikaten, die nur IP-Adressen enthalten.

Hinweise zur Host-Zulassungsliste

Die Option etcd --host-whitelist legt die zulässigen Hostnamen aus HTTP-Clientanfragen fest. Die Richtlinie für Clientursprünge schützt ungesicherte etcd-Server vor „DNS Rebinding“ . Dabei kann eine beliebige Website einfach einen autorisierten DNS-Namen erstellen und ihn auf "localhost" oder eine andere Adresse verweisen lassen. Dadurch werden alle HTTP-Endpunkte eines auf "localhost" lauschenden etcd-Servers zugänglich und somit für DNS-Rebinding-Angriffe anfällig. Weitere Einzelheiten stehen in CVE-2018-5702 .

Die Richtlinie für Clientursprünge funktioniert wie folgt:

  1. Ist die Clientverbindung über HTTPS abgesichert, alle Hostnamen zulassen.
  2. Ist die Clientverbindung nicht abgesichert und "HostWhitelist" nicht leer, nur HTTP-Anfragen zulassen, deren Host-Feld in der Zulassungsliste steht.

Für strengere Kontrolle wird diese Richtlinie unabhängig davon durchgesetzt, ob die Authentifizierung aktiviert ist.

Standardmäßig verwenden etcd --host-whitelist und embed.Config.HostWhitelist den Wert *, sodass alle Hostnamen zugelassen sind. Eine leere Zulassungsliste erlaubt ebenfalls alle Hostnamen. Bei der Angabe von Hostnamen werden Loopback-Adressen nicht automatisch hinzugefügt. Um Loopback-Schnittstellen zuzulassen, sie manuell in die Zulassungsliste aufnehmen (z. B. "localhost", "127.0.0.1" usw.).

Häufig gestellte Fragen

Warum erscheint bei der TLS-Clientauthentifizierung ein SSLv3 alert handshake failure?

Das Paket crypto/tls von golang prüft vor der Verwendung des öffentlichen Zertifikatsschlüssels dessen Verwendungszweck. Damit dieser Schlüssel zur Clientauthentifizierung verwendet werden kann, muss bei seiner Erstellung clientAuth zu Extended Key Usage hinzugefügt werden.

Dazu wie folgt vorgehen:

Den folgenden Abschnitt zu openssl.cnf hinzufügen:

[ ssl_client ]
...
  extendedKeyUsage = clientAuth
...

Bei der Zertifikatserstellung unbedingt mit der Option -extensions darauf verweisen:

$ openssl ca -config openssl.cnf -policy policy_anything -extensions ssl_client -out certs/machine.crt -infiles machine.csr

Bei der Peerauthentifizierung mit Zertifikaten erscheint “certificate is valid for 127.0.0.1, not $MY_IP”

Sicherstellen, dass die Zertifikate mit der öffentlichen IP-Adresse des Mitglieds als Subject Name signiert werden. Das Werkzeug etcd-ca bietet beispielsweise die Option --ip= für seinen Befehl new-cert.

Das Zertifikat muss für den FQDN des Mitglieds im Subject Name signiert werden; die IP-Adresse über Subject Alternative Names (kurz IP SANs) ergänzen. Das Werkzeug etcd-ca bietet die Option --domain= für seinen Befehl new-cert; auch openssl kann dies .

Verschlüsselt etcd Daten auf Datenträgern?

Nein. etcd verschlüsselt keine auf Datenträgern gespeicherten Schlüssel-Wert-Daten. Für die Verschlüsselung von in etcd gespeicherten Daten gibt es unter anderem folgende Möglichkeiten:

  • Clientanwendungen die Daten ver- und entschlüsseln lassen
  • Eine Funktion des zugrunde liegenden Speichersystems zur Verschlüsselung gespeicherter Daten verwenden, etwa dm-crypt

Wenn etcd bestimmte neue Verzeichnisse erstellt, setzt es deren Dateiberechtigungen auf 700, um unberechtigten Zugriff möglichst zu verhindern. Hat der Benutzer ein Verzeichnis bereits mit eigenen Einstellungen angelegt, verwendet etcd dieses vorhandene Verzeichnis und protokolliert eine Warnung, falls die Berechtigungen von 700 abweichen.

14.4 - Anleitung zur Clusterbildung

Einen etcd-Cluster initialisieren: statisch, mit etcd-Erkennung oder mit DNS-Erkennung

Überblick

Der statische Start eines etcd-Clusters setzt voraus, dass jedes Mitglied ein anderes Mitglied des Clusters kennt. In manchen Fällen sind die IP-Adressen der Clustermitglieder im Voraus noch nicht bekannt. Dann lässt sich der etcd-Cluster mithilfe eines Erkennungsdiensts initialisieren.

Sobald ein etcd-Cluster läuft, werden Mitglieder über die Laufzeitrekonfiguration hinzugefügt oder entfernt. Für ein besseres Verständnis des zugrunde liegenden Entwurfs empfehlen wir das Entwurfsdokument zur Laufzeitkonfiguration .

Diese Anleitung behandelt folgende Verfahren zur Initialisierung eines etcd-Clusters:

Mit jedem Verfahren wird ein etcd-Cluster aus drei Rechnern mit folgenden Eigenschaften erstellt:

Name Adresse Hostname
infra0 10.0.1.10 infra0.example.com
infra1 10.0.1.11 infra1.example.com
infra2 10.0.1.12 infra2.example.com

Statisch

Da Mitglieder, Adressen und Größe des Clusters vor dem Start bekannt sind, lässt sich mit der Option initial-cluster eine Offline-Konfiguration zur Initialisierung verwenden. Auf jedem Rechner werden entweder die folgenden Umgebungsvariablen oder Befehlszeilenoptionen gesetzt:

ETCD_INITIAL_CLUSTER="infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380"
ETCD_INITIAL_CLUSTER_STATE=new
--initial-cluster infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380 \
--initial-cluster-state new

Die in initial-cluster angegebenen URLs sind die bekannt gegebenen Peer-URLs. Sie sollten also dem Wert von initial-advertise-peer-urls auf den jeweiligen Knoten entsprechen.

Werden zu Testzwecken mehrere Cluster mit derselben Konfiguration gestartet oder ein einzelner Cluster wiederholt erstellt und gelöscht, wird dringend empfohlen, jedem Cluster einen eindeutigen initial-cluster-token zuzuweisen. Dadurch kann etcd eindeutige Cluster- und Mitglieds-IDs erzeugen, selbst wenn die Konfigurationen ansonsten exakt übereinstimmen. Dies kann etcd vor Wechselwirkungen zwischen Clustern schützen, die diese beschädigen könnten.

etcd lauscht auf listen-client-urls , um Clientverkehr anzunehmen. Ein etcd-Mitglied gibt die unter advertise-client-urls angegebenen URLs an andere Mitglieder, Proxys und Clients weiter. Sicherstellen, dass die vorgesehenen Clients die advertise-client-urls erreichen können. Ein häufiger Fehler ist, advertise-client-urls auf localhost zu setzen oder den Standardwert beizubehalten, obwohl entfernte Clients etcd erreichen sollen.

Auf jedem Rechner etcd mit diesen Optionen starten:

$ etcd --name infra0 --initial-advertise-peer-urls http://10.0.1.10:2380 \
  --listen-peer-urls http://10.0.1.10:2380 \
  --listen-client-urls http://10.0.1.10:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.10:2379 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-cluster infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380 \
  --initial-cluster-state new
$ etcd --name infra1 --initial-advertise-peer-urls http://10.0.1.11:2380 \
  --listen-peer-urls http://10.0.1.11:2380 \
  --listen-client-urls http://10.0.1.11:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.11:2379 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-cluster infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380 \
  --initial-cluster-state new
$ etcd --name infra2 --initial-advertise-peer-urls http://10.0.1.12:2380 \
  --listen-peer-urls http://10.0.1.12:2380 \
  --listen-client-urls http://10.0.1.12:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.12:2379 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-cluster infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380 \
  --initial-cluster-state new

Die mit --initial-cluster beginnenden Befehlszeilenparameter werden bei späteren Starts von etcd ignoriert. Nach der Erstinitialisierung können die Umgebungsvariablen oder Befehlszeilenoptionen entfernt werden. Muss die Konfiguration später geändert werden, etwa um Mitglieder hinzuzufügen oder zu entfernen, hilft die Anleitung zur Laufzeitkonfiguration .

TLS

etcd unterstützt verschlüsselte Kommunikation über das TLS-Protokoll. TLS-Kanäle können sowohl den internen Clusterverkehr zwischen Peers als auch den Clientverkehr verschlüsseln. Dieser Abschnitt zeigt Beispiele zur Einrichtung eines Clusters mit TLS für Peers und Clients. Weitere Einzelheiten zur TLS-Unterstützung von etcd enthält die Sicherheitsanleitung .

Selbstsignierte Zertifikate

Ein Cluster mit selbstsignierten Zertifikaten verschlüsselt den Verkehr und authentifiziert seine Verbindungen. Für den Start eines solchen Clusters sollte jedes Mitglied ein eigenes Schlüsselpaar (member.crt, member.key) besitzen, das von einem gemeinsamen CA-Zertifikat des Clusters (ca.crt) signiert wurde, sowohl für Peer- als auch für Clientverbindungen. Zertifikate können nach dem etcd-Beispiel zur TLS-Einrichtung erzeugt werden.

Auf jedem Rechner würde etcd mit diesen Optionen gestartet:

$ etcd --name infra0 --initial-advertise-peer-urls https://10.0.1.10:2380 \
  --listen-peer-urls https://10.0.1.10:2380 \
  --listen-client-urls https://10.0.1.10:2379,https://127.0.0.1:2379 \
  --advertise-client-urls https://10.0.1.10:2379 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-cluster infra0=https://10.0.1.10:2380,infra1=https://10.0.1.11:2380,infra2=https://10.0.1.12:2380 \
  --initial-cluster-state new \
  --client-cert-auth --trusted-ca-file=/path/to/ca-client.crt \
  --cert-file=/path/to/infra0-client.crt --key-file=/path/to/infra0-client.key \
  --peer-client-cert-auth --peer-trusted-ca-file=ca-peer.crt \
  --peer-cert-file=/path/to/infra0-peer.crt --peer-key-file=/path/to/infra0-peer.key
$ etcd --name infra1 --initial-advertise-peer-urls https://10.0.1.11:2380 \
  --listen-peer-urls https://10.0.1.11:2380 \
  --listen-client-urls https://10.0.1.11:2379,https://127.0.0.1:2379 \
  --advertise-client-urls https://10.0.1.11:2379 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-cluster infra0=https://10.0.1.10:2380,infra1=https://10.0.1.11:2380,infra2=https://10.0.1.12:2380 \
  --initial-cluster-state new \
  --client-cert-auth --trusted-ca-file=/path/to/ca-client.crt \
  --cert-file=/path/to/infra1-client.crt --key-file=/path/to/infra1-client.key \
  --peer-client-cert-auth --peer-trusted-ca-file=ca-peer.crt \
  --peer-cert-file=/path/to/infra1-peer.crt --peer-key-file=/path/to/infra1-peer.key
$ etcd --name infra2 --initial-advertise-peer-urls https://10.0.1.12:2380 \
  --listen-peer-urls https://10.0.1.12:2380 \
  --listen-client-urls https://10.0.1.12:2379,https://127.0.0.1:2379 \
  --advertise-client-urls https://10.0.1.12:2379 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-cluster infra0=https://10.0.1.10:2380,infra1=https://10.0.1.11:2380,infra2=https://10.0.1.12:2380 \
  --initial-cluster-state new \
  --client-cert-auth --trusted-ca-file=/path/to/ca-client.crt \
  --cert-file=/path/to/infra2-client.crt --key-file=/path/to/infra2-client.key \
  --peer-client-cert-auth --peer-trusted-ca-file=ca-peer.crt \
  --peer-cert-file=/path/to/infra2-peer.crt --peer-key-file=/path/to/infra2-peer.key

Automatisch erzeugte Zertifikate

Benötigt der Cluster verschlüsselte Kommunikation, aber keine authentifizierten Verbindungen, kann etcd so konfiguriert werden, dass es seine Schlüssel automatisch erzeugt. Bei der Initialisierung erstellt jedes Mitglied eigene Schlüssel anhand seiner bekannt gegebenen IP-Adressen und Hosts.

Auf jedem Rechner würde etcd mit diesen Optionen gestartet:

$ etcd --name infra0 --initial-advertise-peer-urls https://10.0.1.10:2380 \
  --listen-peer-urls https://10.0.1.10:2380 \
  --listen-client-urls https://10.0.1.10:2379,https://127.0.0.1:2379 \
  --advertise-client-urls https://10.0.1.10:2379 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-cluster infra0=https://10.0.1.10:2380,infra1=https://10.0.1.11:2380,infra2=https://10.0.1.12:2380 \
  --initial-cluster-state new \
  --auto-tls \
  --peer-auto-tls
$ etcd --name infra1 --initial-advertise-peer-urls https://10.0.1.11:2380 \
  --listen-peer-urls https://10.0.1.11:2380 \
  --listen-client-urls https://10.0.1.11:2379,https://127.0.0.1:2379 \
  --advertise-client-urls https://10.0.1.11:2379 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-cluster infra0=https://10.0.1.10:2380,infra1=https://10.0.1.11:2380,infra2=https://10.0.1.12:2380 \
  --initial-cluster-state new \
  --auto-tls \
  --peer-auto-tls
$ etcd --name infra2 --initial-advertise-peer-urls https://10.0.1.12:2380 \
  --listen-peer-urls https://10.0.1.12:2380 \
  --listen-client-urls https://10.0.1.12:2379,https://127.0.0.1:2379 \
  --advertise-client-urls https://10.0.1.12:2379 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-cluster infra0=https://10.0.1.10:2380,infra1=https://10.0.1.11:2380,infra2=https://10.0.1.12:2380 \
  --initial-cluster-state new \
  --auto-tls \
  --peer-auto-tls

Fehlerfälle

Im folgenden Beispiel fehlt der neue Host in der Liste der aufgeführten Knoten. Handelt es sich um einen neuen Cluster, muss der Knoten zur Liste der anfänglichen Clustermitglieder hinzugefügt werden.

$ etcd --name infra1 --initial-advertise-peer-urls http://10.0.1.11:2380 \
  --listen-peer-urls https://10.0.1.11:2380 \
  --listen-client-urls http://10.0.1.11:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.11:2379 \
  --initial-cluster infra0=http://10.0.1.10:2380 \
  --initial-cluster-state new
etcd: infra1 not listed in the initial cluster config
exit 1

In diesem Beispiel soll ein Knoten (infra0) einer anderen Adresse (127.0.0.1:2380) zugeordnet werden als der in der Clusterliste aufgeführten (10.0.1.10:2380). Soll dieser Knoten auf mehreren Adressen lauschen, müssen alle Adressen in der Konfigurationsanweisung “initial-cluster” enthalten sein.

$ etcd --name infra0 --initial-advertise-peer-urls http://127.0.0.1:2380 \
  --listen-peer-urls http://10.0.1.10:2380 \
  --listen-client-urls http://10.0.1.10:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.10:2379 \
  --initial-cluster infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380 \
  --initial-cluster-state=new
etcd: error setting up initial cluster: infra0 has different advertised URLs in the cluster and advertised peer URLs list
exit 1

Ist ein Peer mit anderen Konfigurationsargumenten eingerichtet und versucht, diesem Cluster beizutreten, meldet etcd eine abweichende Cluster-ID und beendet sich.

$ etcd --name infra3 --initial-advertise-peer-urls http://10.0.1.13:2380 \
  --listen-peer-urls http://10.0.1.13:2380 \
  --listen-client-urls http://10.0.1.13:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.13:2379 \
  --initial-cluster infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra3=http://10.0.1.13:2380 \
  --initial-cluster-state=new
etcd: conflicting cluster ID to the target cluster (c6ab534d07e8fcc4 != bc25ea2a74fb18b0). Exiting.
exit 1

Erkennung

In manchen Fällen sind die IP-Adressen der Cluster-Peers im Voraus noch nicht bekannt. Dies ist bei Cloud-Anbietern oder Netzwerken mit DHCP üblich. Dann wird anstelle einer statischen Konfiguration ein bestehender etcd-Cluster verwendet, um einen neuen zu initialisieren. Dieser Vorgang heißt „Erkennung“ (Discovery).

Für die Erkennung stehen zwei Verfahren zur Verfügung:

  • etcd-Erkennungsdienst
  • DNS-SRV-Einträge

etcd-Erkennung

Hinweis

Die Beispiele für den Erkennungsdienst in diesem Abschnitt beschreiben das ältere v2-Protokoll, das in etcd 3.7 entfernt wurde. Für einen neuen v3.7-Cluster v3-Discovery oder die statische Initialisierung bzw. DNS-SRV-Verfahren in dieser Anleitung verwenden.

Für ein besseres Verständnis des Protokollentwurfs empfehlen wir die Dokumentation zum Protokoll des Erkennungsdiensts.

Lebensdauer einer Erkennungs-URL

Eine Erkennungs-URL identifiziert einen eindeutigen etcd-Cluster. Für die Initialisierung eines neuen Clusters verwenden alle etcd-Instanzen gemeinsam eine neue Erkennungs-URL, statt eine vorhandene wiederzuverwenden.

Erkennungs-URLs sollten außerdem NUR für die Erstinitialisierung eines Clusters verwendet werden. Wie die Mitgliedschaft eines bereits laufenden Clusters geändert wird, beschreibt die Anleitung zur Laufzeitrekonfiguration .

Eigener etcd-Erkennungsdienst

Die Erkennung verwendet einen vorhandenen Cluster zur Initialisierung. Bei Verwendung eines privaten etcd-Clusters eine URL wie folgt erstellen:

$ curl -X PUT https://myetcd.local/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83/_config/size -d value=3

Durch Setzen des Schlüssels size unter der URL wird eine Erkennungs-URL mit der erwarteten Clustergröße 3 erstellt.

In diesem Fall lautet die zu verwendende URL https://myetcd.local/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83. Die etcd-Mitglieder verwenden beim Start das Verzeichnis https://myetcd.local/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83 zur Registrierung.

Für jedes Mitglied muss die Namensoption einen anderen Wert angeben. Hostname oder machine-id können eine gute Wahl sein. Andernfalls scheitert die Erkennung an doppelten Namen.

Nun etcd für jedes Mitglied mit den entsprechenden Optionen starten:

$ etcd --name infra0 --initial-advertise-peer-urls http://10.0.1.10:2380 \
  --listen-peer-urls http://10.0.1.10:2380 \
  --listen-client-urls http://10.0.1.10:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.10:2379 \
  --discovery https://myetcd.local/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83
$ etcd --name infra1 --initial-advertise-peer-urls http://10.0.1.11:2380 \
  --listen-peer-urls http://10.0.1.11:2380 \
  --listen-client-urls http://10.0.1.11:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.11:2379 \
  --discovery https://myetcd.local/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83
$ etcd --name infra2 --initial-advertise-peer-urls http://10.0.1.12:2380 \
  --listen-peer-urls http://10.0.1.12:2380 \
  --listen-client-urls http://10.0.1.12:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.12:2379 \
  --discovery https://myetcd.local/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83

Dadurch registriert sich jedes Mitglied beim eigenen etcd-Erkennungsdienst. Sobald alle Rechner registriert sind, startet der Cluster.

Öffentlicher etcd-Erkennungsdienst

Ist kein bestehender Cluster verfügbar, den öffentlichen Erkennungsdienst unter discovery.etcd.io verwenden. Mit folgendem Befehl über den Endpunkt “new” eine private Erkennungs-URL erstellen:

$ curl https://discovery.etcd.io/new?size=3
https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de

Dies erstellt den Cluster mit einer anfänglichen Größe von 3 Mitgliedern. Wird keine Größe angegeben, gilt der Standardwert 3.

ETCD_DISCOVERY=https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de
--discovery https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de

Für jedes Mitglied muss die Namensoption einen anderen Wert angeben, andernfalls scheitert die Erkennung an doppelten Namen. Hostname oder machine-id können eine gute Wahl sein.

Nun etcd für jedes Mitglied mit den entsprechenden Optionen starten:

$ etcd --name infra0 --initial-advertise-peer-urls http://10.0.1.10:2380 \
  --listen-peer-urls http://10.0.1.10:2380 \
  --listen-client-urls http://10.0.1.10:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.10:2379 \
  --discovery https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de
$ etcd --name infra1 --initial-advertise-peer-urls http://10.0.1.11:2380 \
  --listen-peer-urls http://10.0.1.11:2380 \
  --listen-client-urls http://10.0.1.11:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.11:2379 \
  --discovery https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de
$ etcd --name infra2 --initial-advertise-peer-urls http://10.0.1.12:2380 \
  --listen-peer-urls http://10.0.1.12:2380 \
  --listen-client-urls http://10.0.1.12:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.12:2379 \
  --discovery https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de

Dadurch registriert sich jedes Mitglied beim Erkennungsdienst. Sobald alle Mitglieder registriert sind, startet der Cluster.

Mit der Umgebungsvariablen ETCD_DISCOVERY_PROXY lässt sich etcd anweisen, einen HTTP-Proxy für die Verbindung zum Erkennungsdienst zu verwenden.

Fehler- und Warnfälle

Fehler des Erkennungsservers
$ etcd --name infra0 --initial-advertise-peer-urls http://10.0.1.10:2380 \
  --listen-peer-urls http://10.0.1.10:2380 \
  --listen-client-urls http://10.0.1.10:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.10:2379 \
  --discovery https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de
etcd: error: the cluster doesn’t have a size configuration value in https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de/_config
exit 1
Warnungen

Diese harmlose Warnung zeigt an, dass die Erkennungs-URL auf diesem Rechner ignoriert wird.

$ etcd --name infra0 --initial-advertise-peer-urls http://10.0.1.10:2380 \
  --listen-peer-urls http://10.0.1.10:2380 \
  --listen-client-urls http://10.0.1.10:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://10.0.1.10:2379 \
  --discovery https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de
etcdserver: discovery token ignored since a cluster has already been initialized. Valid log found at /var/lib/etcd

DNS-Erkennung

DNS-SRV-Einträge können als Erkennungsverfahren verwendet werden. Mit der Option --discovery-srv lässt sich die DNS-Domäne festlegen, unter der die SRV-Einträge für die Erkennung liegen. Mit --discovery-srv example.com werden DNS-SRV-Einträge in der angegebenen Reihenfolge gesucht:

  • _etcd-server-ssl._tcp.example.com
  • _etcd-server._tcp.example.com

Wird _etcd-server-ssl._tcp.example.com gefunden, versucht etcd die Initialisierung über TLS.

Damit Clients den etcd-Cluster finden, werden folgende DNS-SRV-Einträge in der angegebenen Reihenfolge gesucht:

  • _etcd-client._tcp.example.com
  • _etcd-client-ssl._tcp.example.com

Wird _etcd-client-ssl._tcp.example.com gefunden, versuchen Clients, über SSL/TLS mit dem etcd-Cluster zu kommunizieren.

Verwendet etcd TLS, muss der SRV-Eintrag für die Erkennung (z. B. example.com) zusammen mit dem Hostnamen im DNS-SAN des SSL-Zertifikats enthalten sein. Andernfalls scheitert die Clusterbildung mit Protokollmeldungen wie dieser:

[...] rejected connection from "10.0.1.11:53162" (error "remote error: tls: bad certificate", ServerName "example.com")

Verwendet etcd TLS ohne eine eigene Zertifizierungsstelle, muss die Erkennungsdomäne (z. B. example.com) zur Domäne des SRV-Eintrags (z. B. infra1.example.com) passen. Dies erschwert Angriffe mit gefälschten SRV-Einträgen, die auf eine andere Domäne verweisen. Diese Domäne könnte zwar ein gültiges PKI-Zertifikat besitzen, aber von einem unbekannten Dritten kontrolliert werden.

Die Option -discovery-srv-name legt zusätzlich ein Suffix für den während der Erkennung abgefragten SRV-Namen fest. Mit ihr lassen sich mehrere etcd-Cluster unter derselben Domäne unterscheiden. Sind beispielsweise discovery-srv=example.com und -discovery-srv-name=foo gesetzt, werden folgende DNS-SRV-Abfragen gestellt:

  • _etcd-server-ssl-foo._tcp.example.com
  • _etcd-server-foo._tcp.example.com

DNS-SRV-Einträge erstellen

$ dig +noall +answer SRV _etcd-server._tcp.example.com
_etcd-server._tcp.example.com. 300 IN  SRV  0 0 2380 infra0.example.com.
_etcd-server._tcp.example.com. 300 IN  SRV  0 0 2380 infra1.example.com.
_etcd-server._tcp.example.com. 300 IN  SRV  0 0 2380 infra2.example.com.
$ dig +noall +answer SRV _etcd-client._tcp.example.com
_etcd-client._tcp.example.com. 300 IN SRV 0 0 2379 infra0.example.com.
_etcd-client._tcp.example.com. 300 IN SRV 0 0 2379 infra1.example.com.
_etcd-client._tcp.example.com. 300 IN SRV 0 0 2379 infra2.example.com.
$ dig +noall +answer infra0.example.com infra1.example.com infra2.example.com
infra0.example.com.  300  IN  A  10.0.1.10
infra1.example.com.  300  IN  A  10.0.1.11
infra2.example.com.  300  IN  A  10.0.1.12

Den etcd-Cluster über DNS initialisieren

etcd-Clustermitglieder können Domänennamen oder IP-Adressen bekannt geben; die Initialisierung löst DNS-A-Einträge auf. Seit 3.2 lehnen --listen-peer-urls und --listen-client-urls Domänennamen für die Bindung an Netzwerkschnittstellen ab (3.1 gibt Warnungen aus).

Die aufgelöste Adresse in --initial-advertise-peer-urls muss mit einer der aufgelösten Adressen der SRV-Ziele übereinstimmen. Das etcd-Mitglied liest die aufgelöste Adresse, um festzustellen, ob es zu dem in den SRV-Einträgen definierten Cluster gehört.

$ etcd --name infra0 \
--discovery-srv example.com \
--initial-advertise-peer-urls http://infra0.example.com:2380 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster-state new \
--advertise-client-urls http://infra0.example.com:2379 \
--listen-client-urls http://0.0.0.0:2379 \
--listen-peer-urls http://0.0.0.0:2380
$ etcd --name infra1 \
--discovery-srv example.com \
--initial-advertise-peer-urls http://infra1.example.com:2380 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster-state new \
--advertise-client-urls http://infra1.example.com:2379 \
--listen-client-urls http://0.0.0.0:2379 \
--listen-peer-urls http://0.0.0.0:2380
$ etcd --name infra2 \
--discovery-srv example.com \
--initial-advertise-peer-urls http://infra2.example.com:2380 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster-state new \
--advertise-client-urls http://infra2.example.com:2379 \
--listen-client-urls http://0.0.0.0:2379 \
--listen-peer-urls http://0.0.0.0:2380

Der Cluster kann auch mit IP-Adressen anstelle von Domänennamen initialisiert werden:

$ etcd --name infra0 \
--discovery-srv example.com \
--initial-advertise-peer-urls http://10.0.1.10:2380 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster-state new \
--advertise-client-urls http://10.0.1.10:2379 \
--listen-client-urls http://10.0.1.10:2379 \
--listen-peer-urls http://10.0.1.10:2380
$ etcd --name infra1 \
--discovery-srv example.com \
--initial-advertise-peer-urls http://10.0.1.11:2380 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster-state new \
--advertise-client-urls http://10.0.1.11:2379 \
--listen-client-urls http://10.0.1.11:2379 \
--listen-peer-urls http://10.0.1.11:2380
$ etcd --name infra2 \
--discovery-srv example.com \
--initial-advertise-peer-urls http://10.0.1.12:2380 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster-state new \
--advertise-client-urls http://10.0.1.12:2379 \
--listen-client-urls http://10.0.1.12:2379 \
--listen-peer-urls http://10.0.1.12:2380

Seit v3.1.0 (außer v3.2.9) authentifiziert der Server bei TLS-Konfiguration von etcd --discovery-srv=example.com Peers und Clients nur dann, wenn die angegebenen Zertifikate die Stammdomäne example.com als Eintrag im Feld Subject Alternative Name (SAN) enthalten. Siehe Hinweise zu DNS SRV .

Gateway

Das etcd-Gateway ist ein einfacher TCP-Proxy, der Netzwerkdaten an den etcd-Cluster weiterleitet. Weitere Informationen bietet die Gateway-Anleitung .

Proxy

Frühere etcd-Versionen unterstützten über --proxy einen Proxymodus nur für v2. Dieser Modus wurde entfernt und kann mit etcd 3.7 nicht verwendet werden. Für die v3-API den gRPC-Proxy verwenden.

Historische v2-Proxy-Installationen beschreibt die Clusterdokumentation der etcd-Version 2.3 .

14.5 - etcd-Cluster als Kubernetes-StatefulSet ausführen

etcd als Kubernetes-StatefulSet ausführen

Im Folgenden wird gezeigt, wie die statische Initialisierung als Kubernetes-StatefulSet erfolgt.

Beispielmanifest

Dieses Manifest enthält einen Service und ein StatefulSet zur Bereitstellung eines statischen etcd-Clusters in Kubernetes.

Wird der Inhalt des Manifests in eine Datei namens etcd.yaml kopiert, lässt es sich mit diesem Befehl auf einen Cluster anwenden.

$ kubectl apply --filename etcd.yaml

Nach dem Anwenden warten, bis die Pods bereit sind.

$ kubectl get pods
NAME     READY   STATUS    RESTARTS   AGE
etcd-0   1/1     Running   0          24m
etcd-1   1/1     Running   0          24m
etcd-2   1/1     Running   0          24m

Der im Beispiel verwendete Container enthält etcdctl, das direkt innerhalb der Pods aufgerufen werden kann.

$ kubectl exec -it etcd-0 -- etcdctl member list -wtable
+------------------+---------+--------+-------------------------+-------------------------+------------+
|        ID        | STATUS  |  NAME  |       PEER ADDRS        |      CLIENT ADDRS       | IS LEARNER |
+------------------+---------+--------+-------------------------+-------------------------+------------+
| 4f98c3545405a0b0 | started | etcd-2 | http://etcd-2.etcd:2380 | http://etcd-2.etcd:2379 |      false |
| a394e0ee91773643 | started | etcd-0 | http://etcd-0.etcd:2380 | http://etcd-0.etcd:2379 |      false |
| d10297b8d2f01265 | started | etcd-1 | http://etcd-1.etcd:2380 | http://etcd-1.etcd:2379 |      false |
+------------------+---------+--------+-------------------------+-------------------------+------------+

Für eine Bereitstellung mit einem selbstsignierten Zertifikat die auskommentierten Konfigurationsüberschriften beginnend mit ## TLS beachten; dort stehen Werte, deren Kommentierung aufgehoben werden kann. Ein Abschnitt weiter unten enthält zusätzliche Anweisungen zum Erzeugen eines Zertifikats mit cert-manager.

# file: etcd.yaml
---
apiVersion: v1
kind: Service
metadata:
  name: etcd
  namespace: default
spec:
  type: ClusterIP
  clusterIP: None
  selector:
    app: etcd
  ##
  ## Ideally we would use SRV records to do peer discovery for initialization.
  ## Unfortunately discovery will not work without logic to wait for these to
  ## populate in the container. This problem is relatively easy to overcome by
  ## making changes to prevent the etcd process from starting until the records
  ## have populated. The documentation on statefulsets briefly talk about it.
  ##   https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-network-id
  publishNotReadyAddresses: true
  ##
  ## The naming scheme of the client and server ports match the scheme that etcd
  ## uses when doing discovery with SRV records.
  ports:
  - name: etcd-client
    port: 2379
  - name: etcd-server
    port: 2380
  - name: etcd-metrics
    port: 8080
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  namespace: default
  name: etcd
spec:
  ##
  ## The service name is being set to leverage the service headlessly.
  ## https://kubernetes.io/docs/concepts/services-networking/service/#headless-services
  serviceName: etcd
  ##
  ## If you are increasing the replica count of an existing cluster, you should
  ## also update the --initial-cluster-state flag as noted further down in the
  ## container configuration.
  replicas: 3
  ##
  ## For initialization, the etcd pods must be available to eachother before
  ## they are "ready" for traffic. The "Parallel" policy makes this possible.
  podManagementPolicy: Parallel
  ##
  ## To ensure availability of the etcd cluster, the rolling update strategy
  ## is used. For availability, there must be at least 51% of the etcd nodes
  ## online at any given time.
  updateStrategy:
    type: RollingUpdate
  ##
  ## This is label query over pods that should match the replica count.
  ## It must match the pod template's labels. For more information, see the
  ## following documentation:
  ##   https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors
  selector:
    matchLabels:
      app: etcd
  ##
  ## Pod configuration template.
  template:
    metadata:
      ##
      ## The labeling here is tied to the "matchLabels" of this StatefulSet and
      ## "affinity" configuration of the pod that will be created.
      ##
      ## This example's labeling scheme is fine for one etcd cluster per
      ## namespace, but should you desire multiple clusters per namespace, you
      ## will need to update the labeling schema to be unique per etcd cluster.
      labels:
        app: etcd
      annotations:
        ##
        ## This gets referenced in the etcd container's configuration as part of
        ## the DNS name. It must match the service name created for the etcd
        ## cluster. The choice to place it in an annotation instead of the env
        ## settings is because there should only be 1 service per etcd cluster.
        serviceName: etcd
    spec:
      ##
      ## Configuring the node affinity is necessary to prevent etcd servers from
      ## ending up on the same hardware together.
      ##
      ## See the scheduling documentation for more information about this:
      ##   https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity
      affinity:
        ## The podAntiAffinity is a set of rules for scheduling that describe
        ## when NOT to place a pod from this StatefulSet on a node.
        podAntiAffinity:
          ##
          ## When preparing to place the pod on a node, the scheduler will check
          ## for other pods matching the rules described by the labelSelector
          ## separated by the chosen topology key.
          requiredDuringSchedulingIgnoredDuringExecution:
          ## This label selector is looking for app=etcd
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - etcd
            ## This topology key denotes a common label used on nodes in the
            ## cluster. The podAntiAffinity configuration essentially states
            ## that if another pod has a label of app=etcd on the node, the
            ## scheduler should not place another pod on the node.
            ##   https://kubernetes.io/docs/reference/labels-annotations-taints/#kubernetesiohostname
            topologyKey: "kubernetes.io/hostname"
      ##
      ## Containers in the pod
      containers:
      ## This example only has this etcd container.
      - name: etcd
        image: quay.io/coreos/etcd:v3.7.2
        imagePullPolicy: IfNotPresent
        ports:
        - name: etcd-client
          containerPort: 2379
        - name: etcd-server
          containerPort: 2380
        - name: etcd-metrics
          containerPort: 8080
        ##
        ## These probes will fail over TLS for self-signed certificates, so etcd
        ## is configured to deliver metrics over port 8080 further down.
        ##
        ## As mentioned in the "Monitoring etcd" page, /readyz and /livez were
        ## added in v3.5.12. Prior to this, monitoring required extra tooling
        ## inside the container to make these probes work.
        ##
        ## The values in this readiness probe should be further validated, it
        ## is only an example configuration.
        readinessProbe:
          httpGet:
            path: /readyz
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 5
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 30
        ## The values in this liveness probe should be further validated, it
        ## is only an example configuration.
        livenessProbe:
          httpGet:
            path: /livez
            port: 8080
          initialDelaySeconds: 15
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 3
        env:
        ##
        ## Environment variables defined here can be used by other parts of the
        ## container configuration. They are interpreted by Kubernetes, instead
        ## of in the container environment.
        ##
        ## These env vars pass along information about the pod.
        - name: K8S_NAMESPACE
          valueFrom:
            fieldRef:
             fieldPath: metadata.namespace
        - name: HOSTNAME
          valueFrom:
            fieldRef:
             fieldPath: metadata.name
        - name: SERVICE_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.annotations['serviceName']
        ##
        ## Configuring etcdctl inside the container to connect to the etcd node
        ## in the container reduces confusion when debugging.
        - name: ETCDCTL_ENDPOINTS
          value: $(HOSTNAME).$(SERVICE_NAME):2379
        ##
        ## TLS client configuration for etcdctl in the container.
        ## These files paths are part of the "etcd-client-certs" volume mount.
        # - name: ETCDCTL_KEY
        #   value: /etc/etcd/certs/client/tls.key
        # - name: ETCDCTL_CERT
        #   value: /etc/etcd/certs/client/tls.crt
        # - name: ETCDCTL_CACERT
        #   value: /etc/etcd/certs/client/ca.crt
        ##
        ## Use this URI_SCHEME value for non-TLS clusters.
        - name: URI_SCHEME
          value: "http"
        ## TLS: Use this URI_SCHEME for TLS clusters.
        # - name: URI_SCHEME
        # value: "https"
        ##
        ## If you're using a different container, the executable may be in a
        ## different location. This example uses the full path to help remove
        ## ambiguity to you, the reader.
        ## Often you can just use "etcd" instead of "/usr/local/bin/etcd" and it
        ## will work because the $PATH includes a directory containing "etcd".
        command:
        - /usr/local/bin/etcd
        ##
        ## Arguments used with the etcd command inside the container.
        args:
        ##
        ## Configure the name of the etcd server.
        - --name=$(HOSTNAME)
        ##
        ## Configure etcd to use the persistent storage configured below.
        - --data-dir=/data
        ##
        ## In this example we're consolidating the WAL into sharing space with
        ## the data directory. This is not ideal in production environments and
        ## should be placed in it's own volume.
        - --wal-dir=/data/wal
        ##
        ## URL configurations are parameterized here and you shouldn't need to
        ## do anything with these.
        - --listen-peer-urls=$(URI_SCHEME)://0.0.0.0:2380
        - --listen-client-urls=$(URI_SCHEME)://0.0.0.0:2379
        - --advertise-client-urls=$(URI_SCHEME)://$(HOSTNAME).$(SERVICE_NAME):2379
        ##
        ## This must be set to "new" for initial cluster bootstrapping. To scale
        ## the cluster up, this should be changed to "existing" when the replica
        ## count is increased. If set incorrectly, etcd makes an attempt to
        ## start but fail safely.
        - --initial-cluster-state=new
        ##
        ## Token used for cluster initialization. The recommendation for this is
        ## to use a unique token for every cluster. This example parameterized
        ## to be unique to the namespace, but if you are deploying multiple etcd
        ## clusters in the same namespace, you should do something extra to
        ## ensure uniqueness amongst clusters.
        - --initial-cluster-token=etcd-$(K8S_NAMESPACE)
        ##
        ## The initial cluster flag needs to be updated to match the number of
        ## replicas configured. When combined, these are a little hard to read.
        ## Here is what a single parameterized peer looks like:
        ##   etcd-0=$(URI_SCHEME)://etcd-0.$(SERVICE_NAME):2380
        - --initial-cluster=etcd-0=$(URI_SCHEME)://etcd-0.$(SERVICE_NAME):2380,etcd-1=$(URI_SCHEME)://etcd-1.$(SERVICE_NAME):2380,etcd-2=$(URI_SCHEME)://etcd-2.$(SERVICE_NAME):2380
        ##
        ## The peer urls flag should be fine as-is.
        - --initial-advertise-peer-urls=$(URI_SCHEME)://$(HOSTNAME).$(SERVICE_NAME):2380
        ##
        ## This avoids probe failure if you opt to configure TLS.
        - --listen-metrics-urls=http://0.0.0.0:8080
        ##
        ## These are some configurations you may want to consider enabling, but
        ## should look into further to identify what settings are best for you.
        # - --auto-compaction-mode=periodic
        # - --auto-compaction-retention=10m
        ##
        ## TLS client configuration for etcd, reusing the etcdctl env vars.
        # - --client-cert-auth
        # - --trusted-ca-file=$(ETCDCTL_CACERT)
        # - --cert-file=$(ETCDCTL_CERT)
        # - --key-file=$(ETCDCTL_KEY)
        ##
        ## TLS server configuration for etcdctl in the container.
        ## These files paths are part of the "etcd-server-certs" volume mount.
        # - --peer-client-cert-auth
        # - --peer-trusted-ca-file=/etc/etcd/certs/server/ca.crt
        # - --peer-cert-file=/etc/etcd/certs/server/tls.crt
        # - --peer-key-file=/etc/etcd/certs/server/tls.key
        ##
        ## This is the mount configuration.
        volumeMounts:
        - name: etcd-data
          mountPath: /data
        ##
        ## TLS client configuration for etcdctl
        # - name: etcd-client-tls
        #   mountPath: "/etc/etcd/certs/client"
        #   readOnly: true
        ##
        ## TLS server configuration
        # - name: etcd-server-tls
        #   mountPath: "/etc/etcd/certs/server"
        #   readOnly: true
      volumes:
      ##
      ## TLS client configuration
      # - name: etcd-client-tls
      #   secret:
      #     secretName: etcd-client-tls
      #     optional: false
      ##
      ## TLS server configuration
      # - name: etcd-server-tls
      #   secret:
      #     secretName: etcd-server-tls
      #     optional: false
  ##
  ## This StatefulSet will uses the volumeClaimTemplate field to create a PVC in
  ## the cluster for each replica. These PVCs can not be easily resized later.
  volumeClaimTemplates:
  - metadata:
      name: etcd-data
    spec:
      accessModes: ["ReadWriteOnce"]
      ##
      ## In some clusters, it is necessary to explicitly set the storage class.
      ## This example will end up using the default storage class.
      # storageClassName: ""
      resources:
        requests:
          storage: 1Gi

Zertifikate erzeugen

In diesem Abschnitt wird Helm verwendet, um einen Operator namens cert-manager zu installieren.

Ist cert-manager im Cluster installiert, lassen sich dort selbstsignierte Zertifikate erzeugen. Die erzeugten Zertifikate werden in einem Secret-Objekt abgelegt, das als Dateien in Container eingebunden werden kann.

Dies ist der Helm-Befehl zur Installation von cert-manager.

$ helm upgrade --install --create-namespace --namespace cert-manager cert-manager cert-manager --repo https://charts.jetstack.io --set crds.enabled=true

Dies ist eine beispielhafte ClusterIssuer-Konfiguration zum Erzeugen selbstsignierter Zertifikate.

# file: issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: selfsigned
spec:
  selfSigned: {}

Dieses Manifest erzeugt Certificate-Objekte für die Client- und Serverzertifikate und verweist dabei auf den ClusterIssuer “selfsigned”. Die dnsNames sollten eine vollständige Liste gültiger Hostnamen für die von cert-manager erzeugten Zertifikate enthalten.

# file: certificates.yaml
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: etcd-server
  namespace: default
spec:
  secretName: etcd-server-tls
  issuerRef:
    name: selfsigned
    kind: ClusterIssuer
  commonName: etcd
  dnsNames:
  - etcd
  - etcd.default
  - etcd.default.svc.cluster.local
  - etcd-0
  - etcd-0.etcd
  - etcd-0.etcd.default
  - etcd-0.etcd.default.svc
  - etcd-0.etcd.default.svc.cluster.local
  - etcd-1
  - etcd-1.etcd
  - etcd-1.etcd.default
  - etcd-1.etcd.default.svc
  - etcd-1.etcd.default.svc.cluster.local
  - etcd-2
  - etcd-2.etcd
  - etcd-2.etcd.default
  - etcd-2.etcd.default.svc
  - etcd-2.etcd.default.svc.cluster.local
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: etcd-client
  namespace: default
spec:
  secretName: etcd-client-tls
  issuerRef:
    name: selfsigned
    kind: ClusterIssuer
  commonName: etcd
  dnsNames:
  - etcd
  - etcd.default
  - etcd.default.svc.cluster.local
  - etcd-0
  - etcd-0.etcd
  - etcd-0.etcd.default
  - etcd-0.etcd.default.svc
  - etcd-0.etcd.default.svc.cluster.local
  - etcd-1
  - etcd-1.etcd
  - etcd-1.etcd.default
  - etcd-1.etcd.default.svc
  - etcd-1.etcd.default.svc.cluster.local
  - etcd-2
  - etcd-2.etcd
  - etcd-2.etcd.default
  - etcd-2.etcd.default.svc
  - etcd-2.etcd.default.svc.cluster.local

14.6 - etcd-Cluster in Containern ausführen

etcd mit Docker durch statische Initialisierung ausführen

Die folgende Anleitung zeigt, wie etcd mit Docker über die statische Initialisierung ausgeführt wird.

Docker

Um die etcd-API für Clients außerhalb des Docker-Hosts bereitzustellen, die IP-Adresse des Container-Hosts verwenden. Weitere Informationen zum Ermitteln der IP-Adresse bietet docker inspect . Alternativ dem Befehl docker run die Option --net=host übergeben, damit der Container keinen separaten Netzwerkstack erhält.

etcd mit einem einzelnen Knoten ausführen

Bei der Konfiguration von etcd die IP-Adresse des Hosts verwenden:

export NODE1=192.168.1.21

Ein Docker-Volume zur Speicherung der etcd-Daten konfigurieren:

docker volume create --name etcd-data
export DATA_DIR="etcd-data"

Die neueste Version von etcd ausführen (zum Zeitpunkt der Erstellung dieses Dokuments v3.7.2):

ETCD_VERSION=v3.7.2
REGISTRY=quay.io/coreos/etcd
# available from v3.2.5
REGISTRY=gcr.io/etcd-development/etcd

docker run \
  -p 2379:2379 \
  -p 2380:2380 \
  --volume=${DATA_DIR}:/etcd-data \
  --name etcd ${REGISTRY}:${ETCD_VERSION} \
  /usr/local/bin/etcd \
  --data-dir=/etcd-data --name node1 \
  --initial-advertise-peer-urls http://${NODE1}:2380 --listen-peer-urls http://0.0.0.0:2380 \
  --advertise-client-urls http://${NODE1}:2379 --listen-client-urls http://0.0.0.0:2379 \
  --initial-cluster node1=http://${NODE1}:2380

Das Clustermitglied auflisten:

etcdctl --endpoints=http://${NODE1}:2379 member list

Einen etcd-Cluster mit 3 Knoten ausführen

REGISTRY=quay.io/coreos/etcd
# available from v3.2.5
REGISTRY=gcr.io/etcd-development/etcd

# For each machine
ETCD_VERSION=v3.7.2
TOKEN=my-etcd-token
CLUSTER_STATE=new
NAME_1=etcd-node-0
NAME_2=etcd-node-1
NAME_3=etcd-node-2
HOST_1=10.20.30.1
HOST_2=10.20.30.2
HOST_3=10.20.30.3
CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380
DATA_DIR=/var/lib/etcd

# For node 1
THIS_NAME=${NAME_1}
THIS_IP=${HOST_1}
docker run \
  -p 2379:2379 \
  -p 2380:2380 \
  --volume=${DATA_DIR}:/etcd-data \
  --name etcd ${REGISTRY}:${ETCD_VERSION} \
  /usr/local/bin/etcd \
  --data-dir=/etcd-data --name ${THIS_NAME} \
  --initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://0.0.0.0:2380 \
  --advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://0.0.0.0:2379 \
  --initial-cluster ${CLUSTER} \
  --initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}

# For node 2
THIS_NAME=${NAME_2}
THIS_IP=${HOST_2}
docker run \
  -p 2379:2379 \
  -p 2380:2380 \
  --volume=${DATA_DIR}:/etcd-data \
  --name etcd ${REGISTRY}:${ETCD_VERSION} \
  /usr/local/bin/etcd \
  --data-dir=/etcd-data --name ${THIS_NAME} \
  --initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://0.0.0.0:2380 \
  --advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://0.0.0.0:2379 \
  --initial-cluster ${CLUSTER} \
  --initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}

# For node 3
THIS_NAME=${NAME_3}
THIS_IP=${HOST_3}
docker run \
  -p 2379:2379 \
  -p 2380:2380 \
  --volume=${DATA_DIR}:/etcd-data \
  --name etcd ${REGISTRY}:${ETCD_VERSION} \
  /usr/local/bin/etcd \
  --data-dir=/etcd-data --name ${THIS_NAME} \
  --initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://0.0.0.0:2380 \
  --advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://0.0.0.0:2379 \
  --initial-cluster ${CLUSTER} \
  --initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}

etcdctl mit API-Version 3 ausführen:

docker exec etcd /usr/local/bin/etcdctl put foo bar

Physische Hardware

Für die Bereitstellung eines etcd-Clusters mit 3 Knoten auf physischer Hardware können die Beispiele im baremetal-Repository hilfreich sein.

Ein Zertifikatsvolume einhängen

Der veröffentlichte etcd-Container enthält keine standardmäßigen Stammzertifikate. Um HTTPS mit Zertifikaten zu verwenden, denen eine Stammzertifizierungsstelle vertraut (z. B. für die Diensterkennung), ein Zertifikatsverzeichnis in den etcd-Container einhängen:

Der folgende rkt-Befehl ist ein historisches Beispiel. Seine v2-Discovery-Konfiguration ist mit etcd 3.7 nicht kompatibel; für aktuelle Bereitstellungen die Beispiele zur statischen Initialisierung oben verwenden.

ETCD_VERSION=v3.7.2
REGISTRY=quay.io/coreos/etcd
# available from v3.2.5
REGISTRY=docker://gcr.io/etcd-development/etcd

rkt run \
  --insecure-options=image \
  --volume etcd-ssl-certs-bundle,kind=host,source=/etc/ssl/certs/ca-certificates.crt \
  --mount volume=etcd-ssl-certs-bundle,target=/etc/ssl/certs/ca-certificates.crt \
  ${REGISTRY}:${ETCD_VERSION} -- --name my-name \
  --initial-advertise-peer-urls http://localhost:2380 --listen-peer-urls http://localhost:2380 \
  --advertise-client-urls http://localhost:2379 --listen-client-urls http://localhost:2379 \
  --discovery https://discovery.etcd.io/c11fbcdc16972e45253491a24fcf45e1

Das folgende Docker-Beispiel verwendet das oben gesetzte NODE1 und zeigt das Einhängen eines Zertifikatsvolumes mit statischer Initialisierung.

ETCD_VERSION=v3.7.2
REGISTRY=quay.io/coreos/etcd
# available from v3.2.5
REGISTRY=gcr.io/etcd-development/etcd

docker run \
  -p 2379:2379 \
  -p 2380:2380 \
  --volume=/etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt \
  ${REGISTRY}:${ETCD_VERSION} \
  /usr/local/bin/etcd --name my-name \
  --initial-advertise-peer-urls http://${NODE1}:2380 --listen-peer-urls http://0.0.0.0:2380 \
  --advertise-client-urls http://${NODE1}:2379 --listen-client-urls http://0.0.0.0:2379 \
  --initial-cluster my-name=http://${NODE1}:2380

14.7 - Ausfallarten

Arten von Ausfällen und ihre Tolerierung durch etcd

In großen Rechnerinstallationen treten häufig Ausfälle auf. Ein Rechner fällt aus, wenn seine Hardware oder Software nicht ordnungsgemäß funktioniert. Bei Stromausfällen oder Netzwerkproblemen können mehrere Rechner gleichzeitig ausfallen. Auch mehrere Ausfallarten können zugleich auftreten; es ist nahezu unmöglich, alle denkbaren Ausfallszenarien aufzuzählen.

Dieser Abschnitt ordnet Ausfälle nach Arten ein und erläutert, wie etcd sie toleriert. Die meisten, wenn nicht alle Benutzer können einen konkreten Ausfall einer dieser Arten zuordnen. Um auf seltene oder nicht behebbare Ausfälle vorbereitet zu sein, stets Backups des etcd-Clusters erstellen.

Ausfall einer Minderheit der Follower

Wenn Follower ausfallen, aber weniger als die Hälfte aller Clustermitglieder ausgefallen ist und der Leader weiterhin verfügbar bleibt, kann der etcd-Cluster weiterhin Anfragen annehmen und ohne größere Beeinträchtigung weiterarbeiten. Beispielsweise beeinträchtigt der Ausfall von zwei Followern den Betrieb eines etcd-Clusters mit fünf Mitgliedern nicht. Clients verlieren jedoch die Verbindung zu den ausgefallenen Mitgliedern. Clientbibliotheken sollten solche Unterbrechungen bei Leseanfragen vor Benutzern verbergen, indem sie automatisch Verbindungen zu anderen Mitgliedern herstellen. Betreiber sollten damit rechnen, dass diese neuen Verbindungen die Systemlast auf den anderen Mitgliedern erhöhen.

Ausfall des Leaders

Wenn ein Leader ausfällt, wählt der etcd-Cluster automatisch einen neuen Leader. Diese Wahl erfolgt nicht unmittelbar nach dem Ausfall. Sie dauert ungefähr so lange wie das Wahlzeitlimit, da die Ausfallerkennung auf Zeitüberschreitungen beruht.

Während der Leaderwahl kann der Cluster keine Schreiboperationen verarbeiten. Schreibanfragen, die während der Wahl eingehen, werden zur Verarbeitung in eine Warteschlange gestellt, bis ein neuer Leader gewählt ist.

Schreiboperationen, die bereits an den alten Leader gesendet, aber noch nicht festgeschrieben wurden, können verloren gehen. Der neue Leader kann alle nicht festgeschriebenen Einträge des vorherigen Leaders überschreiben. Aus Benutzersicht können einige Schreibanfragen nach der Wahl eines neuen Leaders mit einer Zeitüberschreitung enden. Bereits festgeschriebene Schreiboperationen gehen jedoch niemals verloren.

Der neue Leader verlängert automatisch die Zeitlimits aller Leases. Dieser Mechanismus stellt sicher, dass eine Lease nicht vor Ablauf ihrer gewährten TTL verfällt, selbst wenn sie vom alten Leader gewährt wurde.

Ausfall einer Mehrheit

Wenn die Mehrheit der Clustermitglieder ausfällt, fällt der etcd-Cluster aus und kann keine weiteren Schreiboperationen annehmen.

Der etcd-Cluster kann sich erst von einem Mehrheitsausfall erholen, wenn die Mehrheit der Mitglieder wieder verfügbar ist. Kann eine Mehrheit der Mitglieder nicht wieder online gehen, muss der Betreiber eine Disaster Recovery einleiten, um den Cluster wiederherzustellen.

Sobald eine Mehrheit der Mitglieder wieder funktioniert, wählt der etcd-Cluster automatisch einen neuen Leader und kehrt in einen intakten Zustand zurück. Der neue Leader verlängert automatisch die Zeitlimits aller Leases. Dieser Mechanismus stellt sicher, dass keine Lease wegen serverseitiger Nichtverfügbarkeit abläuft.

Netzwerkpartition

Eine Netzwerkpartition ähnelt dem Ausfall einer Minderheit der Follower oder dem Ausfall des Leaders. Sie teilt den etcd-Cluster in zwei Teile: einen mit einer Mehrheit und einen mit einer Minderheit der Mitglieder. Die Mehrheitsseite bildet den verfügbaren Cluster; die Minderheitsseite ist nicht verfügbar. In etcd gibt es kein „Split Brain“, da Clustermitglieder ausdrücklich hinzugefügt oder entfernt werden und jede solche Änderung von der aktuellen Mehrheit der Mitglieder genehmigt wird.

Befindet sich der Leader auf der Mehrheitsseite, entspricht der Ausfall aus Sicht der Mehrheit dem Ausfall einer Minderheit der Follower. Befindet er sich auf der Minderheitsseite, entspricht dies einem Leaderausfall. Der Leader auf der Minderheitsseite tritt zurück, und die Mehrheitsseite wählt einen neuen Leader.

Sobald die Netzwerkpartition aufgehoben ist, erkennt die Minderheitsseite automatisch den Leader der Mehrheitsseite an und stellt ihren Zustand wieder her.

Ausfall während der Initialisierung

Die Initialisierung eines Clusters ist nur erfolgreich, wenn alle erforderlichen Mitglieder erfolgreich starten. Tritt während der Initialisierung ein Fehler auf, die Datenverzeichnisse aller Mitglieder entfernen und den Cluster mit einem neuen cluster-token oder einem neuen Discovery-Token erneut initialisieren.

Natürlich lässt sich ein während der Initialisierung ausgefallener Cluster ebenso wie ein laufender Cluster wiederherstellen. Da aber keine Daten wiederherzustellen sind, kostet seine Wiederherstellung fast immer mehr Zeit und Ressourcen als die Initialisierung eines neuen Clusters.

14.8 - Recovery nach einem Totalausfall

Snapshot- und Wiederherstellungsfunktionen von etcd v3

etcd ist dafür ausgelegt, Rechnerausfälle zu verkraften. Ein etcd-Cluster erholt sich automatisch von vorübergehenden Ausfällen (z. B. Neustarts von Rechnern) und toleriert bei N Mitgliedern bis zu (N-1)/2 dauerhafte Ausfälle. Fällt ein Mitglied dauerhaft aus, etwa durch einen Hardwaredefekt oder eine Datenbeschädigung auf dem Datenträger, verliert es den Zugriff auf den Cluster. Verliert der Cluster dauerhaft mehr als (N-1)/2 Mitglieder, kommt es zum Totalausfall: Das Quorum geht unwiederbringlich verloren. Ohne Quorum kann der Cluster keinen Konsens mehr erreichen und daher keine weiteren Aktualisierungen annehmen.

Für die Recovery nach einem Totalausfall bietet etcd v3 Snapshot- und Wiederherstellungsfunktionen, mit denen sich der Cluster ohne Verlust von v3-Schlüsseldaten neu erstellen lässt. Zur Wiederherstellung von v2-Schlüsseln siehe das v2-Administrationshandbuch .

Einen Snapshot des Schlüsselraums erstellen

Für die Wiederherstellung eines Clusters wird zunächst ein Snapshot des Schlüsselraums eines etcd-Mitglieds benötigt. Ein Snapshot kann entweder mit etcdctl snapshot save von einem laufenden Mitglied erstellt oder durch Kopieren der Datei member/snap/db aus einem etcd-Datenverzeichnis gewonnen werden. Der folgende Befehl speichert beispielsweise einen Snapshot des von $ENDPOINT bereitgestellten Schlüsselraums in der Datei snapshot.db:

$ ETCDCTL_API=3 etcdctl --endpoints $ENDPOINT snapshot save snapshot.db

Bei einem Snapshot aus der Datei member/snap/db können Daten verloren gehen, die noch nicht in diese Datei geschrieben wurden, sich aber bereits im Ordner wal (Write-Ahead-Log) befinden.

Status eines Snapshots

Mit dem Befehl etcdutl snapshot status lässt sich ermitteln, welche Revision und welchen Hashwert ein Snapshot enthält:

$ etcdutl snapshot status snapshot.db -w table
+---------+----------+------------+------------+
|  HASH   | REVISION | TOTAL KEYS | TOTAL SIZE |
+---------+----------+------------+------------+
| 7ef846e |   485261 |      11642 |      94 MB |
+---------+----------+------------+------------+

Einen Cluster wiederherstellen

Revisionsunterschied

Bei der Wiederherstellung eines Clusters können bestehende Clients feststellen, dass die Revision um viele Hundert oder Tausend zurückspringt. Ein Snapshot enthält nämlich nur die Datenhistorie bis zum Zeitpunkt seiner Erstellung, während der aktuelle Zustand bereits weiter fortgeschritten sein kann.

Dies ist besonders beim Betrieb von Kubernetes mit etcd problematisch. Dort können Controller und Operatoren sogenannte informers verwenden, die als lokale Caches dienen und über Watches über Aktualisierungen benachrichtigt werden. Die Wiederherstellung auf eine ältere Revision aktualisiert diese Caches möglicherweise nicht korrekt und kann dadurch unvorhersehbares und inkonsistentes Verhalten der Controller verursachen.

Bei der Wiederherstellung aus einem Snapshot wird dringend empfohlen, die nachfolgend beschriebene „Revisionserhöhung“ zu verwenden, wenn bekannte Nutzer der Watch-API vorhanden sind, lokale Kopien von etcd-Daten zwischengespeichert werden oder generell Kubernetes eingesetzt wird.

Aus einem Snapshot wiederherstellen

Zur Wiederherstellung eines Clusters genügt eine einzelne Snapshot-Datei “db”. Eine Clusterwiederherstellung mit etcdutl snapshot restore erstellt neue etcd-Datenverzeichnisse; alle Mitglieder sollten denselben Snapshot verwenden. Bei der Wiederherstellung werden einige Snapshot-Metadaten überschrieben, insbesondere die Mitglieds-ID und die Cluster-ID. Das Mitglied verliert damit seine bisherige Identität. Dieses Überschreiben verhindert, dass das neue Mitglied versehentlich einem bestehenden Cluster beitritt. Um einen Cluster aus einem Snapshot zu starten, muss die Wiederherstellung daher einen neuen logischen Cluster erstellen.

Eine einfache Wiederherstellung lässt sich wie folgt ausführen:

$ etcdutl snapshot restore snapshot.db --data-dir output-dir

Integritätsprüfungen

Die Integrität eines Snapshots kann bei der Wiederherstellung optional geprüft werden. Ein mit etcdctl snapshot save erstellter Snapshot enthält einen Integritätshash, den etcdutl snapshot restore prüft. Wird der Snapshot aus dem Datenverzeichnis kopiert, fehlt dieser Hash; die Wiederherstellung ist dann nur mit --skip-hash-check möglich.

Mit Revisionserhöhung wiederherstellen

Damit die Revisionen nach einer Wiederherstellung niemals zurückgehen, kann die Option --bump-revision angegeben werden. Sie nimmt eine 64-Bit-Ganzzahl entgegen, die angibt, wie viele Revisionen zur aktuellen Revision des Snapshots addiert werden sollen. Da jeder Schreibzugriff auf etcd die Revision um eins erhöht, kann eine Erhöhung um 1'000'000'000 einen eine Woche alten Snapshot abdecken, sofern etcd weniger als 1500 Schreibzugriffe pro Sekunde verarbeitet.

Im Zusammenhang mit Kubernetes-Controllern ist es wichtig, mit --mark-compacted auch alle Revisionen einschließlich der Erhöhung als kompaktiert zu markieren. Dies stellt sicher, dass alle Watches beendet werden und etcd keine Anfragen zu Revisionen beantwortet, die nach der Snapshot-Erstellung entstanden sind. Dadurch werden die Informer-Caches effektiv ungültig.

Ein vollständiger Aufruf kann so aussehen:

$ etcdutl snapshot restore snapshot.db --bump-revision 1000000000 --mark-compacted --data-dir output-dir

Mit aktualisierter Mitgliedschaft wiederherstellen

Die Mitglieder eines etcd-Clusters werden in etcd selbst gespeichert und über den Raft-Konsensalgorithmus verwaltet. Ist das Quorum vollständig verloren, kann neu entschieden werden, wo und wie der neue Cluster gebildet wird, beispielsweise mit vollständig neuen Mitgliedern.

Bei der Wiederherstellung aus einem Snapshot kann die neue Mitgliedschaft wie folgt direkt in den Datenspeicher übernommen werden:

$ etcdutl snapshot restore snapshot.db \
  --name m1 \
  --data-dir m1.etcd \
  --initial-cluster m1=http://host1:2380,m2=http://host2:2380,m3=http://host3:2380 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-advertise-peer-urls http://host1:2380

Dies stellt sicher, dass sich der neu aufgebaute Cluster ausschließlich mit den anderen wiederhergestellten Mitgliedern mit dem angegebenen Token verbindet und nicht mit älteren Mitgliedern, die möglicherweise noch laufen und Verbindungen aufzubauen versuchen.

Alternativ kann beim Start von etcd --force-new-cluster angegeben werden, um die Clustermitgliedschaft zu überschreiben und vorhandene Anwendungsdaten beizubehalten. Davon wird jedoch dringend abgeraten, da dies eine Panic auslöst, wenn andere Mitglieder des vorherigen Clusters noch laufen. Unbedingt regelmäßig Snapshots speichern.

End-2-End-Beispiel

Einen Snapshot von einem laufenden Cluster erstellen:

$ etcdctl snapshot save snapshot.db

Aufbauend auf dem vorherigen Beispiel werden im Folgenden neue etcd-Datenverzeichnisse (m1.etcd, m2.etcd, m3.etcd) für einen Cluster mit drei Mitgliedern erstellt:

$ etcdutl snapshot restore snapshot.db \
  --name m1 \
  --data-dir m1_data_dir.etcd \
  --initial-cluster m1=http://host1:2380,m2=http://host2:2380,m3=http://host3:2380 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-advertise-peer-urls http://host1:2380
$ etcdutl snapshot restore snapshot.db \
  --name m2 \
  --data-dir m2_data_dir.etcd \
  --initial-cluster m1=http://host1:2380,m2=http://host2:2380,m3=http://host3:2380 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-advertise-peer-urls http://host2:2380
$ etcdutl snapshot restore snapshot.db \
  --name m3 \
  --data-dir m3_data_dir.etcd \
  --initial-cluster m1=http://host1:2380,m2=http://host2:2380,m3=http://host3:2380 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-advertise-peer-urls http://host3:2380

Anschließend etcd mit den neuen Datenverzeichnissen starten:

$ etcd \
  --name m1 \
  --data-dir m1_data_dir.etcd \
  --listen-client-urls http://host1:2379 \
  --advertise-client-urls http://host1:2379 \
  --listen-peer-urls http://host1:2380 &
$ etcd \
  --name m2 \
  --data-dir m2_data_dir.etcd \
  --listen-client-urls http://host2:2379 \
  --advertise-client-urls http://host2:2379 \
  --listen-peer-urls http://host2:2380 &
$ etcd \
  --name m3 \
  --data-dir m3_data_dir.etcd \
  --listen-client-urls http://host3:2379 \
  --advertise-client-urls http://host3:2379 \
  --listen-peer-urls http://host3:2380 &

Der wiederhergestellte etcd-Cluster sollte nun verfügbar sein und den Schlüsselraum aus dem Snapshot bereitstellen.

Ab etcd v3.6 kann etcdctl nur zum Erstellen eines Snapshots der Daten verwendet werden; zur Wiederherstellung aus einem Snapshot dient etcdutl. Wird --data-dir nicht angegeben, ist der Standardwert von --data-dir gleich <name>.etcd, wobei <name> dem Wert von --name entspricht. Wurde beispielsweise --data-dir nicht angegeben und heißen die Mitglieder m1, m2 und m3, lauten die --data-dir-Verzeichnisse m1.etcd, m2.etcd und m3.etcd.

14.9 - etcd-Gateway

Das etcd-Gateway: Einsatzgebiete und Einrichtung

Was ist das etcd-Gateway?

Das etcd-Gateway ist ein einfacher TCP-Proxy, der Netzwerkdaten an den etcd-Cluster weiterleitet. Es ist zustandslos und transparent: Es untersucht weder Clientanfragen noch greift es in Clusterantworten ein. Es terminiert keine TLS-Verbindungen, führt keine TLS-Handshakes im Namen seiner Clients durch und prüft nicht, ob eine Verbindung abgesichert ist.

Das Gateway unterstützt mehrere etcd-Serverendpunkte und verwendet ein einfaches Round-Robin-Verfahren. Es leitet nur an verfügbare Endpunkte weiter und verbirgt Ausfälle vor seinen Clients. Weitere Wiederholungsstrategien, etwa gewichtetes Round-Robin, können künftig unterstützt werden.

Wann das etcd-Gateway sinnvoll ist

Jede Anwendung, die auf etcd zugreift, muss zunächst die Adresse eines Clientendpunkts des etcd-Clusters kennen. Greifen mehrere Anwendungen auf demselben Server auf denselben etcd-Cluster zu, muss trotzdem jede Anwendung dessen bekannt gegebene Clientendpunkte kennen. Wird der etcd-Cluster so umkonfiguriert, dass er andere Endpunkte hat, muss möglicherweise auch jede Anwendung ihre Endpunktliste aktualisieren. Diese umfassende Umkonfiguration ist aufwendig und fehleranfällig.

Das etcd-Gateway löst dieses Problem, indem es einen stabilen lokalen Endpunkt bereitstellt. In einer typischen Konfiguration läuft auf jedem Rechner ein Gateway, das auf einer lokalen Adresse lauscht; jede etcd-Anwendung verbindet sich mit ihrem lokalen Gateway. Dadurch muss nur das Gateway seine Endpunkte aktualisieren, statt jede einzelne Anwendung anzupassen.

Um Änderungen der Clusterendpunkte automatisch weiterzugeben, läuft das etcd-Gateway also auf jedem Rechner, auf dem mehrere Anwendungen auf denselben etcd-Cluster zugreifen.

Wann das etcd-Gateway nicht sinnvoll ist

  • Leistungssteigerung

Das Gateway ist nicht dafür ausgelegt, die Leistung eines etcd-Clusters zu verbessern. Es bietet weder Caching noch die Zusammenführung von Watches oder die Bündelung von Anfragen. Das etcd-Team entwickelt einen Caching-Proxy, der die Skalierbarkeit von Clustern verbessern soll.

  • Betrieb auf einem Clusterverwaltungssystem

Fortgeschrittene Clusterverwaltungssysteme wie Kubernetes unterstützen Diensterkennung von Haus aus. Anwendungen können über einen DNS-Namen oder eine vom System verwaltete virtuelle IP-Adresse auf einen etcd-Cluster zugreifen. Beispielsweise entspricht kube-proxy dem etcd-Gateway.

Das etcd-Gateway starten

Als Beispiel dient ein etcd-Cluster mit folgenden statischen Endpunkten:

Name Adresse Hostname Port
infra0 10.0.1.10 infra0.example.com 2379
infra1 10.0.1.11 infra1.example.com 2379
infra2 10.0.1.12 infra2.example.com 2379

Das etcd-Gateway mit folgendem Befehl für diese statischen Endpunkte starten:

$ etcd gateway start --endpoints=infra0.example.com:2379,infra1.example.com:2379,infra2.example.com:2379
2016-08-16 11:21:18.867350 I | tcpproxy: ready to proxy client requests to [...]

Alternativ bei einer Diensterkennung über DNS die folgenden DNS-SRV-Einträge betrachten:

$ dig +noall +answer SRV _etcd-client._tcp.example.com
_etcd-client._tcp.example.com. 300 IN SRV 0 0 2379 infra0.example.com.
_etcd-client._tcp.example.com. 300 IN SRV 0 0 2379 infra1.example.com.
_etcd-client._tcp.example.com. 300 IN SRV 0 0 2379 infra2.example.com.
$ dig +noall +answer infra0.example.com infra1.example.com infra2.example.com
infra0.example.com.  300  IN  A  10.0.1.10
infra1.example.com.  300  IN  A  10.0.1.11
infra2.example.com.  300  IN  A  10.0.1.12

Das etcd-Gateway mit folgendem Befehl starten, damit es die Endpunkte aus den DNS-SRV-Einträgen abruft:

$ etcd gateway start --discovery-srv=example.com
2016-08-16 11:21:18.867350 I | tcpproxy: ready to proxy client requests to [...]

Konfigurationsoptionen

etcd-Cluster

–endpoints

  • Kommagetrennte Liste von etcd-Serverzielen, an die Clientverbindungen weitergeleitet werden.
  • Standard: 127.0.0.1:2379
  • Der Port muss enthalten sein.
  • Ungültiges Beispiel: https://127.0.0.1:2379 (das Gateway terminiert TLS nicht). Das Gateway prüft weder das HTTP-Schema noch die Anfragen; es leitet Anfragen lediglich an die angegebenen Endpunkte weiter.

–discovery-srv

  • DNS-Domäne, über die Clusterendpunkte mithilfe von SRV-Einträgen initialisiert werden.
  • Standard: (nicht gesetzt)

Netzwerk

–listen-addr

  • Schnittstelle und Port, an die gebunden wird, um Clientanfragen anzunehmen.
  • Standard: 127.0.0.1:23790

–retry-delay

  • Wartezeit vor einem erneuten Verbindungsversuch zu ausgefallenen Endpunkten.
  • Standard: 1m0s
  • Ungültiges Beispiel: “123” (das Format erwartet eine Zeiteinheit)

Sicherheit

–insecure-discovery

  • SRV-Einträge akzeptieren, die unsicher oder für Man-in-the-Middle-Angriffe anfällig sind.
  • Standard: false

–trusted-ca-file

  • Pfad zur TLS-CA-Datei des Clients für den etcd-Cluster, um die bei der SRV-Erkennung zurückgegebenen Endpunkte zu überprüfen. Sie wird NUR zur Authentifizierung der gefundenen Endpunkte verwendet, nicht zum Aufbau von Verbindungen für die Datenübertragung. Das Gateway terminiert niemals TLS-Verbindungen und erstellt keine TLS-Verbindungen im Namen seiner Clients.
  • Standard: (nicht gesetzt)

14.10 - gRPC-Proxy

Ein zustandsloser etcd-Reverse-Proxy auf der gRPC-Schicht

Der gRPC-Proxy ist ein zustandsloser etcd-Reverse-Proxy auf der gRPC-Schicht (L7). Er soll die gesamte Verarbeitungslast auf dem zentralen etcd-Cluster verringern. Für horizontale Skalierbarkeit führt er Watch- und Lease-API-Anfragen zusammen. Um den Cluster vor missbräuchlich arbeitenden Clients zu schützen, speichert er Anfragen für Schlüsselbereiche zwischen.

Der gRPC-Proxy unterstützt mehrere etcd-Serverendpunkte. Beim Start wählt er zufällig einen davon aus. Dieser Endpunkt bedient alle Anfragen, bis der Proxy einen Endpunktausfall erkennt. Dann wechselt der gRPC-Proxy zu einem anderen Endpunkt, sofern verfügbar, um Ausfälle vor seinen Clients zu verbergen. Weitere Wiederholungsstrategien, etwa gewichtetes Round-Robin, können künftig unterstützt werden.

Skalierbare Watch-API

Der gRPC-Proxy führt mehrere Client-Watcher (c-watchers) für denselben Schlüssel oder Bereich zu einem einzelnen Watcher (s-watcher) zusammen, der mit einem etcd-Server verbunden ist. Der Proxy verteilt alle Ereignisse des s-watcher an seine c-watchers.

Wenn N Clients denselben Schlüssel beobachten, kann ein gRPC-Proxy die Watch-Last auf dem etcd-Server von N auf 1 reduzieren. Durch den Einsatz mehrerer gRPC-Proxys lässt sich die Serverlast weiter verteilen.

Im folgenden Beispiel beobachten drei Clients den Schlüssel A. Der gRPC-Proxy führt die drei Watcher zusammen und erstellt einen einzelnen Watcher am etcd-Server.

            +-------------+
            | etcd server |
            +------+------+
                   ^ watch key A (s-watcher)
                   |
           +-------+-----+
           | gRPC proxy  | <-------+
           |             |         |
           ++-----+------+         |watch key A (c-watcher)
watch key A ^     ^ watch key A    |
(c-watcher) |     | (c-watcher)    |
    +-------+-+  ++--------+  +----+----+
    |  client |  |  client |  |  client |
    |         |  |         |  |         |
    +---------+  +---------+  +---------+

Einschränkungen

Um mehrere Client-Watcher effizient zu einem einzelnen Watcher zusammenzuführen, ordnet der gRPC-Proxy neue c-watchers nach Möglichkeit einem vorhandenen s-watcher zu. Dieser gemeinsame s-watcher kann wegen Netzwerkverzögerungen oder gepufferter, noch nicht zugestellter Ereignisse hinter dem etcd-Server zurückliegen. Ist keine Watch-Revision angegeben, garantiert der gRPC-Proxy nicht, dass der c-watcher bei der neuesten Revision des Speichers zu beobachten beginnt. Beobachtet ein Client beispielsweise direkt über einen etcd-Server mit Revision 1000, beginnt dieser Watcher bei Revision 1000. Bei einem Watch über den gRPC-Proxy kann der Client hingegen bereits bei Revision 990 beginnen.

Ähnliche Einschränkungen gelten für den Abbruch. Beim Abbrechen eines Watchers kann die Revision des etcd-Servers höher sein als die Revision in der Abbruchantwort.

Diese beiden Einschränkungen sollten in den meisten Anwendungsfällen keine Probleme verursachen. Künftig kann es zusätzliche Optionen geben, die den Watcher zwingen, den gRPC-Proxy zu umgehen, um genauere Revisionen in Antworten zu erhalten.

Skalierbare Lease-API

Um seine Leases aufrechtzuerhalten, muss ein Client mindestens einen gRPC-Stream zu einem etcd-Server aufbauen und darüber regelmäßig Heartbeats senden. Bei einer etcd-Arbeitslast mit umfangreicher Lease-Aktivität über viele Clients hinweg können diese Streams zu einer übermäßigen CPU-Auslastung beitragen. Um die Gesamtzahl der Streams auf dem zentralen Cluster zu verringern, unterstützt der Proxy die Zusammenführung von Lease-Streams.

Wenn N Clients Leases aktualisieren, reduziert ein einzelner gRPC-Proxy die Stream-Last auf dem etcd-Server von N auf 1. Zusätzliche gRPC-Proxys können die Streams weiter auf mehrere Proxys verteilen.

Im folgenden Beispiel aktualisieren drei Clients drei unabhängige Leases (L1, L2 und L3). Der gRPC-Proxy führt die drei Lease-Streams der Clients (c-streams) zu einem einzelnen Stream zur Aufrechterhaltung von Leases (s-stream) zusammen, der mit einem etcd-Server verbunden ist. Der Proxy leitet die clientseitigen Lease-Heartbeats von den c-streams an den s-stream weiter und sendet die Antworten anschließend an die jeweiligen c-streams zurück.

          +-------------+
          | etcd server |
          +------+------+
                 ^
                 | heartbeat L1, L2, L3
                 | (s-stream)
                 v
         +-------+-----+
         | gRPC proxy  +<-----------+
         +---+------+--+            | heartbeat L3
             ^      ^               | (c-stream)
heartbeat L1 |      | heartbeat L2  |
(c-stream)   v      v (c-stream)    v
      +------+-+  +-+------+  +-----+--+
      | client |  | client |  | client |
      +--------+  +--------+  +--------+

Schutz vor missbräuchlich arbeitenden Clients

Der gRPC-Proxy speichert Antworten auf Anfragen zwischen, sofern dies keine Konsistenzanforderungen verletzt. Dadurch kann er den etcd-Server vor missbräuchlich arbeitenden Clients schützen, die Anfragen in engen for-Schleifen senden.

Den etcd-gRPC-Proxy starten

Als Beispiel dient ein etcd-Cluster mit folgenden statischen Endpunkten:

Name Adresse Hostname
infra0 10.0.1.10 infra0.example.com
infra1 10.0.1.11 infra1.example.com
infra2 10.0.1.12 infra2.example.com

Den etcd-gRPC-Proxy mit folgendem Befehl für diese statischen Endpunkte starten:

$ etcd grpc-proxy start --endpoints=infra0.example.com,infra1.example.com,infra2.example.com --listen-addr=127.0.0.1:2379

Der etcd-gRPC-Proxy startet und lauscht auf Port 2379. Er leitet Clientanfragen an einen der drei oben angegebenen Endpunkte weiter.

Anfragen über den Proxy senden:

$ ETCDCTL_API=3 etcdctl --endpoints=127.0.0.1:2379 put foo bar
OK
$ ETCDCTL_API=3 etcdctl --endpoints=127.0.0.1:2379 get foo
foo
bar

Synchronisierung der Clientendpunkte und Namensauflösung

Der Proxy kann seine Endpunkte zur Diensterkennung registrieren, indem er an einen benutzerdefinierten Endpunkt schreibt. Dies dient zwei Zwecken. Erstens können Clients ihre Endpunkte mit einer Menge von Proxyendpunkten synchronisieren, um Hochverfügbarkeit zu erreichen. Zweitens stellt dies Endpunkte für die gRPC-Namensauflösung von etcd bereit.

Proxys durch Angabe eines benutzerdefinierten Präfixes registrieren:

$ etcd grpc-proxy start --endpoints=localhost:2379 \
  --listen-addr=127.0.0.1:23790 \
  --advertise-client-url=127.0.0.1:23790 \
  --resolver-prefix="___grpc_proxy_endpoint" \
  --resolver-ttl=60

$ etcd grpc-proxy start --endpoints=localhost:2379 \
  --listen-addr=127.0.0.1:23791 \
  --advertise-client-url=127.0.0.1:23791 \
  --resolver-prefix="___grpc_proxy_endpoint" \
  --resolver-ttl=60

Der Proxy führt bei der Abfrage der Mitgliederliste alle seine Mitglieder auf:

ETCDCTL_API=3 etcdctl --endpoints=http://localhost:23790 member list --write-out table

+----+---------+--------------------------------+------------+-----------------+
| ID | STATUS  |              NAME              | PEER ADDRS |  CLIENT ADDRS   |
+----+---------+--------------------------------+------------+-----------------+
|  0 | started | Gyu-Hos-MBP.sfo.coreos.systems |            | 127.0.0.1:23791 |
|  0 | started | Gyu-Hos-MBP.sfo.coreos.systems |            | 127.0.0.1:23790 |
+----+---------+--------------------------------+------------+-----------------+

Dadurch können Clients Proxyendpunkte automatisch über Sync erkennen:

cli, err := clientv3.New(clientv3.Config{
    Endpoints: []string{"http://localhost:23790"},
})
if err != nil {
    log.Fatal(err)
}
defer cli.Close()

// fetch registered grpc-proxy endpoints
if err := cli.Sync(context.Background()); err != nil {
    log.Fatal(err)
}

Wird ein Proxy ohne Resolver-Präfix konfiguriert,

$ etcd grpc-proxy start --endpoints=localhost:2379 \
  --listen-addr=127.0.0.1:23792 \
  --advertise-client-url=127.0.0.1:23792

gibt die Mitgliederlisten-API des grpc-proxy dessen eigene advertise-client-url zurück:

ETCDCTL_API=3 etcdctl --endpoints=http://localhost:23792 member list --write-out table

+----+---------+--------------------------------+------------+-----------------+
| ID | STATUS  |              NAME              | PEER ADDRS |  CLIENT ADDRS   |
+----+---------+--------------------------------+------------+-----------------+
|  0 | started | Gyu-Hos-MBP.sfo.coreos.systems |            | 127.0.0.1:23792 |
+----+---------+--------------------------------+------------+-----------------+

Namensräume

Angenommen, eine Anwendung erwartet die volle Kontrolle über den gesamten Schlüsselraum, der etcd-Cluster wird aber mit anderen Anwendungen geteilt. Damit alle Anwendungen ohne gegenseitige Beeinträchtigung laufen können, kann der Proxy den etcd-Schlüsselraum so aufteilen, dass Clients scheinbar auf den vollständigen Schlüsselraum zugreifen. Wird dem Proxy die Option --namespace übergeben, werden alle eingehenden Clientanfragen so umgeschrieben, dass die Schlüssel ein benutzerdefiniertes Präfix erhalten. Zugriffe auf den etcd-Cluster erfolgen unter diesem Präfix; der Proxy entfernt es aus den Antworten. Für den Client wirkt es, als gäbe es überhaupt kein Präfix.

Um einen Namensraum für einen Proxy festzulegen, ihn mit --namespace starten:

$ etcd grpc-proxy start --endpoints=localhost:2379 \
  --listen-addr=127.0.0.1:23790 \
  --namespace=my-prefix/

Bei Zugriffen auf den Proxy wird nun im etcd-Cluster transparent das Präfix vorangestellt:

$ ETCDCTL_API=3 etcdctl --endpoints=localhost:23790 put my-key abc
# OK
$ ETCDCTL_API=3 etcdctl --endpoints=localhost:23790 get my-key
# my-key
# abc
$ ETCDCTL_API=3 etcdctl --endpoints=localhost:2379 get my-prefix/my-key
# my-prefix/my-key
# abc

TLS-Terminierung

Der gRPC-Proxy kann TLS zu einem abgesicherten etcd-Cluster terminieren und dafür einen unverschlüsselten lokalen Endpunkt bereitstellen.

Zum Ausprobieren einen Ein-Mitglied-Cluster von etcd mit HTTPS für Clients starten:

$ etcd --listen-client-urls https://localhost:2379 --advertise-client-urls https://localhost:2379 --cert-file=peer.crt --key-file=peer.key --trusted-ca-file=ca.crt --client-cert-auth

Prüfen, ob der Clientport HTTPS bereitstellt:

# fails
$ ETCDCTL_API=3 etcdctl --endpoints=http://localhost:2379 endpoint status
# works
$ ETCDCTL_API=3 etcdctl --endpoints=https://localhost:2379 --cert=client.crt --key=client.key --cacert=ca.crt endpoint status

Anschließend einen gRPC-Proxy auf localhost:12379 starten, der sich mithilfe der Clientzertifikate mit dem etcd-Endpunkt https://localhost:2379 verbindet:

$ etcd grpc-proxy start --endpoints=https://localhost:2379 --listen-addr localhost:12379 --cert client.crt --key client.key --cacert=ca.crt --insecure-skip-tls-verify &

Abschließend die TLS-Terminierung testen, indem über HTTP ein Schlüssel in den Proxy geschrieben wird:

$ ETCDCTL_API=3 etcdctl --endpoints=http://localhost:12379 put abc def
# OK

Metriken und Zustandsprüfung

Der gRPC-Proxy stellt für die durch --endpoints definierten etcd-Mitglieder die Endpunkte /health und Prometheus /metrics bereit. Alternativ lässt sich mit der Option --metrics-addr eine zusätzliche URL definieren, die sowohl auf /metrics als auch auf /health antwortet.

$ etcd grpc-proxy start \
  --endpoints https://localhost:2379 \
  --metrics-addr https://0.0.0.0:4443 \
  --listen-addr 127.0.0.1:23790 \
  --key client.key \
  --key-file proxy-server.key \
  --cert client.crt \
  --cert-file proxy-server.crt \
  --cacert ca.pem \
  --trusted-ca-file proxy-ca.pem

Bekanntes Problem

Die Hauptschnittstelle des Proxys bedient sowohl HTTP2 als auch HTTP/1.1. Ist der Proxy wie im obigen Beispiel mit TLS eingerichtet, muss bei Anfragen eines Clients wie cURL an die lauschende Schnittstelle ausdrücklich HTTP/1.1 als Protokoll eingestellt werden, damit /metrics oder /health zurückgegeben werden. Die mit --metrics-addr eingerichtete zweite Schnittstelle hat diese Anforderung nicht.

 $ curl --cacert proxy-ca.pem --key proxy-client.key --cert proxy-client.crt https://127.0.0.1:23790/metrics --http1.1

14.11 - Hardwareempfehlungen

Hardwarehinweise für die Verwaltung von etcd-Clustern

etcd läuft für Entwicklung und Tests in der Regel auch mit begrenzten Ressourcen gut; die Entwicklung mit etcd auf einem Laptop oder einer günstigen Cloud-Instanz ist üblich. Für den produktiven Betrieb von etcd-Clustern helfen jedoch einige Hardwarehinweise bei der sachgerechten Verwaltung. Diese Empfehlungen sind keine starren Regeln, sondern ein guter Ausgangspunkt für eine robuste Produktivinstallation. Wie immer sollten Installationen vor dem produktiven Einsatz mit simulierten Arbeitslasten getestet werden.

CPUs

Nur wenige etcd-Installationen benötigen viel CPU-Leistung. Typische Cluster kommen für einen reibungslosen Betrieb mit zwei bis vier Kernen aus. Stark ausgelastete etcd-Installationen, die Tausende von Clients oder Zehntausende von Anfragen pro Sekunde bedienen, sind meist durch die CPU begrenzt, da etcd Anfragen aus dem Arbeitsspeicher bedienen kann. Solche Installationen benötigen gewöhnlich acht bis sechzehn dedizierte Kerne.

Arbeitsspeicher

etcd hat einen vergleichsweise geringen Speicherbedarf, seine Leistung hängt aber dennoch von ausreichend Arbeitsspeicher ab. Ein etcd-Server speichert Schlüssel-Wert-Daten umfassend zwischen und verwendet den größten Teil des übrigen Speichers zur Verwaltung von Watchern. Typischerweise reichen 8GB aus. Für große Installationen mit Tausenden von Watchern und Millionen von Schlüsseln entsprechend 16GB bis 64GB Arbeitsspeicher vorsehen.

Datenträger

Schnelle Datenträger sind der wichtigste Faktor für Leistung und Stabilität einer etcd-Installation.

Ein langsamer Datenträger erhöht die Latenz von etcd-Anfragen und kann die Clusterstabilität beeinträchtigen. Da das Konsensprotokoll von etcd auf der dauerhaften Speicherung von Metadaten in einem Log beruht, muss eine Mehrheit der Clustermitglieder jede Anfrage auf den Datenträger schreiben. Zusätzlich schreibt etcd seinen Zustand schrittweise als Checkpoints auf den Datenträger, um dieses Log kürzen zu können. Dauern diese Schreiboperationen zu lange, können Heartbeats ihr Zeitlimit überschreiten und eine Wahl auslösen, was die Clusterstabilität beeinträchtigt. Ob ein Datenträger für etcd schnell genug ist, lässt sich im Allgemeinen mit einem Benchmarkwerkzeug wie fio ermitteln. Ein Beispiel steht hier .

etcd reagiert sehr empfindlich auf die Schreiblatenz von Datenträgern. Typischerweise sind 50 sequenzielle IOPS erforderlich (z. B. eine Festplatte mit 7200 RPM). Für stark ausgelastete Cluster werden 500 sequenzielle IOPS empfohlen (z. B. eine typische lokale SSD oder ein leistungsfähiges virtualisiertes Blockgerät). Die meisten Cloud-Anbieter veröffentlichen parallele statt sequenzieller IOPS; die veröffentlichten parallelen IOPS können 10x höher als die sequenziellen IOPS sein. Um die tatsächlichen sequenziellen IOPS zu messen, empfiehlt sich ein Datenträger-Benchmarkwerkzeug wie diskbench oder fio .

etcd benötigt nur eine mäßige Datenträgerbandbreite. Eine höhere Bandbreite verkürzt aber die Wiederherstellungszeit, wenn ein ausgefallenes Mitglied zum Cluster aufschließen muss. Typischerweise lassen sich mit 10MB/s 100MB Daten innerhalb von 15 Sekunden wiederherstellen. Für große Cluster werden mindestens 100MB/s empfohlen, um 1GB Daten innerhalb von 15 Sekunden wiederherzustellen.

Für die Speicherung von etcd nach Möglichkeit eine SSD verwenden. Eine SSD bietet gewöhnlich niedrigere und weniger schwankende Schreiblatenzen als eine rotierende Festplatte und verbessert damit Stabilität und Zuverlässigkeit von etcd. Bei rotierenden Festplatten die schnellstmöglichen Modelle wählen (15,000 RPM). RAID 0 ist ebenfalls ein wirksames Mittel, die Datenträgergeschwindigkeit zu erhöhen, sowohl bei Festplatten als auch bei SSDs. Bei mindestens drei Clustermitgliedern sind RAID-Varianten mit Spiegelung und/oder Parität nicht erforderlich; die konsistente Replikation von etcd sorgt bereits für Hochverfügbarkeit.

Netzwerk

etcd-Installationen mit mehreren Mitgliedern profitieren von einem schnellen und zuverlässigen Netzwerk. Da etcd sowohl Konsistenz als auch Partitionstoleranz gewährleisten muss, führt ein unzuverlässiges Netzwerk mit Unterbrechungen durch Partitionen zu schlechter Verfügbarkeit. Niedrige Latenz ermöglicht eine schnelle Kommunikation zwischen etcd-Mitgliedern. Hohe Bandbreite kann die Wiederherstellungszeit eines ausgefallenen Mitglieds verkürzen. Für gängige etcd-Installationen reicht 1GbE aus. Bei großen etcd-Clustern verkürzt ein 10GbE-Netzwerk die mittlere Wiederherstellungszeit.

etcd-Mitglieder nach Möglichkeit innerhalb eines einzigen Rechenzentrums bereitstellen, um zusätzliche Latenz zu vermeiden und die Wahrscheinlichkeit von Netzwerkpartitionen zu verringern. Wird ein separater Ausfallbereich in einem anderen Rechenzentrum benötigt, ein möglichst nahe gelegenes Rechenzentrum wählen. Weitere Informationen zu Installationen über mehrere Rechenzentren hinweg enthält die Dokumentation zur Optimierung .

Beispiele für Hardwarekonfigurationen

Im Folgenden stehen einige beispielhafte Hardwarekonfigurationen für AWS- und GCE-Umgebungen. Wie bereits erwähnt, gilt auch hier: Administratoren sollten eine etcd-Installation vor dem produktiven Einsatz mit einer simulierten Arbeitslast testen.

Diese Konfigurationen setzen voraus, dass die Rechner ausschließlich für etcd vorgesehen sind. Werden darauf neben etcd weitere Anwendungen ausgeführt, können Ressourcenkonflikte entstehen und den Cluster instabil machen.

Kleiner Cluster

Ein kleiner Cluster bedient weniger als 100 Clients und weniger als 200 Anfragen pro Sekunde und speichert höchstens 100MB Daten.

Beispielarbeitslast: ein Kubernetes-Cluster mit 50 Knoten

Anbieter Typ vCPUs Arbeitsspeicher (GB) Maximale parallele IOPS Datenträgerbandbreite (MB/s)
AWS m4.large 2 8 3600 56.25
GCE n1-standard-2 + 50GB PD SSD 2 7.5 1500 25

Mittlerer Cluster

Ein mittlerer Cluster bedient weniger als 500 Clients und weniger als 1,000 Anfragen pro Sekunde und speichert höchstens 500MB Daten.

Beispielarbeitslast: ein Kubernetes-Cluster mit 250 Knoten

Anbieter Typ vCPUs Arbeitsspeicher (GB) Maximale parallele IOPS Datenträgerbandbreite (MB/s)
AWS m4.xlarge 4 16 6000 93.75
GCE n1-standard-4 + 150GB PD SSD 4 15 4500 75

Großer Cluster

Ein großer Cluster bedient weniger als 1,500 Clients und weniger als 10,000 Anfragen pro Sekunde und speichert höchstens 1GB Daten.

Beispielarbeitslast: ein Kubernetes-Cluster mit 1,000 Knoten

Anbieter Typ vCPUs Arbeitsspeicher (GB) Maximale parallele IOPS Datenträgerbandbreite (MB/s)
AWS m4.2xlarge 8 32 8000 125
GCE n1-standard-8 + 250GB PD SSD 8 30 7500 125

Sehr großer Cluster

Ein sehr großer Cluster bedient mehr als 1,500 Clients und mehr als 10,000 Anfragen pro Sekunde und speichert mehr als 1GB Daten.

Beispielarbeitslast: ein Kubernetes-Cluster mit 3,000 Knoten

Anbieter Typ vCPUs Arbeitsspeicher (GB) Maximale parallele IOPS Datenträgerbandbreite (MB/s)
AWS m4.4xlarge 16 64 16,000 250
GCE n1-standard-16 + 500GB PD SSD 16 60 15,000 250

14.12 - Wartung

Anleitung zur regelmäßigen Wartung von etcd-Clustern

Überblick

Ein etcd-Cluster muss regelmäßig gewartet werden, um zuverlässig zu bleiben. Je nach Anforderungen der etcd-Anwendung lässt sich diese Wartung gewöhnlich automatisieren und ohne Ausfallzeiten oder erhebliche Leistungseinbußen durchführen.

Alle Wartungsaufgaben in etcd dienen der Verwaltung der Speicherressourcen, die der etcd-Schlüsselraum belegt. Speicherplatzkontingente sichern gegen eine unzureichende Begrenzung der Schlüsselraumgröße ab: Wird der Speicherplatz eines etcd-Mitglieds knapp, löst ein Kontingent clusterweite Alarme aus, die das System in einen Wartungsmodus mit eingeschränktem Funktionsumfang versetzen. Damit weiterhin Platz für Schreibzugriffe auf den Schlüsselraum vorhanden ist, muss dessen Historie kompaktiert werden. Der Speicherplatz selbst kann durch Defragmentierung der etcd-Mitglieder zurückgewonnen werden. Regelmäßige Snapshot-Backups des Zustands eines etcd-Mitglieds ermöglichen schließlich die Wiederherstellung nach unbeabsichtigtem logischem Datenverlust oder nach Datenbeschädigungen durch Bedienfehler.

Aufbewahrung des Raft-Logs

etcd --snapshot-count legt fest, wie viele angewendete Raft-Einträge vor der Kompaktierung im Arbeitsspeicher gehalten werden. Sobald --snapshot-count erreicht ist, speichert der Server zunächst die Snapshot-Daten dauerhaft auf dem Datenträger und entfernt anschließend alte Einträge. Fordert ein langsamer Follower Logs vor einem kompaktierten Index an, sendet der Leader den Snapshot und zwingt den Follower damit, seinen Zustand zu überschreiben.

Ein höherer Wert für --snapshot-count hält bis zum Snapshot mehr Raft-Einträge im Arbeitsspeicher und verursacht damit eine wiederkehrend höhere Speichernutzung . Da der Leader die neuesten Raft-Einträge länger aufbewahrt, hat ein langsamer Follower mehr Zeit, vor dem nächsten Snapshot des Leaders aufzuschließen. --snapshot-count stellt somit einen Kompromiss zwischen höherem Speicherbedarf und besserer Verfügbarkeit langsamer Follower dar.

In v3.2 wurde der Standardwert von --snapshot-count von 10,000 auf 100,000 geändert . In v3.7.0 beträgt der Standardwert 10,000.

Werte von --snapshot-count über 100,000 können den Schreibdurchsatz beeinträchtigen. Eine größere Anzahl von Objekten im Arbeitsspeicher kann die Markierungsphase des Go-GC, runtime.scanobject , verlangsamen; eine seltene Speicherfreigabe verlangsamt außerdem die Speicherzuweisung. Die Leistung hängt von Arbeitslast und Systemumgebung ab. Generell beeinträchtigt eine zu häufige Kompaktierung jedoch Clusterverfügbarkeit und Schreibdurchsatz. Eine zu seltene Kompaktierung ist ebenfalls schädlich, da sie den Garbage Collector von Go zu stark belastet. Weitere Untersuchungsergebnisse bietet Leistungsaspekte von etcd und Raft verstehen .

Kompaktierung der Historie: Schlüssel-Wert-Datenbank der v3-API

Da etcd eine genaue Historie seines Schlüsselraums führt, sollte diese regelmäßig kompaktiert werden, um Leistungseinbußen und letztlich eine Erschöpfung des Speicherplatzes zu vermeiden. Die Kompaktierung der Schlüsselraumhistorie entfernt alle Informationen zu Schlüsseln, die vor einer bestimmten Revision des Schlüsselraums ersetzt wurden. Der von diesen Schlüsseln belegte Platz steht danach für weitere Schreibzugriffe auf den Schlüsselraum zur Verfügung.

Der Schlüsselraum lässt sich automatisch mit der zeitfensterbasierten Aufbewahrungsrichtlinie von etcd oder manuell mit etcdctl kompaktieren. etcdctl ermöglicht eine genaue Steuerung der Kompaktierung; die automatische Kompaktierung eignet sich für Anwendungen, die die Schlüsselhistorie nur für einen bestimmten Zeitraum benötigen.

Eine mit etcdctl ausgelöste Kompaktierung funktioniert wie folgt:

# compact up to revision 3
$ etcdctl compact 3

Revisionen vor der Kompaktierungsrevision sind danach nicht mehr zugänglich:

$ etcdctl get --rev=2 somekey
Error:  rpc error: code = 11 desc = etcdserver: mvcc: required revision has been compacted

Automatische Kompaktierung

etcd lässt sich mit den Optionen --auto-compaction-mode und --auto-compaction-retention so konfigurieren, dass es den Schlüsselraum automatisch kompaktiert. Es gibt zwei Kompaktierungsmodi: periodic (Standard) und revision.

Periodische Kompaktierung

Die periodische Kompaktierung bewahrt ein zeitbasiertes Fenster der Schlüsselraumhistorie auf:

# keep one hour of history
$ etcd --auto-compaction-retention=1h

Der Aufbewahrungswert legt fest, wie viel Historie erhalten bleibt. Ein Datensatz wird erst ungefähr diese Zeitspanne nach seiner Erstellung kompaktiert. Dadurch können langsame Watcher innerhalb des Aufbewahrungsfensters noch aufschließen.

Ist die Aufbewahrungsdauer größer als 1 Stunde, kompaktiert etcd stündlich und behält dabei das vollständige Aufbewahrungsfenster bei. Beträgt die Aufbewahrungsdauer 1 Stunde oder weniger, erfolgt die Kompaktierung im Abstand dieser Dauer.

Bei --auto-compaction-retention=10h wartet etcd beispielsweise 10 Stunden bis zur ersten Kompaktierung und kompaktiert danach stündlich:

0hr  (rev = 1)
1hr  (rev = 10)
...
8hr  (rev = 80)
9hr  (rev = 90)
10hr (rev = 100, Compact(1))
11hr (rev = 110, Compact(10))
...

Die empfohlenen Werte hängen vom Anwendungsfall ab:

  • Häufige Aktualisierungen derselben Schlüssel: ein kurzer Zeitraum wie 1h oder 30m
  • Seltene Aktualisierungen: ein längerer Zeitraum wie 24h, 48h oder 72h
  • Allgemeiner Standardwert: 10h

Revisionsbasierte Kompaktierung

Die revisionsbasierte Kompaktierung bewahrt eine feste Anzahl von Revisionen auf:

# keep 1000 revisions
$ etcd --auto-compaction-mode=revision --auto-compaction-retention=1000

etcd prüft alle 5 Minuten und kompaktiert bei "latest revision" - 1000. Ist die neueste Revision beispielsweise 30000, erfolgt die Kompaktierung bei Revision 29000.

Defragmentierung

Nach der Kompaktierung des Schlüsselraums kann die Backend-Datenbank intern fragmentiert sein. Interne Fragmentierung bezeichnet Platz, den das Backend wiederverwenden kann, der aber weiterhin Speicherplatz belegt. Beim Kompaktieren alter Revisionen entstehen Lücken in der Backend-Datenbank, wodurch etcd intern fragmentiert wird. Fragmentierter Platz steht etcd zur Verfügung, dem Dateisystem des Hosts jedoch nicht. Das Löschen von Anwendungsdaten gibt also keinen Speicherplatz auf dem Datenträger frei.

Die Defragmentierung gibt diesen Speicherplatz an das Dateisystem zurück. Sie wird für jedes Mitglied einzeln ausgelöst, um clusterweite Latenzspitzen vermeiden zu können.

Ein etcd-Mitglied mit dem Befehl etcdctl defrag defragmentieren:

$ etcdctl defrag
Finished defragmenting etcd member[127.0.0.1:2379]
Warnung

Die Defragmentierung eines laufenden Mitglieds blockiert während des Neuaufbaus seines Zustands alle Lese- und Schreibzugriffe auf Daten.

Warnung

Eine Defragmentierungsanfrage wird nicht im Cluster repliziert, sondern nur auf dem lokalen Knoten ausgeführt. Alle Mitglieder mit der Option --endpoints angeben oder mit --cluster alle Clustermitglieder automatisch ermitteln lassen.

Defragmentierung für alle Endpunkte des Clusters ausführen, zu dem der Standardendpunkt gehört:

$ etcdctl defrag --cluster
Finished defragmenting etcd member[http://127.0.0.1:2379]
Finished defragmenting etcd member[http://127.0.0.1:22379]
Finished defragmenting etcd member[http://127.0.0.1:32379]

Um ein etcd-Datenverzeichnis direkt zu defragmentieren, während etcd nicht läuft, folgenden Befehl verwenden:

etcdutl defrag --data-dir <path-to-etcd-data-dir>

Speicherplatzkontingent

Das Speicherplatzkontingent in etcd stellt einen zuverlässigen Clusterbetrieb sicher. Ohne ein solches Kontingent kann etcd bei einem übermäßig großen Schlüsselraum an Leistung verlieren oder schlicht den gesamten Speicherplatz aufbrauchen, was zu unvorhersehbarem Clusterverhalten führt. Überschreitet die Backend-Datenbank des Schlüsselraums eines beliebigen Mitglieds das Kontingent, löst etcd einen clusterweiten Alarm aus. Dieser versetzt den Cluster in einen Wartungsmodus, der nur das Lesen und Löschen von Schlüsseln erlaubt. Erst nachdem genügend Platz im Schlüsselraum freigegeben, die Backend-Datenbank defragmentiert und der Kontingentalarm aufgehoben wurde, kann der Cluster den normalen Betrieb wieder aufnehmen.

Standardmäßig verwendet etcd ein konservatives Speicherplatzkontingent, das für die meisten Anwendungen geeignet ist. Es lässt sich jedoch auf der Befehlszeile in Bytes konfigurieren:

# set a very small 16 MiB quota
$ etcd --quota-backend-bytes=$((16*1024*1024))

Das Kontingent lässt sich mit einer Schleife ausschöpfen:

# fill keyspace
$ while [ 1 ]; do dd if=/dev/urandom bs=1024 count=1024  | ETCDCTL_API=3 etcdctl put key  || break; done
...
Error:  rpc error: code = 8 desc = etcdserver: mvcc: database space exceeded
# confirm quota space is exceeded
$ ETCDCTL_API=3 etcdctl --write-out=table endpoint status
+----------------+------------------+-----------+---------+-----------+-----------+------------+
|    ENDPOINT    |        ID        |  VERSION  | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX |
+----------------+------------------+-----------+---------+-----------+-----------+------------+
| 127.0.0.1:2379 | bf9071f4639c75cc | 2.3.0+git | 18 MB   | true      |         2 |       3332 |
+----------------+------------------+-----------+---------+-----------+-----------+------------+
# confirm alarm is raised
$ ETCDCTL_API=3 etcdctl alarm list
memberID:13803658152347727308 alarm:NOSPACE

Durch das Entfernen überflüssiger Daten aus dem Schlüsselraum und die Defragmentierung der Backend-Datenbank liegt der Cluster wieder innerhalb des Kontingents:

# get current revision
$ rev=$(ETCDCTL_API=3 etcdctl --endpoints=:2379 endpoint status --write-out="json" | egrep -o '"revision":[0-9]*' | egrep -o '[0-9].*')
# compact away all old revisions
$ ETCDCTL_API=3 etcdctl compact $rev
compacted revision 1516
# defragment away excessive space
$ ETCDCTL_API=3 etcdctl defrag
Finished defragmenting etcd member[127.0.0.1:2379]
# disarm alarm
$ ETCDCTL_API=3 etcdctl alarm disarm
memberID:13803658152347727308 alarm:NOSPACE
# test puts are allowed again
$ ETCDCTL_API=3 etcdctl put newkey 123
OK

Die Metrik etcd_mvcc_db_total_size_in_use_in_bytes zeigt die tatsächliche Datenbankbelegung nach einer Kompaktierung der Historie. etcd_debugging_mvcc_db_total_size_in_bytes zeigt dagegen die Datenbankgröße einschließlich freien Platzes, der noch auf Defragmentierung wartet. Letztere steigt nur, wenn Erstere nahe an ihr liegt. Nähern sich beide Metriken dem Kontingent, ist daher eine Kompaktierung der Historie erforderlich, um das Auslösen des Speicherplatzkontingents zu vermeiden.

Ab v3.4 heißt etcd_debugging_mvcc_db_total_size_in_bytes nun etcd_mvcc_db_total_size_in_bytes.

Warnung

Eine Put/Txn/LeaseGrant-Anfrage kann den Fehler ErrGRPCNoSpace zurückgeben, obwohl der Schreibzugriff im Backend erfolgreich ist. etcd prüft das Speicherplatzkontingent sowohl auf der API-Schicht als auch auf der internen Apply-Schicht. Die Apply-Schicht löst lediglich den Alarm NOSPACE aus, ohne die weitere Ausführung der Transaktion zu blockieren.

Snapshot-Backup

Regelmäßige Snapshots des etcd-Clusters dienen als dauerhaftes Backup des etcd-Schlüsselraums. Durch regelmäßige Snapshots der Backend-Datenbank eines etcd-Mitglieds lässt sich ein etcd-Cluster auf einen Zeitpunkt mit einem nachweislich intakten Zustand zurücksetzen.

Ein Snapshot wird mit etcdctl erstellt:

$ etcdctl snapshot save backup.db
$ etcdutl --write-out=table snapshot status backup.db
+----------+----------+------------+------------+
|   HASH   | REVISION | TOTAL KEYS | TOTAL SIZE |
+----------+----------+------------+------------+
| fe01cf57 |       10 |          7 | 2.1 MB     |
+----------+----------+------------+------------+

14.13 - etcd überwachen

Systemzustand überwachen und Clusterfehler in etcd untersuchen

Jeder etcd-Server stellt über HTTP-Endpunkte auf seinem Clientport lokale Überwachungsinformationen bereit. Diese Daten helfen sowohl bei der Prüfung des Systemzustands als auch bei der Fehlersuche im Cluster.

Debug-Endpunkt

Ist --log-level=debug gesetzt, stellt der etcd-Server auf seinem Clientport unter dem Pfad /debug Informationen zur Fehlersuche bereit. --log-level=debug mit Bedacht setzen, da dies die Leistung beeinträchtigt und eine ausführliche Protokollierung verursacht.

Der Endpunkt /debug/pprof ist der standardmäßige Profiling-Endpunkt der Go-Laufzeitumgebung. Damit lassen sich CPU-, Heap-, Mutex- und Goroutine-Nutzung untersuchen. Im folgenden Beispiel ermittelt go tool pprof die 10 Funktionen, in denen etcd die meiste Zeit verbringt:

$ go tool pprof http://localhost:2379/debug/pprof/profile
Fetching profile from http://localhost:2379/debug/pprof/profile
Please wait... (30s)
Saved profile in /home/etcd/pprof/pprof.etcd.localhost:2379.samples.cpu.001.pb.gz
Entering interactive mode (type "help" for commands)
(pprof) top10
310ms of 480ms total (64.58%)
Showing top 10 nodes out of 157 (cum >= 10ms)
    flat  flat%   sum%        cum   cum%
   130ms 27.08% 27.08%      130ms 27.08%  runtime.futex
    70ms 14.58% 41.67%       70ms 14.58%  syscall.Syscall
    20ms  4.17% 45.83%       20ms  4.17%  github.com/coreos/etcd/vendor/golang.org/x/net/http2/hpack.huffmanDecode
    20ms  4.17% 50.00%       30ms  6.25%  runtime.pcvalue
    20ms  4.17% 54.17%       50ms 10.42%  runtime.schedule
    10ms  2.08% 56.25%       10ms  2.08%  github.com/coreos/etcd/vendor/github.com/coreos/etcd/etcdserver.(*EtcdServer).AuthInfoFromCtx
    10ms  2.08% 58.33%       10ms  2.08%  github.com/coreos/etcd/vendor/github.com/coreos/etcd/etcdserver.(*EtcdServer).Lead
    10ms  2.08% 60.42%       10ms  2.08%  github.com/coreos/etcd/vendor/github.com/coreos/etcd/pkg/wait.(*timeList).Trigger
    10ms  2.08% 62.50%       10ms  2.08%  github.com/coreos/etcd/vendor/github.com/prometheus/client_golang/prometheus.(*MetricVec).hashLabelValues
    10ms  2.08% 64.58%       10ms  2.08%  github.com/coreos/etcd/vendor/golang.org/x/net/http2.(*Framer).WriteHeaders

Der Endpunkt /debug/requests stellt gRPC-Traces und Leistungsstatistiken für einen Webbrowser bereit. Hier ist beispielsweise eine Range-Anfrage für den Schlüssel abc zu sehen:

When	Elapsed (s)
2017/08/18 17:34:51.999317 	0.000244 	/etcdserverpb.KV/Range
17:34:51.999382 	 .    65 	... RPC: from 127.0.0.1:47204 deadline:4.999377747s
17:34:51.999395 	 .    13 	... recv: key:"abc"
17:34:51.999499 	 .   104 	... OK
17:34:51.999535 	 .    36 	... sent: header:<cluster_id:14841639068965178418 member_id:10276657743932975437 revision:15 raft_term:17 > kvs:<key:"abc" create_revision:6 mod_revision:14 version:9 value:"asda" > count:1

Metrikendpunkt

Jeder etcd-Server stellt Metriken unter dem Pfad /metrics auf seinem Clientport sowie optional an den mit --listen-metrics-urls angegebenen Adressen bereit.

Die Metriken lassen sich mit curl abrufen:

$ curl -L http://localhost:2379/metrics | grep -v debugging # ignore unstable debugging metrics

# HELP etcd_disk_backend_commit_duration_seconds The latency distributions of commit called by backend.
# TYPE etcd_disk_backend_commit_duration_seconds histogram
etcd_disk_backend_commit_duration_seconds_bucket{le="0.002"} 72756
etcd_disk_backend_commit_duration_seconds_bucket{le="0.004"} 401587
etcd_disk_backend_commit_duration_seconds_bucket{le="0.008"} 405979
etcd_disk_backend_commit_duration_seconds_bucket{le="0.016"} 406464
...

Health Check

Seit v3.3.0 antworten alle mit --listen-metrics-urls angegebenen Adressen neben /metrics auch auf den Endpunkt /health. Dies ist hilfreich, wenn der Standardendpunkt mit gegenseitiger TLS-Authentifizierung (Clientauthentifizierung) konfiguriert ist, ein Load-Balancer oder Überwachungsdienst aber weiterhin Zugriff auf den Health Check benötigt.

Seit v3.4 gibt es die beiden neuen Endpunkte /livez und /readyz.

  • Der Endpunkt /livez zeigt an, ob der Prozess lebt oder neu gestartet werden muss.
  • Der Endpunkt /readyz zeigt an, ob der Prozess bereit ist, Anfragen zu bedienen.

Die Entwurfsdetails der Endpunkte sind im KEP dokumentiert.

Jeder Endpunkt umfasst mehrere einzelne Health Checks. Mit dem Parameter verbose lassen sich Einzelheiten und Status der Prüfungen ausgeben, beispielsweise:

curl -k http://localhost:2379/readyz?verbose

Die Antwort sieht dann etwa so aus:

[+]data_corruption ok
[+]serializable_read ok
[+]linearizable_read ok
ok

Die HTTP-API unterstützt auch den Ausschluss einzelner Prüfungen, beispielsweise:

curl -k http://localhost:2379/readyz?exclude=data_corruption

Prometheus

Ein Überwachungsdienst mit Prometheus ist der einfachste Weg, die Metriken von etcd zu erfassen und aufzuzeichnen.

Zunächst Prometheus installieren:

PROMETHEUS_VERSION="2.0.0"
wget https://github.com/prometheus/prometheus/releases/download/v$PROMETHEUS_VERSION/prometheus-$PROMETHEUS_VERSION.linux-amd64.tar.gz -O /tmp/prometheus-$PROMETHEUS_VERSION.linux-amd64.tar.gz
tar -xvzf /tmp/prometheus-$PROMETHEUS_VERSION.linux-amd64.tar.gz --directory /tmp/ --strip-components=1
/tmp/prometheus -version

Die Endpunkte des etcd-Clusters als Abrufziele von Prometheus festlegen:

cat > /tmp/test-etcd.yaml <<EOF
global:
  scrape_interval: 10s
scrape_configs:
  - job_name: test-etcd
    static_configs:
    - targets: ['10.240.0.32:2379','10.240.0.33:2379','10.240.0.34:2379']
EOF
cat /tmp/test-etcd.yaml

Den Prometheus-Handler einrichten:

nohup /tmp/prometheus \
    -config.file /tmp/test-etcd.yaml \
    -web.listen-address ":9090" \
    -storage.local.path "test-etcd.data" >> /tmp/test-etcd.log  2>&1 &

Prometheus ruft nun alle 10 Sekunden die Metriken von etcd ab.

Alarmierung

Für etcd-v3-Cluster gibt es einen Satz von Standardalarmen für Prometheus.

Hinweis

Die job-Labels müssen möglicherweise an die jeweiligen Anforderungen angepasst werden. Die Regeln wurden für einen einzelnen Cluster geschrieben; daher werden Labels empfohlen, die für einen Cluster eindeutig sind.

Grafana

Grafana unterstützt Prometheus von Haus aus; dazu einfach eine Prometheus-Datenquelle hinzufügen:

Name:   test-etcd
Type:   Prometheus
Url:    http://localhost:9090
Access: proxy

Anschließend die standardmäßige etcd-Dashboardvorlage importieren und anpassen. Heißt die Prometheus-Datenquelle beispielsweise my-etcd, müssen auch die Werte der datasource-Felder im JSON my-etcd lauten.

Beispieldashboard:

Verteiltes Tracing

In v3.5 wurde etcd um Unterstützung für verteiltes Tracing mit OpenTelemetry erweitert.

Hinweis

In etcd 3.7 die folgenden Tracing-Optionen ohne das frühere Präfix experimental verwenden.

Um verteiltes Tracing zu aktivieren, dem etcd-Server --enable-distributed-tracing=true übergeben. Mit der Option --distributed-tracing-sampling-rate=<number> wird zusätzlich festgelegt, wie viele Stichproben pro Million Spans erfasst werden; die Standardrate ist 0.

Das verteilte Tracing lässt sich konfigurieren, indem der etcd-Server mit folgenden optionalen Optionen gestartet wird:

  • --distributed-tracing-address - (Optional) - “localhost:4317” - Adresse des Tracing-Collectors.

  • --distributed-tracing-service-name - (Optional) - “etcd” - Dienstname für verteiltes Tracing; muss für alle etcd-Instanzen gleich sein.

  • --distributed-tracing-instance-id - (Optional) - Instanz-ID; ihre Angabe ist optional, wird aber dringend empfohlen. Sie muss für jede etcd-Instanz eindeutig sein.

Vor der Aktivierung des verteilten Tracings sicherstellen, dass ein OpenTelemetry-Endpunkt verfügbar ist. Weicht seine Adresse vom Standard ab, sie mit --distributed-tracing-address überschreiben. Da OpenTelemetry auf verschiedene Arten betrieben werden kann, enthält die Collector-Dokumentation weitere Informationen.

Hinweis

Wie jedes Signal zur Beobachtung des Systems verursacht auch diese Funktion zusätzlichen Ressourcenbedarf. Nach unseren ersten Messungen kann die zusätzliche CPU-Last zwischen 2% - 4% liegen.

14.14 - Leistung

Leistung verstehen: Latenz und Durchsatz

Leistung verstehen

etcd bietet eine stabile, dauerhaft hohe Leistung. Zwei Faktoren bestimmen die Leistung: Latenz und Durchsatz. Die Latenz ist die Zeit bis zum Abschluss einer Operation. Der Durchsatz ist die Gesamtzahl der in einem bestimmten Zeitraum abgeschlossenen Operationen. Nimmt etcd gleichzeitige Clientanfragen an, steigt die mittlere Latenz gewöhnlich mit dem Gesamtdurchsatz. In gängigen Cloud-Umgebungen, etwa auf einer standardmäßigen n-4-Instanz bei Google Compute Engine (GCE) oder einem vergleichbaren AWS-Instanztyp, schließt ein etcd-Cluster mit drei Mitgliedern bei geringer Last eine Anfrage in weniger als einer Millisekunde ab und kann bei hoher Last mehr als 30,000 Anfragen pro Sekunde verarbeiten.

etcd verwendet den Raft-Konsensalgorithmus, um Anfragen zwischen Mitgliedern zu replizieren und Einigkeit herzustellen. Die Konsensleistung, insbesondere die Commit-Latenz, wird durch zwei physikalische Grenzen bestimmt: die Latenz der Netzwerk-IO und die Latenz der Datenträger-IO. Die Mindestdauer einer etcd-Anfrage ergibt sich aus der Netzwerkumlaufzeit (Round Trip Time, RTT) zwischen den Mitgliedern zuzüglich der Zeit, die fdatasync benötigt, um die Daten dauerhaft zu speichern. Innerhalb eines Rechenzentrums kann die RTT mehrere Hundert Mikrosekunden betragen. Eine typische RTT innerhalb der USA liegt bei etwa 50ms und kann zwischen Kontinenten bis zu 400ms erreichen. Die typische fdatasync-Latenz einer rotierenden Festplatte liegt bei etwa 10ms, bei SSDs häufig unter 1ms. Um den Durchsatz zu erhöhen, bündelt etcd mehrere Anfragen und übergibt sie gemeinsam an Raft. Diese Bündelung ermöglicht etcd auch bei hoher Last einen hohen Durchsatz.

Weitere Teilsysteme beeinflussen die Gesamtleistung von etcd. Jede serialisierte etcd-Anfrage muss die boltdb-basierte MVCC-Speicherengine durchlaufen, was gewöhnlich einige zehn Mikrosekunden dauert. Regelmäßig erstellt etcd inkrementelle Snapshots der zuletzt angewendeten Anfragen und führt sie mit dem vorherigen Snapshot auf dem Datenträger zusammen. Dieser Vorgang kann eine Latenzspitze verursachen. Auf SSDs ist dies gewöhnlich unproblematisch, auf HDD kann sich die beobachtete Latenz jedoch verdoppeln. Auch laufende Kompaktierungen können die Leistung von etcd beeinflussen. Ihre Auswirkung ist glücklicherweise oft gering, da die Kompaktierung zeitlich gestaffelt erfolgt und so nicht mit regulären Anfragen um Ressourcen konkurriert. Das RPC-System gRPC bietet etcd eine klar definierte, erweiterbare API, verursacht aber auch zusätzliche Latenz, insbesondere bei lokalen Lesezugriffen.

Benchmarks

Die Leistung von etcd lässt sich mit dem enthaltenen CLI-Werkzeug benchmark messen.

Als Grundlage für einige Leistungskennzahlen dient ein etcd-Cluster mit drei Mitgliedern und folgender Hardwarekonfiguration:

  • Google Cloud Compute Engine
  • 3 Rechner mit 8 vCPUs + 16GB Arbeitsspeicher + 50GB SSD
  • 1 Rechner (Client) mit 16 vCPUs + 30GB Arbeitsspeicher + 50GB SSD
  • Ubuntu 17.04
  • etcd 3.2.0, go 1.8.3

Mit dieser Konfiguration erreicht etcd ungefähr folgende Schreibleistung:

Anzahl der Schlüssel Schlüsselgröße in Bytes Wertgröße in Bytes Anzahl der Verbindungen Anzahl der Clients etcd-Zielserver Mittlere Schreib-QPS Mittlere Latenz pro Anfrage Mittlerer Server-RSS
10,000 8 256 1 1 nur Leader 583 1.6ms 48 MB
100,000 8 256 100 1000 nur Leader 44,341 22ms 124MB
100,000 8 256 100 1000 alle Mitglieder 50,104 20ms 126MB

Beispielbefehle:

# write to leader
benchmark --endpoints=${HOST_1} --target-leader --conns=1 --clients=1 \
    put --key-size=8 --sequential-keys --total=10000 --val-size=256
benchmark --endpoints=${HOST_1} --target-leader  --conns=100 --clients=1000 \
    put --key-size=8 --sequential-keys --total=100000 --val-size=256

# write to all members
benchmark --endpoints=${HOST_1},${HOST_2},${HOST_3} --conns=100 --clients=1000 \
    put --key-size=8 --sequential-keys --total=100000 --val-size=256

Linearisierbare Leseanfragen beziehen ein Quorum von Clustermitgliedern in die Konsensbildung ein, um die neuesten Daten abzurufen. Serialisierbare Leseanfragen sind günstiger, da sie von einem beliebigen einzelnen etcd-Mitglied statt von einem Quorum bedient werden; dafür können sie veraltete Daten zurückgeben. etcd erreicht folgende Leseleistung:

Anzahl der Anfragen Schlüsselgröße in Bytes Wertgröße in Bytes Anzahl der Verbindungen Anzahl der Clients Konsistenz Mittlere Lese-QPS Mittlere Latenz pro Anfrage
10,000 8 256 1 1 Linearisierbar 1,353 0.7ms
10,000 8 256 1 1 Serialisierbar 2,909 0.3ms
100,000 8 256 100 1000 Linearisierbar 141,578 5.5ms
100,000 8 256 100 1000 Serialisierbar 185,758 2.2ms

Beispielbefehle:

# Single connection read requests
benchmark --endpoints=${HOST_1},${HOST_2},${HOST_3} --conns=1 --clients=1 \
    range YOUR_KEY --consistency=l --total=10000
benchmark --endpoints=${HOST_1},${HOST_2},${HOST_3} --conns=1 --clients=1 \
    range YOUR_KEY --consistency=s --total=10000

# Many concurrent read requests
benchmark --endpoints=${HOST_1},${HOST_2},${HOST_3} --conns=100 --clients=1000 \
    range YOUR_KEY --consistency=l --total=100000
benchmark --endpoints=${HOST_1},${HOST_2},${HOST_3} --conns=100 --clients=1000 \
    range YOUR_KEY --consistency=s --total=100000

Beim erstmaligen Einrichten eines etcd-Clusters in einer neuen Umgebung wird empfohlen, den Benchmarktest auszuführen, um eine angemessene Leistung sicherzustellen. Latenz und Durchsatz des Clusters können empfindlich auf geringe Unterschiede in der Umgebung reagieren.

14.15 - Entwurf der Laufzeitrekonfiguration

Der Entwurf der etcd-Befehle zur Laufzeitrekonfiguration

Die Laufzeitrekonfiguration gehört zu den schwierigsten und fehleranfälligsten Funktionen eines verteilten Systems, insbesondere eines konsensbasierten Systems wie etcd.

Im Folgenden wird erläutert, wie die Befehle zur Laufzeitrekonfiguration von etcd entworfen wurden und wie wir diese Probleme gelöst haben.

Konfigurationsänderungen in zwei Phasen schützen den Cluster

In etcd muss jede Laufzeitrekonfiguration aus Sicherheitsgründen zwei Phasen durchlaufen. Um beispielsweise ein Mitglied hinzuzufügen, wird zunächst der Cluster über die neue Konfiguration informiert und anschließend das neue Mitglied gestartet.

Phase 1 – Den Cluster über die neue Konfiguration informieren

Um einem etcd-Cluster ein Mitglied hinzuzufügen, wird dies über einen API-Aufruf angefordert. Dies ist die einzige Möglichkeit, ein neues Mitglied zu einem bestehenden Cluster hinzuzufügen. Der API-Aufruf kehrt zurück, sobald sich der Cluster auf die Konfigurationsänderung geeinigt hat.

Phase 2 – Das neue Mitglied starten

Damit das neue etcd-Mitglied dem bestehenden Cluster beitritt, den korrekten Wert für initial-cluster angeben und initial-cluster-state auf existing setzen. Beim Start kontaktiert das Mitglied zunächst den bestehenden Cluster und prüft, ob dessen aktuelle Konfiguration mit der in initial-cluster angegebenen erwarteten Konfiguration übereinstimmt. Sobald das neue Mitglied erfolgreich gestartet ist, hat der Cluster die erwartete Konfiguration erreicht.

Die Aufteilung in zwei getrennte Phasen zwingt Benutzer dazu, Änderungen der Clustermitgliedschaft ausdrücklich vorzunehmen. Tatsächlich verschafft dies mehr Flexibilität und macht die Abläufe leichter nachvollziehbar. Wird beispielsweise versucht, ein neues Mitglied mit derselben ID wie ein bereits vorhandenes Mitglied hinzuzufügen, scheitert die Aktion sofort in der ersten Phase, ohne den laufenden Cluster zu beeinträchtigen. Ein ähnlicher Schutz verhindert, dass neue Mitglieder versehentlich hinzugefügt werden. Versucht ein neues etcd-Mitglied beizutreten, bevor der Cluster die Konfigurationsänderung angenommen hat, wird es vom Cluster nicht akzeptiert.

Ohne den ausdrücklichen Ablauf für Mitgliedschaftsänderungen wäre etcd anfällig für unerwartete Änderungen der Clustermitgliedschaft. Läuft etcd beispielsweise unter einem Init-System wie systemd, würde etcd nach der Entfernung über die Mitgliedschafts-API neu gestartet und beim Start erneut versuchen, dem Cluster beizutreten. Diese unerwartete Schleife würde sich jedes Mal wiederholen, wenn ein Mitglied über die API entfernt wird und systemd etcd nach einem Fehlschlag neu starten soll.

Wir gehen davon aus, dass die Laufzeitrekonfiguration nur selten erforderlich ist. Daher haben wir sie bewusst als ausdrücklichen, benutzergesteuerten Vorgang gestaltet, um die Konfigurationssicherheit zu gewährleisten und den Cluster unter klarer Kontrolle reibungslos zu betreiben.

Dauerhafter Quorumverlust erfordert einen neuen Cluster

Verliert ein Cluster dauerhaft die Mehrheit seiner Mitglieder, muss ein neuer Cluster aus einem alten Datenverzeichnis gestartet werden, um den vorherigen Zustand wiederherzustellen.

Es wäre durchaus möglich, ausgefallene Mitglieder zwangsweise aus dem bestehenden Cluster zu entfernen und ihn so wiederherzustellen. Wir unterstützen dieses Verfahren jedoch nicht, da es die normale Commit-Phase des Konsensverfahrens umgeht und somit unsicher ist. Ist das zu entfernende Mitglied tatsächlich noch aktiv oder wird die Entfernung über verschiedene Mitglieder desselben Clusters erzwungen, entstehen voneinander abweichende Cluster mit derselben clusterID. Dies ist sehr gefährlich und im Nachhinein schwer zu untersuchen oder zu beheben.

Bei einer korrekten Installation ist die Wahrscheinlichkeit eines dauerhaften Mehrheitsverlusts sehr gering. Das Problem ist jedoch schwerwiegend genug, um besondere Vorsorge zu rechtfertigen. Wir empfehlen dringend, vor dem produktiven Einsatz von etcd die Dokumentation zur Disaster Recovery zu lesen und Vorkehrungen für einen dauerhaften Mehrheitsverlust zu treffen.

Den öffentlichen Erkennungsdienst nicht für die Laufzeitrekonfiguration verwenden

Der öffentliche Erkennungsdienst sollte nur zur Initialisierung eines Clusters verwendet werden. Um ein Mitglied zu einem bestehenden Cluster hinzuzufügen, die API zur Laufzeitrekonfiguration verwenden.

Der Erkennungsdienst ist für die Initialisierung eines etcd-Clusters in einer Cloud-Umgebung gedacht, wenn die IP-Adressen aller Mitglieder noch nicht bekannt sind. Nach erfolgreicher Initialisierung sind diese IP-Adressen bekannt. Technisch sollte der Erkennungsdienst dann nicht mehr benötigt werden.

Der öffentliche Erkennungsdienst scheint eine bequeme Möglichkeit zur Laufzeitrekonfiguration zu sein, da er bereits alle Informationen zur Clusterkonfiguration besitzt. Die Abhängigkeit von ihm bringt jedoch Probleme mit sich:

  1. Sie schafft externe Abhängigkeiten über den gesamten Lebenszyklus des Clusters hinweg, nicht nur während der Initialisierung. Bei Netzwerkproblemen zwischen dem Cluster und dem öffentlichen Erkennungsdienst wird der Cluster beeinträchtigt.

  2. Der öffentliche Erkennungsdienst muss über den gesamten Lebenszyklus des Clusters hinweg dessen korrekte Laufzeitkonfiguration abbilden. Er muss Sicherheitsmechanismen gegen unerwünschte Aktionen bereitstellen, was schwierig ist.

  3. Der öffentliche Erkennungsdienst muss Zehntausende von Clusterkonfigurationen aufbewahren. Das Backend unseres öffentlichen Erkennungsdiensts ist für diese Arbeitslast nicht ausgelegt.

Wird ein Erkennungsdienst mit Unterstützung für Laufzeitrekonfiguration benötigt, ist ein eigener privater Dienst die beste Wahl.

14.16 - Laufzeitrekonfiguration

Unterstützung für schrittweise Laufzeitrekonfiguration in etcd

etcd unterstützt die schrittweise Laufzeitrekonfiguration, mit der die Mitgliedschaft im Cluster während des Betriebs geändert werden kann.

Rekonfigurationsanfragen können nur verarbeitet werden, wenn die Mehrheit der Clustermitglieder funktioniert. Für den produktiven Betrieb wird dringend empfohlen, stets mehr als zwei Mitglieder zu verwenden. Das Entfernen eines Mitglieds aus einem Cluster mit zwei Mitgliedern ist unsicher, da auch dessen Mehrheit aus zwei Mitgliedern besteht. Tritt während der Entfernung ein Fehler auf, kann der Cluster möglicherweise nicht mehr weiterarbeiten und einen Neustart nach einem Mehrheitsausfall benötigen.

Weitere Informationen zum Entwurf der Laufzeitrekonfiguration bietet das Dokument zur Laufzeitrekonfiguration .

Anwendungsfälle für die Rekonfiguration

Dieser Abschnitt beschreibt einige häufige Gründe für die Rekonfiguration eines Clusters. Meist bestehen die erforderlichen Schritte aus Kombinationen des Hinzufügens und Entfernens von Mitgliedern. Diese werden weiter unten unter Operationen zur Clusterrekonfiguration erläutert.

Mehrere Rechner austauschen oder aufrüsten

Müssen mehrere Clustermitglieder wegen geplanter Wartungsarbeiten umziehen (Hardwareaufrüstung, Netzwerkunterbrechungen usw.), wird empfohlen, die Mitglieder nacheinander zu ändern.

Der Leader kann sicher entfernt werden; während der anschließenden Wahl gibt es jedoch eine kurze Ausfallzeit. Enthält der Cluster mehr als 50MB v2-Daten, wird empfohlen, das Datenverzeichnis des Mitglieds zu migrieren .

Clustergröße ändern

Eine Vergrößerung des Clusters kann die Fehlertoleranz und die Leseleistung verbessern. Da Clients von jedem Mitglied lesen können, erhöht eine größere Mitgliederzahl den gesamten Durchsatz serialisierbarer Lesezugriffe.

Eine Verkleinerung des Clusters kann die Schreibleistung verbessern, verringert aber seine Ausfallsicherheit. Schreiboperationen werden auf eine Mehrheit der Clustermitglieder repliziert, bevor sie als festgeschrieben gelten. Eine Verkleinerung senkt die erforderliche Mehrheit, sodass jede Schreiboperation schneller festgeschrieben wird.

Einen ausgefallenen Rechner ersetzen

Fällt ein Rechner durch einen Hardwaredefekt, ein beschädigtes Datenverzeichnis oder einen anderen schwerwiegenden Fehler aus, sollte er so schnell wie möglich ersetzt werden. Ausgefallene, aber noch nicht entfernte Rechner wirken sich ungünstig auf das Quorum aus und verringern die Toleranz gegenüber einem weiteren Ausfall.

Um den Rechner zu ersetzen, zunächst nach der Anleitung das Mitglied aus dem Cluster entfernen und anschließend ein neues Mitglied hinzufügen . Enthält der Cluster mehr als 50MB, wird empfohlen, das Datenverzeichnis des ausgefallenen Mitglieds zu migrieren , sofern es noch zugänglich ist.

Cluster nach einem Mehrheitsausfall neu starten

Geht die Mehrheit des Clusters verloren oder haben sich die IP-Adressen aller Knoten geändert, ist für eine sichere Wiederherstellung ein manueller Eingriff erforderlich. Die grundlegenden Schritte umfassen das Erstellen eines neuen Clusters mit den alten Daten , das Erzwingen eines einzelnen Mitglieds als Leader und schließlich das schrittweise Hinzufügen neuer Mitglieder zu diesem Cluster über die Laufzeitkonfiguration.

Cluster nach einem Minderheitsausfall wiederherstellen

Geht ein einzelnes Mitglied verloren, entspricht dies dem Ersetzen eines ausgefallenen Rechners. Die Schritte stehen unter Einen ausgefallenen Rechner ersetzen .

Operationen zur Clusterrekonfiguration

Für diese Anwendungsfälle lassen sich die jeweils erforderlichen Operationen wie folgt beschreiben.

Vor jeder Änderung muss eine einfache Mehrheit (ein Quorum) der etcd-Mitglieder verfügbar sein. Im Wesentlichen gilt dieselbe Anforderung für jede Art von Schreibzugriff auf etcd.

Alle Änderungen am Cluster müssen nacheinander erfolgen:

  • Zum Aktualisieren der peerURLs eines einzelnen Mitglieds eine Aktualisierungsoperation ausführen
  • Zum Ersetzen eines einzelnen intakten Mitglieds das alte Mitglied entfernen und danach ein neues hinzufügen
  • Für eine Erweiterung von 3 auf 5 Mitglieder zwei Hinzufügeoperationen ausführen
  • Für eine Verkleinerung von 5 auf 3 zwei Entfernungsoperationen ausführen

Alle Beispiele verwenden das mit etcd gelieferte Befehlszeilenwerkzeug etcdctl. Um die Mitgliedschaft ohne etcdctl zu ändern, die v3-gRPC-Mitglieder-API verwenden.

Ein Mitglied aktualisieren

Bekannt gegebene Client-URLs aktualisieren

Um die bekannt gegebenen Client-URLs eines Mitglieds zu aktualisieren, dieses einfach mit der aktualisierten Option --advertise-client-urls oder Umgebungsvariablen ETCD_ADVERTISE_CLIENT_URLS neu starten. Das neu gestartete Mitglied veröffentlicht die aktualisierten URLs selbst. Eine falsch aktualisierte Client-URL beeinträchtigt den Zustand des etcd-Clusters nicht.

Bekannt gegebene Peer-URLs aktualisieren

Um die bekannt gegebenen Peer-URLs eines Mitglieds zu aktualisieren, sie zunächst ausdrücklich mit dem member-Befehl ändern und anschließend das Mitglied neu starten. Dieser zusätzliche Schritt ist erforderlich, da Peer-URL-Änderungen die clusterweite Konfiguration ändern und den Zustand des etcd-Clusters beeinflussen können.

Zum Aktualisieren der bekannt gegebenen Peer-URLs zunächst die ID des Zielmitglieds ermitteln. Alle Mitglieder mit etcdctl auflisten:

$ etcdctl member list
6e3bd23ae5f1eae0: name=node2 peerURLs=http://localhost:23802 clientURLs=http://127.0.0.1:23792
924e2e83e93f2560: name=node3 peerURLs=http://localhost:23803 clientURLs=http://127.0.0.1:23793
a8266ecf031671f3: name=node1 peerURLs=http://localhost:23801 clientURLs=http://127.0.0.1:23791

In diesem Beispiel wird update auf die Mitglieds-ID a8266ecf031671f3 angewendet und deren peerURLs-Wert in http://10.0.1.10:2380 geändert:

$ etcdctl member update a8266ecf031671f3 --peer-urls=http://10.0.1.10:2380
Updated member with ID a8266ecf031671f3 in cluster

Ein Mitglied entfernen

Angenommen, die ID des zu entfernenden Mitglieds ist a8266ecf031671f3. Das Mitglied mit dem Befehl remove entfernen:

$ etcdctl member remove a8266ecf031671f3
Removed member a8266ecf031671f3 from cluster

Das Zielmitglied beendet sich daraufhin selbst und protokolliert seine Entfernung:

etcd: this member has been permanently removed from the cluster. Exiting.

Der Leader kann sicher entfernt werden, allerdings ist der Cluster während der Wahl eines neuen Leaders inaktiv. Diese Dauer entspricht normalerweise dem Wahlzeitlimit zuzüglich des Abstimmungsvorgangs.

Ein neues Mitglied hinzufügen

Das Hinzufügen eines Mitglieds erfolgt in zwei Schritten:

  • Das neue Mitglied über die v3-gRPC-Mitglieder-API oder den Befehl etcdctl member add zum Cluster hinzufügen.
  • Das neue Mitglied mit der neuen Clusterkonfiguration starten, einschließlich der aktualisierten Mitgliederliste (vorhandene Mitglieder + neues Mitglied).

etcdctl fügt ein neues Mitglied hinzu, indem dessen Name und bekannt gegebene Peer-URLs angegeben werden:

$ etcdctl member add infra3 --peer-urls=http://10.0.1.13:2380
added member 9bf1b35fc7761a23 to cluster

ETCD_NAME="infra3"
ETCD_INITIAL_CLUSTER="infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380,infra3=http://10.0.1.13:2380"
ETCD_INITIAL_CLUSTER_STATE=existing

etcdctl hat den Cluster über das neue Mitglied informiert und die für dessen erfolgreichen Start benötigten Umgebungsvariablen ausgegeben. Nun den neuen etcd-Prozess mit den passenden Optionen für das neue Mitglied starten:

$ export ETCD_NAME="infra3"
$ export ETCD_INITIAL_CLUSTER="infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380,infra3=http://10.0.1.13:2380"
$ export ETCD_INITIAL_CLUSTER_STATE=existing
$ etcd --listen-client-urls http://10.0.1.13:2379 --advertise-client-urls http://10.0.1.13:2379 --listen-peer-urls http://10.0.1.13:2380 --initial-advertise-peer-urls http://10.0.1.13:2380 --data-dir %data_dir%

Das neue Mitglied läuft als Teil des Clusters und beginnt sofort, zum übrigen Cluster aufzuschließen.

Beim Hinzufügen mehrerer Mitglieder empfiehlt es sich, jeweils ein einzelnes Mitglied zu konfigurieren und seinen korrekten Start zu prüfen, bevor weitere Mitglieder hinzukommen. Wird einem Cluster mit 1 Knoten ein neues Mitglied hinzugefügt, kann der Cluster erst weiterarbeiten, sobald dieses gestartet ist, da er für den Konsens nun zwei Mitglieder als Mehrheit benötigt. Dieses Verhalten tritt nur zwischen der Meldung des neuen Mitglieds durch etcdctl member add und dem erfolgreichen Verbindungsaufbau des neuen zum bestehenden Mitglied auf.

Ein neues Mitglied als Learner hinzufügen

Seit v3.4 unterstützt etcd das Hinzufügen eines neuen Mitglieds als Learner, also als nicht stimmberechtigtes Mitglied. Die Gründe und der Entwurf sind im Entwurfsdokument beschrieben. Um das Hinzufügen sicherer zu machen und die dabei entstehenden Clusterunterbrechungen zu verkürzen, empfiehlt es sich, das neue Mitglied zunächst als Learner hinzuzufügen, bis es aufgeholt hat. Dies lässt sich als Ablauf in drei Schritten beschreiben:

  • Das neue Mitglied über die gRPC-Mitglieder-API oder den Befehl etcdctl member add --learner als Learner hinzufügen.

  • Das neue Mitglied mit der neuen Clusterkonfiguration starten, einschließlich der aktualisierten Mitgliederliste (vorhandene Mitglieder + neues Mitglied). Dieser Schritt ist genau derselbe wie zuvor.

  • Den neu hinzugefügten Learner über die gRPC-Mitglieder-API oder den Befehl etcdctl member promote zu einem stimmberechtigten Mitglied befördern. Der etcd-Server prüft die Beförderungsanfrage, um die Betriebssicherheit zu gewährleisten. Erst wenn sein Raft-Log zum Log des Leaders aufgeholt hat, kann der Learner zum stimmberechtigten Mitglied befördert werden. Hat ein Learner-Mitglied noch nicht zum Raft-Log des Leaders aufgeholt, schlägt die Beförderungsanfrage fehl (Einzelheiten stehen im Abschnitt Fehlerfälle bei der Beförderung eines Mitglieds ). In diesem Fall sollte gewartet und die Anfrage später wiederholt werden.

In v3.4 begrenzt der etcd-Server die Zahl der Learner im Cluster auf einen. Dadurch soll vor allem die zusätzliche Last begrenzt werden, die dem Leader durch die Übertragung von Daten an den Learner entsteht.

Mit etcdctl member add und der Option --learner ein neues Mitglied als Learner zum Cluster hinzufügen.

$ etcdctl member add infra3 --peer-urls=http://10.0.1.13:2380 --learner
Member 9bf1b35fc7761a23 added to cluster a7ef944b95711739

ETCD_NAME="infra3"
ETCD_INITIAL_CLUSTER="infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380,infra3=http://10.0.1.13:2380"
ETCD_INITIAL_CLUSTER_STATE=existing

Nachdem der neue etcd-Prozess für das hinzugefügte Learner-Mitglied gestartet wurde, den Learner mit etcdctl member promote zu einem stimmberechtigten Mitglied befördern.

$ etcdctl member promote 9bf1b35fc7761a23
Member 9e29bbaa45d74461 promoted in cluster a7ef944b95711739

Fehlerfälle beim Hinzufügen von Mitgliedern

Im folgenden Fall fehlt ein neuer Host in der Liste der aufgeführten Knoten. Handelt es sich um einen neuen Cluster, muss der Knoten zur Liste der anfänglichen Clustermitglieder hinzugefügt werden.

$ etcd --name infra3 \
  --initial-cluster infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380 \
  --initial-cluster-state existing
etcdserver: assign ids error: the member count is unequal
exit 1

In diesem fehlgeschlagenen Beispiel startet das Mitglied mit einer Adresse (10.0.1.14:2380), die von der registrierten Peer-Adresse (10.0.1.13:2380) abweicht:

$ etcd --name infra4 \
  --initial-cluster infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380,infra4=http://10.0.1.14:2380 \
  --initial-cluster-state existing
etcdserver: assign ids error: unmatched member while checking PeerURLs
exit 1

Startet etcd mit dem Datenverzeichnis eines entfernten Mitglieds, beendet es sich automatisch, sobald es sich mit einem aktiven Clustermitglied verbindet:

$ etcd
etcd: this member has been permanently removed from the cluster. Exiting.
exit 1

Fehlerfälle beim Hinzufügen eines Learner-Mitglieds

Ein Learner kann nicht hinzugefügt werden, wenn der Cluster bereits 1 Learner enthält (v3.4).

$ etcdctl member add infra4 --peer-urls=http://10.0.1.14:2380 --learner
Error: etcdserver: too many learner members in cluster

Fehlerfälle bei der Beförderung eines Learner-Mitglieds

Ein Learner kann nur zu einem stimmberechtigten Mitglied befördert werden, wenn er mit dem Leader synchron ist.

$ etcdctl member promote 9bf1b35fc7761a23
Error: etcdserver: can only promote a learner member which is in sync with leader

Die Beförderung eines Mitglieds, das kein Learner ist, schlägt fehl.

$ etcdctl member promote 9bf1b35fc7761a23
Error: etcdserver: can only promote a learner member

Die Beförderung eines Mitglieds, das im Cluster nicht existiert, schlägt fehl.

$ etcdctl member promote 12345abcde
Error: etcdserver: member not found

Strenge Rekonfigurationsprüfung (-strict-reconfig-check)

Wie oben beschrieben, empfiehlt es sich, neue Mitglieder einzeln zu konfigurieren und ihren korrekten Start zu prüfen, bevor weitere hinzukommen. Dieses schrittweise Vorgehen ist sehr wichtig: Ist ein neues Mitglied falsch konfiguriert, etwa mit falschen Peer-URLs, kann der Cluster sein Quorum verlieren. Der Quorumverlust entsteht, weil das neue Mitglied bei der Quorumberechnung mitgezählt wird, selbst wenn die übrigen Mitglieder es nicht erreichen können. Auch Verbindungsprobleme oder betriebliche Probleme können zum Quorumverlust führen.

Um dieses Problem zu vermeiden, bietet etcd die Option -strict-reconfig-check. Wird sie an etcd übergeben, lehnt etcd Rekonfigurationsanfragen ab, wenn die Anzahl gestarteter Mitglieder nach der Änderung kleiner als das Quorum des neu konfigurierten Clusters wäre.

Diese Option ist standardmäßig aktiviert.

14.17 - Unterstützte Plattformen

etcd-Unterstützung für gängige Architekturen und Betriebssysteme

Unterstützungsstufen

etcd läuft auf verschiedenen Plattformen. Die gewährten Garantien hängen jedoch von der Unterstützungsstufe der jeweiligen Plattform ab:

  • Stufe 1: vollständig von den etcd-Maintainern unterstützt; etcd besteht garantiert alle Tests einschließlich Funktions- und Robustheitstests.
  • Stufe 2: etcd besteht garantiert Integrations- und Ende-zu-Ende-Tests, aber nicht unbedingt Funktions- oder Robustheitstests.
  • Stufe 3: etcd lässt sich garantiert bauen, wird möglicherweise nur wenig oder gar nicht getestet und sollte daher als instabil betrachtet werden.

Aktuelle Unterstützung

Die folgende Tabelle führt die derzeit unterstützten Plattformen und ihre jeweilige etcd-Unterstützungsstufe auf:

Architektur Betriebssystem Unterstützungsstufe Maintainer
AMD64 Linux 1 etcd-Maintainer
ARM64 Linux 1 etcd-Maintainer
AMD64 Darwin 3
ARM64 Darwin 3
AMD64 Windows 3
ppc64le Linux 3
s390x Linux 3

Nicht aufgeführte Plattformen werden nicht unterstützt.

Eine neue Plattform unterstützen

Möchten Sie als „offizieller“ Maintainer einer neuen Plattform zu etcd beitragen? Neben der Zusage, die Plattform zu unterstützen, müssen Sie eine kontinuierliche Integration (CI) für etcd einrichten, die abhängig von der Unterstützungsstufe die folgenden Anforderungen erfüllt:

Kontinuierliche Integration für etcd Stufe 1 Stufe 2 Stufe 3
Build erfolgreich ✓ ✓ ✓
Unittests bestanden ✓ ✓
Integrations- und Ende-zu-Ende-Tests bestanden ✓ ✓
Robustheitstests bestanden ✓

Ein Beispiel zur Einrichtung einer CI der Stufe 2 für ARM64 bietet etcd PR #12928 .

Nicht unterstützte Plattformen

Um den unbeabsichtigten Betrieb eines etcd-Servers auf einer nicht unterstützten Plattform zu vermeiden, gibt etcd eine Warnung aus und beendet sich sofort, sofern die Umgebungsvariable ETCD_UNSUPPORTED_ARCH nicht auf die Zielarchitektur gesetzt ist.

Warnung

32-Bit-Systeme Auf 32-Bit-Systemen hat etcd aufgrund eines Fehlers in der Go-Laufzeitumgebung bekannte Probleme. Weitere Informationen bieten das Go-Issue #599 und der Fehlerhinweis zum Paket atomic .

14.18 - Versionierung

Versionierungsunterstützung in etcd

Dieses Dokument beschreibt die vom etcd-Projekt unterstützten Versionen.

Dienstversionierung und unterstützte Versionen

etcd-Versionen werden als x.y.z angegeben. Dabei ist x die Hauptversion, y die Nebenversion und z die Patchversion, entsprechend der Terminologie der semantischen Versionierung . Neue Nebenversionen können der API zusätzliche Funktionen hinzufügen.

Das etcd-Projekt pflegt Release-Branches für die aktuelle und die vorherige Version. Ist beispielsweise v3.5 die aktuelle Version, wird v3.4 unterstützt. Mit der Veröffentlichung von v3.6 endet die Unterstützung für v3.4.

Geeignete Fehlerbehebungen, einschließlich Sicherheitskorrekturen, können abhängig von Schweregrad und Machbarkeit auf diese beiden Release-Branches zurückportiert werden. Bei Bedarf werden daraus Patchversionen veröffentlicht.

Diese Entscheidung treffen die Maintainer des Projekts.

Die Version eines laufenden etcd-Clusters lässt sich mit etcdctl prüfen:

etcdctl --endpoints=127.0.0.1:2379 endpoint status

API-Versionierung

Die Antworten der v3-API sollten sich nach der Veröffentlichung von 3.0.0 nicht ändern; im Laufe der Zeit werden jedoch neue Funktionen hinzugefügt.

14.19 - Datenbeschädigung

Datenbeschädigung und Recovery in etcd

etcd verfügt über eine integrierte automatische Erkennung von Datenbeschädigungen, damit die Zustände der Mitglieder nicht voneinander abweichen.

Hinweis

In etcd 3.7 die nachfolgenden Funktionsschalter und Optionen für Zeitintervalle verwenden. Die früheren experimentellen Optionen zur Prüfung auf Datenbeschädigungen wurden entfernt; siehe Konfigurationsoptionen .

Erkennung von Datenbeschädigungen aktivieren

Datenbeschädigungen lassen sich mit folgenden Prüfungen erkennen:

  • Anfangsprüfung, aktiviert mit der Option --feature-gates=InitialCorruptCheck=true.
  • Regelmäßige Prüfung folgender Hashwerte:
    • Hashwert der kompaktierten Revision, aktiviert mit der Option --feature-gates=CompactHashCheck=true.
    • Hashwert der neuesten Revision, aktiviert mit der Option --corrupt-check-time.

Die Anfangsprüfung erfolgt während der Initialisierung des etcd-Mitglieds. Das Mitglied vergleicht seinen persistenten Zustand mit dem der anderen Mitglieder und beendet sich bei einer Abweichung.

Beide regelmäßigen Prüfungen werden in einem bereits laufenden Cluster vom Leader ausgeführt. Der Leader vergleicht seinen persistenten Zustand mit dem der anderen Mitglieder und löst bei einer Abweichung einen CORRUPT ALARM aus. Beide Prüfungen dienen demselben Zweck. Es lohnt sich jedoch, beide zu aktivieren, um Leistung und Erkennungszeit gegeneinander abzuwägen.

  • Prüfung des Hashwerts der kompaktierten Revision – erfordert regelmäßige Kompaktierung, verursacht minimale Leistungseinbußen und kommt mit langsamen Followern zurecht.
  • Prüfung des Hashwerts der neuesten Revision – verursacht hohe Leistungseinbußen und kommt weder mit langsamen Followern noch mit häufigen Kompaktierungen zurecht.

Hashwert der kompaktierten Revision prüfen

Bei Aktivierung mit der Option --feature-gates=CompactHashCheck=true wird die Prüfung einmal pro Minute ausgeführt. Dies lässt sich mit der Option --compact-hash-check-time in folgendem Format anpassen: 1m – jede Minute, 1h – jede Stunde. Diese Prüfung erweitert die Kompaktierung um die Berechnung einer Prüfsumme, die zwischen Clustermitgliedern verglichen werden kann. Sie erfordert keinen zusätzlichen Datenbankscan und ist dadurch sehr kostengünstig, setzt aber eine regelmäßige Kompaktierung im Cluster voraus.

Hashwert der neuesten Revision prüfen

Die Aktivierung erfolgt mit der Option --corrupt-check-time; dabei muss ein Ausführungsintervall in folgendem Format angegeben werden: 1m – jede Minute, 1h – jede Stunde. Wegen der hohen Leistungseinbußen wird ein Intervall von einigen Stunden empfohlen. Für die Prüfung muss der gesamte etcd-Inhalt bei der angegebenen Revision gescannt werden, um eine Prüfsumme zu berechnen.

Ein Mitglied mit beschädigten Daten wiederherstellen

Es gibt drei Möglichkeiten, ein Mitglied mit beschädigten Daten wiederherzustellen:

  • Persistenten Zustand des Mitglieds löschen
  • Mitglied ersetzen
  • Gesamten Cluster wiederherstellen

Nach der Wiederherstellung des Mitglieds kann der CORRUPT ALARM aufgehoben werden.

Persistenten Zustand des Mitglieds löschen

Der Zustand eines Mitglieds lässt sich wie folgt löschen:

  1. Die etcd-Instanz stoppen.
  2. Ein Backup des etcd-Datenverzeichnisses erstellen.
  3. Das Unterverzeichnis snap aus dem etcd-Datenverzeichnis verschieben.
  4. etcd mit --initial-cluster-state=existing und den in --initial-cluster aufgeführten Clustermitgliedern starten.

Das etcd-Mitglied sollte daraufhin einen aktuellen Snapshot vom Leader herunterladen.

Mitglied ersetzen

Ein Mitglied lässt sich wie folgt ersetzen:

  1. Die etcd-Instanz stoppen.
  2. Ein Backup des etcd-Datenverzeichnisses erstellen.
  3. Das Datenverzeichnis entfernen.
  4. Das Mitglied durch Ausführen von etcdctl member remove aus dem Cluster entfernen.
  5. Es durch Ausführen von etcdctl member add wieder hinzufügen
  6. etcd mit --initial-cluster-state=existing und den in --initial-cluster aufgeführten Clustermitgliedern starten.

Gesamten Cluster wiederherstellen

Der Cluster lässt sich wiederherstellen, indem ein Snapshot des aktuellen Leaders gespeichert und auf allen Mitgliedern wiederhergestellt wird. etcdctl snapshot save gegen den Leader ausführen und dem Verfahren zur Wiederherstellung eines Clusters folgen.

15 - Benchmarks

Leistungsmessungen für etcd

Benchmarks

etcd-Benchmarks werden regelmäßig veröffentlicht und im Folgenden für jede Version dokumentiert:

Benchmarks zum Speicherverbrauch

Hier wird der erwartete Speicherverbrauch in verschiedenen Szenarien erfasst.

15.1 - Benchmark zum Speicherverbrauch der Speicherschicht

Leistungsmessungen für die etcd-Speicherschicht (Index im Arbeitsspeicher und Seitencache)

Zwei Komponenten der etcd-Speicherschicht beanspruchen physischen Speicher. Der etcd-Prozess legt einen Index im Arbeitsspeicher an, um Schlüssel schneller nachzuschlagen. Der vom Betriebssystem verwaltete Seitencache des Prozesses hält kürzlich vom Datenträger gelesene Daten zur schnellen Wiederverwendung vor.

Der Index im Arbeitsspeicher enthält alle Schlüssel in einer B-Baum -Datenstruktur, zusammen mit Zeigern auf die Daten (die Werte) auf dem Datenträger. Jeder Schlüssel im B-Baum kann mehrere Zeiger enthalten, die auf verschiedene Versionen seiner Werte verweisen. Der theoretische Speicherverbrauch des Index lässt sich daher mit folgender Formel näherungsweise berechnen:

N * (c1 + avg_key_size) + N * (avg_versions_of_key) * (c2 + size_of_pointer)

Dabei ist c1 der Zusatzaufwand für Schlüsselmetadaten und c2 der Zusatzaufwand für Versionsmetadaten.

Die Grafik zeigt den detaillierten Aufbau des B-Baum-Index im Arbeitsspeicher.



                                In mem index

                               +------------+
                               | key || ... |
  +--------------+             |     ||     |
  |              |             +------------+
  |              |             | v1  || ... |
  |   disk    <----------------|     ||     | Tree Node
  |              |             +------------+
  |              |             | v2  || ... |
  |           <----------------+     ||     |
  |              |             +------------+
  +--------------+       +-----+    |   |   |
                         |     |    |   |   |
                         |     +------------+
                         |
                         |
                         ^
                      ------+
                      | ... |
                      |     |
                      +-----+
                      | ... | Tree Node
                      |     |
                      +-----+
                      | ... |
                      |     |
                      ------+

Der Seitencache wird vom Betriebssystem verwaltet und in diesem Dokument nicht näher behandelt.

Testumgebung

etcd-Version

GCE-Rechnertyp n1-standard-2

  • 7.5 GB Arbeitsspeicher
  • 2x CPUs

Speicherverbrauch des Index im Arbeitsspeicher

Dieser Test misst ausschließlich den Speicherverbrauch des Index im Arbeitsspeicher. Ziel ist, die oben genannten Werte c1 und c2 zu bestimmen und die feste Grenze des Speicherverbrauchs der Speicherschicht zu verstehen.

Wir berechnen den Speicherverbrauch mit der Go-Funktion runtime.ReadMemStats. Dazu ermitteln wir die Differenz der insgesamt zugewiesenen Bytes vor und nach dem Erstellen des Index. Dies bildet den Speicherverbrauch des Index selbst nicht exakt ab, zeigt aber das ungefähre Verbrauchsmuster.

N Versionen Schlüsselgröße Speicherverbrauch
100K 1 64bytes 22MB
100K 5 64bytes 39MB
1M 1 64bytes 218MB
1M 5 64bytes 432MB
100K 1 256bytes 41MB
100K 5 256bytes 65MB
1M 1 256bytes 409MB
1M 5 256bytes 506MB

Aus den Ergebnissen lassen sich c1=120bytes und c2=30bytes berechnen. Da c1 und c2 die einzigen Unbekannten in der Formel sind, reichen zwei Datensätze zu ihrer Berechnung aus. Die Werte c1=120bytes und c2=30bytes sind die Mittelwerte der 4 berechneten Wertepaarungen für c1 und c2. Bei kleinen Schlüssel-Wert-Paaren ist der Zusatzaufwand für Schlüsselmetadaten mit 50% weiterhin beträchtlich. Gegenüber dem alten Speicher mit mindestens 1000% Zusatzaufwand ist dies jedoch eine erhebliche Verbesserung.

Gesamter Speicherverbrauch

Der gesamte Speicherverbrauch erfasst, wie viel RSS etcd mit der Speicherschicht beansprucht. Die Größe der Werte sollte den gesamten Speicherverbrauch von etcd nur wenig beeinflussen, da die Werte auf dem Datenträger liegen und nur häufig verwendete Werte im Arbeitsspeicher verbleiben, verwaltet vom Seitencache des Betriebssystems.

N Versionen Schlüsselgröße Wertgröße Speicherverbrauch
100K 1 64bytes 256bytes 40MB
100K 5 64bytes 256bytes 89MB
1M 1 64bytes 256bytes 470MB
1M 5 64bytes 256bytes 880MB
100K 1 64bytes 1KB 102MB
100K 5 64bytes 1KB 164MB
1M 1 64bytes 1KB 587MB
1M 5 64bytes 1KB 836MB

Die Ergebnisse zeigen, dass die Größe der Werte den Speicherverbrauch nicht wesentlich beeinflusst. Er steigt geringfügig, weil der Seitencache des Betriebssystems mehr Daten vorhält.

15.2 - Benchmark zum Speicherverbrauch von Watches

Leistungsmessungen für etcd-Watcher
Hinweis

Die Watch-Funktionen werden aktiv weiterentwickelt; ihr Speicherverbrauch kann sich dabei ändern. Wir erwarten nicht, dass er die unten angegebenen Werte wesentlich übersteigt.

Ein wesentliches Ziel von etcd ist die Unterstützung sehr vieler Watcher mit einer außerordentlich großen Zahl von Watch-Registrierungen. Angestrebt werden O(10k) Clients, O(100K) Watch-Streams (O(10) Streams pro Client) und insgesamt O(10M) Watch-Registrierungen (O(100) pro Stream). Der Speicherverbrauch der einzelnen Watch-Registrierungen macht den größten Teil des gesamten Speicherverbrauchs von etcd aus und steht deshalb im Mittelpunkt der aktuellen und künftigen Optimierungen.

Drei zusammengehörige Komponenten der Watch-Funktion von etcd beanspruchen physischen Speicher: jede grpc.Conn, jeder Watch-Stream und jede einzelne Watch-Registrierung. grpc.Conn verwaltet die tatsächliche TCP-Verbindung und weitere gRPC-Verbindungszustände. Jede grpc.Conn beansprucht O(10kb) Speicher und kann mehrere Watch-Streams haben.

Jeder Watch-Stream ist eine eigenständige HTTP2-Verbindung, die weitere O(10kb) Speicher beansprucht. Mehrere Watch-Registrierungen können sich einen Watch-Stream teilen.

Eine Watch-Registrierung ist die eigentliche Struktur, die Änderungen im Schlüssel-Wert-Speicher verfolgt. Jede Registrierung sollte nur < O(1kb) beanspruchen.

                                          +-------+
                                          | watch |
                              +---------> | foo   |
                              |           +-------+
                       +------+-----+
                       |   stream   |
      +--------------> |            |
      |                +------+-----+     +-------+
      |                       |           | watch |
      |                       +---------> | bar   |
+-----+------+                            +-------+
|            |         +------------+
|   conn     +-------> |   stream   |
|            |         |            |
+-----+------+         +------------+
      |
      |
      |
      |                +------------+
      +--------------> |   stream   |
                       |            |
                       +------------+

Der theoretische Speicherverbrauch von Watch lässt sich mit folgender Formel näherungsweise berechnen: memory = c1 * number_of_conn + c2 * avg_number_of_stream_per_conn + c3 * avg_number_of_watch_stream

Testumgebung

etcd-Version

GCE-Rechnertyp n1-standard-2

  • 7.5 GB Arbeitsspeicher
  • 2x CPUs

Gesamter Speicherverbrauch

Der gesamte Speicherverbrauch erfasst, wie viel RSS etcd mit den Client-Watchern beansprucht. Obwohl das Ergebnis um bis zu 10% schwanken kann, ist es aussagekräftig: Ziel ist, den ungefähren Speicherverbrauch und das Muster der Speicherzuweisungen zu verstehen.

Aus dem Benchmark-Ergebnis lassen sich näherungsweise c1 = 17kb, c2 = 18kb und c3 = 350bytes berechnen. Jede zusätzliche Clientverbindung beansprucht also 17kb Speicher, jeder zusätzliche Stream 18kb und jede weitere Watch-Registrierung nur 350bytes. Ein einzelner etcd-Server kann im Normalfall Millionen von Watch-Registrierungen mit wenigen GB Arbeitsspeicher verwalten.

Clients Streams pro Client Watch-Registrierungen pro Stream Watch-Registrierungen insgesamt Speicherverbrauch
1k 1 1 1k 50MB
2k 1 1 2k 90MB
5k 1 1 5k 200MB
1k 10 1 10k 217MB
2k 10 1 20k 417MB
5k 10 1 50k 980MB
1k 50 1 50k 1001MB
2k 50 1 100k 1960MB
5k 50 1 250k 4700MB
1k 50 10 500k 1171MB
2k 50 10 1M 2371MB
5k 50 10 2.5M 5710MB
1k 50 100 5M 2380MB
2k 50 100 10M 4672MB
5k 50 100 25M OOM

15.3 - Benchmarks für etcd v3

Leistungsmessungen für etcd v3

Physische Rechner

GCE-Rechnertyp n1-highcpu-2

  • 1x dedizierte lokale SSD, unter /var/lib/etcd eingebunden
  • 1x dedizierter langsamer Datenträger für das Betriebssystem
  • 1.8 GB Arbeitsspeicher
  • 2x CPUs
  • etcd-Version 2.2.0

etcd-Cluster

1 etcd-Mitglied im v3-Demomodus

Testverfahren

Das Benchmarkwerkzeug für etcd v3 verwenden.

Leistung

Einen einzelnen Schlüssel lesen

Schlüsselgröße in Bytes Anzahl der Clients Lese-QPS 90. Latenzperzentil (ms)
256 1 2716 0.4
256 64 16623 6.1
256 256 16622 21.7

Die Leistung ist nahezu gleich wie mit einem leeren Server-Handler.

Einen einzelnen Schlüssel nach dem Schreiben lesen

Schlüsselgröße in Bytes Anzahl der Clients Lese-QPS 90. Latenzperzentil (ms)
256 1 2269 0.5
256 64 13582 8.6
256 256 13262 47.5

Mit einem leeren Server-Handler beeinflusst ein einzelner put-Vorgang die Leistung nicht. Der Leistungsrückgang dürfte daher durch das Speicherpaket verursacht werden.

15.4 - Benchmarks für etcd v2.2.0-rc-memory

Leistungsmessungen für etcd v2.2.0-rc-memory

Physischer Rechner

GCE-Rechnertyp n1-standard-2

  • 1x dedizierte lokale SSD, unter /var/lib/etcd eingebunden
  • 1x dedizierter langsamer Datenträger für das Betriebssystem
  • 7.5 GB Arbeitsspeicher
  • 2x CPUs

etcd

etcd Version: 2.2.0-rc.0+git
Git SHA: 103cb5c
Go Version: go1.5
Go OS/Arch: linux/amd64

Testverfahren

Einen etcd-Cluster mit 3 Mitgliedern starten, von denen jedes 2 Kerne verwendet.

Schlüsselnamen sind stets 64 Bytes lang, was einer angemessenen durchschnittlichen Schlüssellänge entspricht.

Maximaler Speicherverbrauch

  • etcd kann den maximalen Speicherverbrauch erreichen, wenn ein Follower ausgefallen ist und der Leader fortlaufend Snapshots sendet.
  • max RSS ist der höchste in 3 Durchläufen gemessene Speicherverbrauch.
Wertgröße in Bytes Schlüsselanzahl Datenmenge(MB) max. RSS(MB) Verhältnis max. RSS/Datenmenge auf dem Leader
128 50000 6 433 72x
128 100000 12 659 54x
128 200000 24 1466 61x
1024 50000 48 1253 26x
1024 100000 96 2344 24x
1024 200000 192 4361 22x

Schwellenwert für die Datenmenge

  • Wenn etcd den Schwellenwert für die Datenmenge erreicht, kann es leicht zu einer Leader-Wahl kommen, und ein Teil der Vorschläge kann verworfen werden.
  • In den meisten Fällen sollte der etcd-Cluster reibungslos arbeiten, solange er den Schwellenwert nicht erreicht. Arbeitet er wegen unzureichender Ressourcen nicht zuverlässig, die Datenmenge reduzieren.
Wertgröße in Bytes Begrenzung der Schlüsselanzahl Empfohlener Schwellenwert für die Datenmenge(MB) Verbrauchter RSS(MB)
128 400K 48 2400
1024 300K 292 6500

15.5 - Benchmarks für etcd v2.2.0-rc

Leistungsmessungen für etcd v2.2.0-rc

Physischer Rechner

GCE-Rechnertyp n1-highcpu-2

  • 1x dedizierte lokale SSD, unter /var/lib/etcd eingebunden
  • 1x dedizierter langsamer Datenträger für das Betriebssystem
  • 1.8 GB Arbeitsspeicher
  • 2x CPUs

etcd-Cluster

3 Mitglieder mit etcd 2.2.0-rc, jeweils auf einem eigenen Rechner.

Versionsdetails:

etcd Version: 2.2.0-alpha.1+git
Git SHA: 59a5a7e
Go Version: go1.4.2
Go OS/Arch: linux/amd64

Außerdem bilden wir aus 3 Mitgliedern mit etcd 2.1.0 im Alpha-Stadium einen Cluster, um die Ausgangsleistung zu ermitteln. Der verwendete etcd-Commit ist c7146bd5 , derselbe wie im etcd-2.1-Benchmark .

Testverfahren

Einen weiteren Rechner einrichten und mit dem HTTP-Benchmarkwerkzeug hey Anfragen an jedes etcd-Mitglied senden. Eine ausführliche Anleitung enthält der Leitfaden zur Benchmark-Entwicklung .

Leistung

Einen einzelnen Schlüssel lesen

Schlüsselgröße in Bytes Anzahl der Clients etcd-Zielserver Lese-QPS 90. Latenzperzentil (ms)
64 1 nur Leader 2804 (-5%) 0.4 (+0%)
64 64 nur Leader 17816 (+0%) 5.7 (-6%)
64 256 nur Leader 18667 (-6%) 20.4 (+2%)
256 1 nur Leader 2181 (-15%) 0.5 (+25%)
256 64 nur Leader 17435 (-7%) 6.0 (+9%)
256 256 nur Leader 18180 (-8%) 21.3 (+3%)
64 64 alle Server 46965 (-4%) 2.1 (+0%)
64 256 alle Server 55286 (-6%) 7.4 (+6%)
256 64 alle Server 46603 (-6%) 2.1 (+5%)
256 256 alle Server 55291 (-6%) 7.3 (+4%)

Einen einzelnen Schlüssel schreiben

Schlüsselgröße in Bytes Anzahl der Clients etcd-Zielserver Schreib-QPS 90. Latenzperzentil (ms)
64 1 nur Leader 76 (+22%) 19.4 (-15%)
64 64 nur Leader 2461 (+45%) 31.8 (-32%)
64 256 nur Leader 4275 (+1%) 69.6 (-10%)
256 1 nur Leader 64 (+20%) 16.7 (-30%)
256 64 nur Leader 2385 (+30%) 31.5 (-19%)
256 256 nur Leader 4353 (-3%) 74.0 (+9%)
64 64 alle Server 2005 (+81%) 49.8 (-55%)
64 256 alle Server 4868 (+35%) 81.5 (-40%)
256 64 alle Server 1925 (+72%) 47.7 (-59%)
256 256 alle Server 4975 (+36%) 70.3 (-36%)

Erklärung der Leistungsänderungen

  • Die Lese-QPS sinken in den meisten Szenarien um 5~8%. Der Grund ist, dass etcd für jede Speicheroperation Speichermetriken erfasst. Diese sind für Überwachung und Fehlersuche wichtig, weshalb der Rückgang vertretbar ist.

  • Die Schreib-QPS an den Leader steigen um 20~30%. Dies liegt daran, dass wir die Raft-Hauptschleife von der Schleife zum Anwenden der Einträge entkoppeln, sodass sie sich nicht gegenseitig blockieren.

  • Die Schreib-QPS an alle Server steigen um 30~80%, weil Follower den neuesten Commit-Index früher erhalten und Vorschläge schneller festschreiben können.

15.6 - Benchmarks für etcd v2.2.0

Leistungsmessungen für etcd v2.2.0

Physische Rechner

GCE-Rechnertyp n1-highcpu-2

  • 1x dedizierte lokale SSD, als etcd-Datenverzeichnis eingebunden
  • 1x dedizierter langsamer Datenträger für das Betriebssystem
  • 1.8 GB Arbeitsspeicher
  • 2x CPUs

etcd-Cluster

3 etcd-2.2.0-Mitglieder, jeweils auf einem eigenen Rechner.

Versionsdetails:

etcd Version: 2.2.0
Git SHA: e4561dd
Go Version: go1.5
Go OS/Arch: linux/amd64

Testverfahren

Einen weiteren Rechner außerhalb des etcd-Clusters einrichten und das HTTP-Benchmarkwerkzeug hey mit einem Patch zur Wiederverwendung von Verbindungen ausführen, um Anfragen an jedes Clustermitglied zu senden. Die Benchmark-Anleitung enthält den Patch und die Schritte zum Reproduzieren unserer Vorgehensweise.

Die Leistung wird aus den Ergebnissen von 100 Benchmark-Durchläufen berechnet.

Leistung

Leseleistung für einen einzelnen Schlüssel

Schlüsselgröße in Bytes Anzahl der Clients etcd-Zielserver Durchschnitt der Lese-QPS Standardabweichung der Lese-QPS Durchschnitt des 90. Latenzperzentils (ms) Standardabweichung der Latenz
64 1 nur Leader 2303 200 0.49 0.06
64 64 nur Leader 15048 685 7.60 0.46
64 256 nur Leader 14508 434 29.76 1.05
256 1 nur Leader 2162 214 0.52 0.06
256 64 nur Leader 14789 792 7.69 0.48
256 256 nur Leader 14424 512 29.92 1.42
64 64 alle Server 45752 2048 2.47 0.14
64 256 alle Server 46592 1273 10.14 0.59
256 64 alle Server 45332 1847 2.48 0.12
256 256 alle Server 46485 1340 10.18 0.74

Schreibleistung für einen einzelnen Schlüssel

Schlüsselgröße in Bytes Anzahl der Clients etcd-Zielserver Durchschnitt der Schreib-QPS Standardabweichung der Schreib-QPS Durchschnitt des 90. Latenzperzentils (ms) Standardabweichung der Latenz
64 1 nur Leader 55 4 24.51 13.26
64 64 nur Leader 2139 125 35.23 3.40
64 256 nur Leader 4581 581 70.53 10.22
256 1 nur Leader 56 4 22.37 4.33
256 64 nur Leader 2052 151 36.83 4.20
256 256 nur Leader 4442 560 71.59 10.03
64 64 alle Server 1625 85 58.51 5.14
64 256 alle Server 4461 298 89.47 36.48
256 64 alle Server 1599 94 60.11 6.43
256 256 alle Server 4315 193 88.98 7.01

Leistungsänderungen

  • Da etcd jetzt für jeden API-Aufruf Metriken erfasst, scheinen die Lese-QPS in den meisten Szenarien geringfügig zu sinken. Angesichts der umfangreichen Informationen für Überwachung und Fehlersuche wurde dieser minimale Leistungsverlust als vertretbar eingeschätzt.

  • Die Schreib-QPS an Cluster-Leader scheinen leicht gestiegen zu sein. Ursache ist die Entkopplung der Hauptschleife von den Schleifen zum Anwenden der Einträge in der Raft-Logik von etcd. Dadurch entfallen mehrere gegenseitige Blockierungen.

  • Die Schreib-QPS an alle Mitglieder scheinen erheblich gestiegen zu sein, weil Follower den neuesten Commit-Index jetzt früher erhalten und Vorschläge schneller festschreiben.

15.7 - Benchmarks für etcd v2.1.0

Leistungsmessungen für etcd v2.1.0

Physische Rechner

GCE-Rechnertyp n1-highcpu-2

  • 1x dedizierte lokale SSD, unter /var/lib/etcd eingebunden
  • 1x dedizierter langsamer Datenträger für das Betriebssystem
  • 1.8 GB Arbeitsspeicher
  • 2x CPUs
  • etcd-Version 2.1.0 alpha

etcd-Cluster

3 etcd-Mitglieder, jeweils auf einem eigenen Rechner

Testverfahren

Einen weiteren Rechner einrichten und mit dem HTTP-Benchmarkwerkzeug hey Anfragen an jedes etcd-Mitglied senden. Eine ausführliche Anleitung enthält der Leitfaden zur Benchmark-Entwicklung .

Leistung

Einen einzelnen Schlüssel lesen

Schlüsselgröße in Bytes Anzahl der Clients etcd-Zielserver Lese-QPS 90. Latenzperzentil (ms)
64 1 nur Leader 1534 0.7
64 64 nur Leader 10125 9.1
64 256 nur Leader 13892 27.1
256 1 nur Leader 1530 0.8
256 64 nur Leader 10106 10.1
256 256 nur Leader 14667 27.0
64 64 alle Server 24200 3.9
64 256 alle Server 33300 11.8
256 64 alle Server 24800 3.9
256 256 alle Server 33000 11.5

Einen einzelnen Schlüssel schreiben

Schlüsselgröße in Bytes Anzahl der Clients etcd-Zielserver Schreib-QPS 90. Latenzperzentil (ms)
64 1 nur Leader 60 21.4
64 64 nur Leader 1742 46.8
64 256 nur Leader 3982 90.5
256 1 nur Leader 58 20.3
256 64 nur Leader 1770 47.8
256 256 nur Leader 4157 105.3
64 64 alle Server 1028 123.4
64 256 alle Server 3260 123.8
256 64 alle Server 1033 121.5
256 256 alle Server 3061 119.3

16 - Downgrades

Downgrades von etcd-Clustern und -Anwendungen

16.1 - Downgrades von etcd-Clustern und -Anwendungen

Dokumentationsübersicht zu Downgrades von etcd-Clustern und -Anwendungen

Dieser Abschnitt enthält Dokumente speziell zu Downgrades von etcd-Clustern und -Anwendungen.

Downgrade eines etcd-v3.x-Clusters

16.2 - Downgrade von etcd v3.7 auf v3.6

Verfahren, Checklisten und Hinweise zum Downgrade von etcd v3.7 auf v3.6

Im Allgemeinen kann das Downgrade von etcd v3.7 auf v3.6 als schrittweises Downgrade ohne Ausfallzeit erfolgen:

  • Die etcd-v3.7-Prozesse nacheinander stoppen und durch etcd-v3.6-Prozesse ersetzen.
  • Nach dem Aktivieren des Downgrades stehen dem Cluster die neuen Funktionen von v3.7 nicht mehr zur Verfügung.

Lesen Sie zur Vorbereitung den Rest dieses Leitfadens, bevor Sie mit dem Downgrade beginnen .

Checklisten für das Downgrade

Wichtige Unterschiede zwischen v3.7 und v3.6:

Unterschiede bei Flags

v3.7 führt keine neuen Flags ein. Ein v3.6-Prozess akzeptiert daher jedes Flag einer v3.7-Konfiguration, und beim Downgrade sind keine Konfigurationsänderungen erforderlich.

Hinweis

Der Vergleich basiert auf den Versionen v3.7.0-rc.0 und v3.6.13. Die tatsächlichen Unterschiede hängen von Ihrer Patch-Version ab; prüfen Sie sie zunächst mit diff <(etcd-3.7/bin/etcd -h | grep \\-\\-) <(etcd-3.6/bin/etcd -h | grep \\-\\-).

Die veralteten --experimental-*-Flags, die in v3.7 entfernt wurden, sind in v3.6 noch vorhanden. Fügen Sie sie nach dem Downgrade jedoch nicht wieder hinzu; verwenden Sie ihre nicht experimentellen Gegenstücke oder --feature-gates-Einträge, die in beiden Versionen funktionieren.

Unterschiede bei Prometheus-Metriken

# metrics not available in v3.6
-etcd_server_request_duration_seconds
-etcd_debugging_server_watch_send_loop_control_stream_duration_seconds
-etcd_debugging_server_watch_send_loop_progress_duration_seconds
-etcd_debugging_server_watch_send_loop_watch_stream_duration_seconds
-etcd_debugging_server_watch_send_loop_watch_stream_duration_per_event_seconds

Checklisten für das Server-Downgrade

Downgrade-Voraussetzungen

Damit das schrittweise Downgrade reibungslos verläuft, muss der laufende Cluster fehlerfrei sein. Prüfen Sie den Zustand des Clusters mit dem Befehl etcdctl endpoint health, bevor Sie fortfahren.

Vorbereitung

Testen Sie vor einem etcd-Downgrade immer die von etcd abhängigen Dienste in einer Staging-Umgebung, bevor Sie das Downgrade in der Produktionsumgebung durchführen.

Laden Sie vor Beginn das Snapshot-Backup herunter . Falls beim Downgrade etwas schiefgeht, können Sie mit diesem Backup ein Rollback auf die bestehende etcd-Version durchführen.

Laden Sie vor Beginn das neueste Release von etcd v3.6 herunter.

Gemischte Versionen

Während des Downgrades unterstützt ein etcd-Cluster Mitglieder mit gemischten etcd-Versionen und verwendet das Protokoll der niedrigsten gemeinsamen Version. Der Cluster gilt als heruntergestuft, sobald das Downgrade mit etcdctl downgrade enable 3.6 aktiviert wurde. Intern wird die Gesamtversion des Clusters auf die Zielversion des Downgrades gesetzt, die die gemeldete Version und die unterstützten Funktionen bestimmt.

Rollback

Erstellen Sie vor dem Downgrade Ihres etcd-Clusters ein Snapshot-Backup des Clusters und laden Sie es herunter . Mit diesem Snapshot lässt sich der Cluster bei Bedarf in seinen Zustand vor dem Downgrade zurückversetzen. Falls während des Downgrades Probleme auftreten, sollten Benutzer zunächst deren Ursache ermitteln und beheben.

Wenn das Downgrade nach Ausführung von etcdctl downgrade enable begonnen hat und sich der Cluster noch in einem Zustand mit gemischten Versionen befindet, also mindestens ein Mitglied weiterhin v3.7 verwendet, können Benutzer das laufende Downgrade durch Ausführen von etcdctl downgrade cancel abbrechen und alle heruntergestuften Mitglieder mit den ursprünglichen v3.7-Binärdateien neu starten.

Sobald alle Mitglieder auf v3.6 heruntergestuft wurden, gilt das Downgrade des Clusters als vollständig abgeschlossen. Wenn Benutzer danach zur ursprünglichen Version zurückkehren möchten, sollten sie dem offiziellen Upgrade-Leitfaden folgen, um Konsistenz zu gewährleisten und Datenbeschädigungen zu vermeiden.

Downgrade-Verfahren

Dieses Beispiel zeigt das Downgrade eines etcd-v3.7-Clusters mit 3 Mitgliedern, der auf einem lokalen Rechner läuft. Die folgende Ausgabe stammt aus einem tatsächlichen Durchlauf mit etcd v3.7.0-rc.0 und etcd v3.6.13 auf einem einzelnen Host mit drei Loopback-Ports; der Cluster war kurz zuvor von v3.6.13 aktualisiert worden.

Schritt 1: Downgrade-Voraussetzungen prüfen

Ist der Cluster fehlerfrei und läuft er mit v3.7.x?

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint health
<<COMMENT
localhost:2379 is healthy: successfully committed proposal: took = 1.052416ms
localhost:32379 is healthy: successfully committed proposal: took = 1.11625ms
localhost:22379 is healthy: successfully committed proposal: took = 1.114291ms
COMMENT

curl http://localhost:2379/version
<<COMMENT
{"etcdserver":"3.7.0-rc.0","etcdcluster":"3.7.0","storage":"3.7.0"}
COMMENT

curl http://localhost:22379/version
<<COMMENT
{"etcdserver":"3.7.0-rc.0","etcdcluster":"3.7.0","storage":"3.7.0"}
COMMENT

curl http://localhost:32379/version
<<COMMENT
{"etcdserver":"3.7.0-rc.0","etcdcluster":"3.7.0","storage":"3.7.0"}
COMMENT

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint status -w=table
<<COMMENT
+-----------------+------------------+------------+-----------------+---------+--------+-----------------------+--------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
|    ENDPOINT     |        ID        |  VERSION   | STORAGE VERSION | DB SIZE | IN USE | PERCENTAGE NOT IN USE | QUOTA  | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS | DOWNGRADE TARGET VERSION | DOWNGRADE ENABLED |
+-----------------+------------------+------------+-----------------+---------+--------+-----------------------+--------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
|  localhost:2379 | 7339c4e5e833c029 | 3.7.0-rc.0 |           3.7.0 |   98 kB |  98 kB |                    0% | 2.1 GB |      true |      false |         5 |         20 |                 20 |        |                          |             false |
| localhost:22379 | 729934363faa4a24 | 3.7.0-rc.0 |           3.7.0 |   98 kB |  98 kB |                    0% | 2.1 GB |     false |      false |         5 |         20 |                 20 |        |                          |             false |
| localhost:32379 |  b548c2511513015 | 3.7.0-rc.0 |           3.7.0 |   98 kB |  98 kB |                    0% | 2.1 GB |     false |      false |         5 |         20 |                 20 |        |                          |             false |
+-----------------+------------------+------------+-----------------+---------+--------+-----------------------+--------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
COMMENT

Schritt 2: Snapshot-Backup vom Leader herunterladen

Laden Sie das Snapshot-Backup herunter , um das Downgrade bei Problemen rückgängig machen zu können:

etcdctl --endpoints=localhost:2379 snapshot save backup.db
<<COMMENT
{"level":"info","ts":"2026-07-02T06:48:11.091982+0300","caller":"snapshot/v3_snapshot.go:83","msg":"created temporary db file","path":"backup.db.part"}
{"level":"info","ts":"2026-07-02T06:48:11.092253+0300","logger":"client","caller":"v3/maintenance.go:236","msg":"opened snapshot stream; downloading"}
{"level":"info","ts":"2026-07-02T06:48:11.099884+0300","caller":"snapshot/v3_snapshot.go:96","msg":"fetching snapshot","endpoint":"localhost:2379"}
{"level":"info","ts":"2026-07-02T06:48:11.100394+0300","logger":"client","caller":"v3/maintenance.go:302","msg":"completed snapshot read; closing"}
{"level":"info","ts":"2026-07-02T06:48:11.103116+0300","caller":"snapshot/v3_snapshot.go:111","msg":"fetched snapshot","endpoint":"localhost:2379","size":"98 kB","took":"10.9815ms","etcd-version":"3.7.0"}
{"level":"info","ts":"2026-07-02T06:48:11.103296+0300","caller":"snapshot/v3_snapshot.go:121","msg":"saved","path":"backup.db"}
Snapshot saved at backup.db
Server version 3.7.0
COMMENT

Schritt 3: Zielversion des Downgrades validieren

Validieren Sie die Zielversion des Downgrades, bevor Sie das Downgrade aktivieren:

  • Wir unterstützen nur Downgrades um jeweils eine Nebenversion. Ein Downgrade von v3.7 auf v3.5 ist beispielsweise nicht zulässig.
  • Fahren Sie erst mit dem nächsten Schritt fort, wenn die Validierung erfolgreich war.
etcdctl downgrade validate 3.6
<<COMMENT
Downgrade validate success, cluster version 3.7
COMMENT

Schritt 4: Downgrade aktivieren

etcdctl downgrade enable 3.6
<<COMMENT
Downgrade enable success, cluster version 3.7
COMMENT

Nach dem Aktivieren des Downgrades beginnt der Cluster, das Protokoll von v3.6 zu verwenden, der Zielversion des Downgrades. Außerdem migriert etcd das Schema automatisch auf die Zielversion des Downgrades, was normalerweise sehr schnell geschieht. Prüfen Sie den Endpunktstatus und bestätigen Sie, dass die Speicherversion aller Server auf v3.6 migriert wurde, bevor Sie mit dem nächsten Schritt fortfahren.

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint status -w=table
<<COMMENT
+-----------------+------------------+------------+-----------------+---------+--------+-----------------------+--------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
|    ENDPOINT     |        ID        |  VERSION   | STORAGE VERSION | DB SIZE | IN USE | PERCENTAGE NOT IN USE | QUOTA  | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS | DOWNGRADE TARGET VERSION | DOWNGRADE ENABLED |
+-----------------+------------------+------------+-----------------+---------+--------+-----------------------+--------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
|  localhost:2379 | 7339c4e5e833c029 | 3.7.0-rc.0 |           3.6.0 |   98 kB |  98 kB |                    0% | 2.1 GB |      true |      false |         5 |         22 |                 22 |        |                    3.6.0 |              true |
| localhost:22379 | 729934363faa4a24 | 3.7.0-rc.0 |           3.6.0 |   98 kB |  98 kB |                    0% | 2.1 GB |     false |      false |         5 |         22 |                 22 |        |                    3.6.0 |              true |
| localhost:32379 |  b548c2511513015 | 3.7.0-rc.0 |           3.6.0 |   98 kB |  98 kB |                    0% | 2.1 GB |     false |      false |         5 |         22 |                 22 |        |                    3.6.0 |              true |
+-----------------+------------------+------------+-----------------+---------+--------+-----------------------+--------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
COMMENT
Hinweis

Sobald das Downgrade aktiviert wurde, verwendet der Cluster weiterhin das Protokoll von v3.6, auch wenn auf allen Servern noch die v3.7-Binärdatei läuft, sofern das Downgrade nicht mit etcdctl downgrade cancel abgebrochen wird.

Schritt 5: Einen bestehenden etcd-Server stoppen

Prüfen Sie vor dem Stoppen des Servers, ob er der Leader ist. Wir empfehlen, den Leader zuletzt herunterzustufen. Wenn der zu stoppende Server der Leader ist, können Sie einen Teil der Ausfallzeit vermeiden, indem Sie vor dem Stoppen dieses Servers mit move-leader die Führungsrolle auf einen anderen Server übertragen.

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 move-leader 729934363faa4a24
<<COMMENT
Leadership transferred from 7339c4e5e833c029 to 729934363faa4a24
COMMENT

Wenn ein etcd-Prozess gestoppt wird, protokollieren die anderen Cluster-Mitglieder erwartete Fehler. Dies ist normal, da die Verbindung zu einem Cluster-Mitglied (vorübergehend) unterbrochen wurde:

{"level":"warn","ts":"2026-07-02T06:48:14.518460+0300","caller":"rafthttp/stream.go:227","msg":"lost TCP streaming connection with remote peer","stream-writer-type":"stream Message","local-member-id":"7339c4e5e833c029","remote-peer-id":"729934363faa4a24"}
{"level":"warn","ts":"2026-07-02T06:48:15.913169+0300","caller":"etcdserver/cluster_util.go:261","msg":"failed to reach the peer URL","address":"http://localhost:22380/version","remote-member-id":"729934363faa4a24","error":"Get \"http://localhost:22380/version\": dial tcp [::1]:22380: connect: connection refused"}
{"level":"warn","ts":"2026-07-02T06:48:15.913364+0300","caller":"etcdserver/cluster_util.go:162","msg":"failed to get version","remote-member-id":"729934363faa4a24","error":"Get \"http://localhost:22380/version\": dial tcp [::1]:22380: connect: connection refused"}
{"level":"warn","ts":"2026-07-02T06:48:16.856521+0300","caller":"version/monitor.go:212","msg":"remotes server has mismatching etcd version","remote-member-id":"b548c2511513015","current-server-version":"3.7.0","target-version":"3.6.0"}

Schritt 6: Den etcd-Server mit derselben Konfiguration neu starten

Starten Sie den etcd-Server mit derselben Konfiguration, aber mit der etcd-v3.6-Binärdatei neu.

-etcd-3.7/bin/etcd --name s2 \
+etcd-3.6/bin/etcd --name s2 \
  --data-dir /tmp/etcd/s2 \
  --listen-client-urls http://localhost:22379 \
  --advertise-client-urls http://localhost:22379 \
  --listen-peer-urls http://localhost:22380 \
  --initial-advertise-peer-urls http://localhost:22380 \
  --initial-cluster s1=http://localhost:2380,s2=http://localhost:22380,s3=http://localhost:32380 \
  --initial-cluster-token tkn \
  --initial-cluster-state existing

Prüfen Sie, ob jedes Mitglied und anschließend der gesamte Cluster mit der etcd-v3.6-Binärdatei wieder fehlerfrei ist:

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint status -w=table
<<COMMENT
+-----------------+------------------+------------+-----------------+---------+--------+-----------------------+--------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
|    ENDPOINT     |        ID        |  VERSION   | STORAGE VERSION | DB SIZE | IN USE | PERCENTAGE NOT IN USE | QUOTA  | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS | DOWNGRADE TARGET VERSION | DOWNGRADE ENABLED |
+-----------------+------------------+------------+-----------------+---------+--------+-----------------------+--------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
|  localhost:2379 | 7339c4e5e833c029 | 3.7.0-rc.0 |           3.6.0 |   98 kB |  98 kB |                    0% | 2.1 GB |      true |      false |         5 |         23 |                 23 |        |                    3.6.0 |              true |
| localhost:22379 | 729934363faa4a24 |     3.6.13 |           3.6.0 |   98 kB |  98 kB |                    0% | 2.1 GB |     false |      false |         5 |         23 |                 23 |        |                    3.6.0 |              true |
| localhost:32379 |  b548c2511513015 | 3.7.0-rc.0 |           3.6.0 |   98 kB |  98 kB |                    0% | 2.1 GB |     false |      false |         5 |         23 |                 23 |        |                    3.6.0 |              true |
+-----------------+------------------+------------+-----------------+---------+--------+-----------------------+--------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
COMMENT

etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
<<COMMENT
localhost:2379 is healthy: successfully committed proposal: took = 939.625µs
localhost:32379 is healthy: successfully committed proposal: took = 981.459µs
localhost:22379 is healthy: successfully committed proposal: took = 1.11075ms
COMMENT
Hinweis

Anders als v3.5 meldet der Statusendpunkt von v3.6 die Downgrade-Informationen. Daher zeigen heruntergestufte Mitglieder bis zum Abschluss des Downgrades weiterhin DOWNGRADE ENABLED als true sowie ihre Speicherversion an.

Schritt 7: Schritt 5 und Schritt 6 für die übrigen Mitglieder wiederholen

Sobald alle Mitglieder heruntergestuft wurden, wird das Downgrade automatisch abgeschlossen und DOWNGRADE ENABLED auf false zurückgesetzt. Prüfen Sie den Zustand und Status des Clusters und bestätigen Sie, dass die Nebenversion aller Mitglieder und die Speicherversion v3.6 sind:

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint status -w=table
<<COMMENT
+-----------------+------------------+---------+-----------------+---------+--------+-----------------------+--------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
|    ENDPOINT     |        ID        | VERSION | STORAGE VERSION | DB SIZE | IN USE | PERCENTAGE NOT IN USE | QUOTA  | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS | DOWNGRADE TARGET VERSION | DOWNGRADE ENABLED |
+-----------------+------------------+---------+-----------------+---------+--------+-----------------------+--------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
|  localhost:2379 | 7339c4e5e833c029 |  3.6.13 |           3.6.0 |   98 kB |  98 kB |                    0% | 2.1 GB |     false |      false |         6 |         30 |                 30 |        |                          |             false |
| localhost:22379 | 729934363faa4a24 |  3.6.13 |           3.6.0 |   98 kB |  98 kB |                    0% | 2.1 GB |      true |      false |         6 |         30 |                 30 |        |                          |             false |
| localhost:32379 |  b548c2511513015 |  3.6.13 |           3.6.0 |   98 kB |  98 kB |                    0% | 2.1 GB |     false |      false |         6 |         30 |                 30 |        |                          |             false |
+-----------------+------------------+---------+-----------------+---------+--------+-----------------------+--------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
COMMENT

etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
<<COMMENT
localhost:22379 is healthy: successfully committed proposal: took = 5.176958ms
localhost:32379 is healthy: successfully committed proposal: took = 5.177875ms
localhost:2379 is healthy: successfully committed proposal: took = 5.191625ms
COMMENT

curl http://localhost:2379/version
<<COMMENT
{"etcdserver":"3.6.13","etcdcluster":"3.6.0","storage":"3.6.0"}
COMMENT

curl http://localhost:22379/version
<<COMMENT
{"etcdserver":"3.6.13","etcdcluster":"3.6.0","storage":"3.6.0"}
COMMENT

curl http://localhost:32379/version
<<COMMENT
{"etcdserver":"3.6.13","etcdcluster":"3.6.0","storage":"3.6.0"}
COMMENT

Im Protokoll des Leaders sollten Sie eine Meldung ähnlich der folgenden sehen können:

{"level":"info","ts":"2026-07-02T06:48:32.312205+0300","caller":"version/monitor.go:143","msg":"the cluster has been downgraded","cluster-version":"3.6.0"}

16.3 - Downgrade von etcd v3.6 auf v3.5

Verfahren, Checklisten und Hinweise zum Downgrade von etcd v3.6 auf v3.5

Im Allgemeinen kann das Downgrade von etcd v3.6 auf v3.5 als schrittweises Downgrade ohne Ausfallzeit erfolgen:

  • Die etcd-v3.6-Prozesse nacheinander stoppen und durch etcd-v3.5-Prozesse ersetzen.
  • Nach dem Aktivieren des Downgrades stehen dem Cluster die neuen Funktionen von v3.6 nicht mehr zur Verfügung.

Lesen Sie zur Vorbereitung den Rest dieses Leitfadens, bevor Sie mit dem Downgrade beginnen .

Checklisten für das Downgrade

Wichtige inkompatible Änderungen von v3.6 auf v3.5:

Unterschiede bei Flags

Wenn Sie eines der folgenden Flags in Ihren v3.6-Konfigurationen verwenden, entfernen Sie es beim Downgrade auf v3.5, benennen Sie es um oder ändern Sie den Standardwert entsprechend.

Hinweis

Der Vergleich basiert auf den Versionen v3.6.0 und v.3.5.18. Die tatsächlichen Unterschiede hängen von Ihrer Patch-Version ab; prüfen Sie sie zunächst mit diff <(etcd-3.6/bin/etcd -h | grep \\-\\-) <(etcd-3.5/bin/etcd -h | grep \\-\\-).

# flags not available in v3.5
-etcd --discovery-token ''
-etcd --discovery-endpoints ''
-etcd --discovery-dial-timeout '2s'
-etcd --discovery-request-timeout '5s'
-etcd --discovery-keepalive-time '2s'
-etcd --discovery-keepalive-timeout '6s'
-etcd --discovery-insecure-transport 'true'
-etcd --discovery-insecure-skip-tls-verify 'false'
-etcd --discovery-cert ''
-etcd --discovery-key ''
-etcd --discovery-cacert ''
-etcd --discovery-user ''
-etcd --discovery-password ''
-etcd --feature-gates
-etcd --log-format

# same flag with different names
-etcd --bootstrap-defrag-threshold-megabytes
+etcd --experimental-bootstrap-defrag-threshold-megabytes
-etcd --compaction-batch-limit
+etcd --experimental-compaction-batch-limit
-etcd --compact-hash-check-time
+etcd --experimental-compact-hash-check-time
-etcd --compaction-sleep-interval
+etcd --experimental-compaction-sleep-interval
-etcd --corrupt-check-time
+etcd --experimental-corrupt-check-time
-etcd --enable-distributed-tracing
+etcd --experimental-enable-distributed-tracing
-etcd --distributed-tracing-address
+etcd --experimental-distributed-tracing-address
-etcd --distributed-tracing-instance-id
+etcd --experimental-distributed-tracing-instance-id
-etcd --distributed-tracing-sampling-rate
+etcd --experimental-distributed-tracing-sampling-rate
-etcd --distributed-tracing-service-name
+etcd --experimental-distributed-tracing-service-name
-etcd --downgrade-check-time
+etcd --experimental-downgrade-check-time
-etcd --max-learners
+etcd --experimental-max-learners
-etcd --memory-mlock
+etcd --experimental-memory-mlock
-etcd --peer-skip-client-san-verification
+etcd --experimental-peer-skip-client-san-verification
-etcd --snapshot-catchup-entries
+etcd --experimental-snapshot-catchup-entries
-etcd --warning-apply-duration
+etcd --experimental-warning-apply-duration
-etcd --warning-unary-request-duration
+etcd --experimental-warning-unary-request-duration
-etcd --watch-progress-notify-interval
+etcd --experimental-watch-progress-notify-interval

# equivalent flags of v3.6 feature gates
-etcd --feature-gates=CompactHashCheck=true
+etcd --experimental-compact-hash-check-enabled=true
-etcd --feature-gates=InitialCorruptCheck=true
+etcd --experimental-enable-initial-corrupt-check=true
-etcd --feature-gates=LeaseCheckpoint=true
+etcd --experimental-enable-lease-checkpoint=true
-etcd --feature-gates=LeaseCheckpointPersist=true
+etcd --experimental-enable-lease-checkpoint-persist=true
-etcd --feature-gates=StopGRPCServiceOnDefrag=true
+etcd --experimental-stop-grpc-service-on-defrag=true
-etcd --feature-gates=TxnModeWriteWithSharedBuffer=false
+etcd --experimental-txn-mode-write-with-shared-buffer=false

# same flag different defaults
-etcd --snapshot-count=10000
+etcd --snapshot-count=100000
-etcd --v2-deprecation='write-only'
+etcd --v2-deprecation='not-yet'
-etcd --discovery-fallback='exit'
+etcd --discovery-fallback='proxy'

Unterschiede bei Prometheus-Metriken

# metrics not available in v3.5
-etcd_network_known_peers
-etcd_server_feature_enabled

Checklisten für das Server-Downgrade

Downgrade-Voraussetzungen

Damit das schrittweise Downgrade reibungslos verläuft, muss der laufende Cluster fehlerfrei sein. Prüfen Sie den Zustand des Clusters mit dem Befehl etcdctl endpoint health, bevor Sie fortfahren.

Vorbereitung

Testen Sie vor einem etcd-Downgrade immer die von etcd abhängigen Dienste in einer Staging-Umgebung, bevor Sie das Downgrade in der Produktionsumgebung durchführen.

Laden Sie vor Beginn das Snapshot-Backup herunter . Falls beim Downgrade etwas schiefgeht, können Sie mit diesem Backup ein Rollback auf die bestehende etcd-Version durchführen.

Laden Sie vor Beginn das neueste Release von etcd v3.5 herunter.

Gemischte Versionen

Während des Downgrades unterstützt ein etcd-Cluster Mitglieder mit gemischten etcd-Versionen und verwendet das Protokoll der niedrigsten gemeinsamen Version. Der Cluster gilt als heruntergestuft, sobald das Downgrade mit etcdctl downgrade enable 3.5 aktiviert wurde. Intern wird die Gesamtversion des Clusters auf die Zielversion des Downgrades gesetzt, die die gemeldete Version und die unterstützten Funktionen bestimmt.

Rollback

Erstellen Sie vor dem Downgrade Ihres etcd-Clusters ein Snapshot-Backup des Clusters und laden Sie es herunter . Mit diesem Snapshot lässt sich der Cluster bei Bedarf in seinen Zustand vor dem Downgrade zurückversetzen. Falls während des Downgrades Probleme auftreten, sollten Benutzer zunächst deren Ursache ermitteln und beheben.

Wenn das Downgrade nach Ausführung von etcdctl downgrade enable begonnen hat und sich der Cluster noch in einem Zustand mit gemischten Versionen befindet, also mindestens ein Mitglied weiterhin v3.6 verwendet, können Benutzer das laufende Downgrade durch Ausführen von etcdctl downgrade cancel abbrechen und alle heruntergestuften Mitglieder mit den ursprünglichen v3.6-Binärdateien neu starten.

Sobald alle Mitglieder auf v3.5 heruntergestuft wurden, gilt das Downgrade des Clusters als vollständig abgeschlossen. Wenn Benutzer danach zur ursprünglichen Version zurückkehren möchten, sollten sie dem offiziellen Upgrade-Leitfaden folgen, um Konsistenz zu gewährleisten und Datenbeschädigungen zu vermeiden.

Downgrade-Verfahren

Dieses Beispiel zeigt das Downgrade eines etcd-v3.6-Clusters mit 3 Mitgliedern, der auf einem lokalen Rechner läuft.

Schritt 1: Downgrade-Voraussetzungen prüfen

Ist der Cluster fehlerfrei und läuft er mit v3.6.x?

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint health
<<COMMENT
localhost:2379 is healthy: successfully committed proposal: took = 2.118638ms
localhost:22379 is healthy: successfully committed proposal: took = 3.631388ms
localhost:32379 is healthy: successfully committed proposal: took = 2.157051ms
COMMENT

curl http://localhost:2379/version
<<COMMENT
{"etcdserver":"3.6.0-alpha.0","etcdcluster":"3.6.0","storage":"3.6.0"}
COMMENT

curl http://localhost:22379/version
<<COMMENT
{"etcdserver":"3.6.0-alpha.0","etcdcluster":"3.6.0","storage":"3.6.0"}
COMMENT

curl http://localhost:32379/version
<<COMMENT
{"etcdserver":"3.6.0-alpha.0","etcdcluster":"3.6.0","storage":"3.6.0"}
COMMENT

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint status -w=table
<<COMMENT
+-----------------+------------------+---------------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
|    ENDPOINT     |        ID        |    VERSION    | STORAGE VERSION | DB SIZE | IN USE | PERCENTAGE NOT IN USE | QUOTA | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS | DOWNGRADE TARGET VERSION | DOWNGRADE ENABLED |
+-----------------+------------------+---------------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
|  localhost:2379 | 8211f1d0f64f3269 | 3.6.0-alpha.0 |           3.6.0 |   20 kB |  16 kB |                   20% |   0 B |      true |      false |         2 |         10 |                 10 |        |                          |             false |
| localhost:22379 | 91bc3c398fb3c146 | 3.6.0-alpha.0 |           3.6.0 |   20 kB |  16 kB |                   20% |   0 B |     false |      false |         2 |         10 |                 10 |        |                          |             false |
| localhost:32379 | fd422379fda50e48 | 3.6.0-alpha.0 |           3.6.0 |   20 kB |  16 kB |                   20% |   0 B |     false |      false |         2 |         10 |                 10 |        |                          |             false |
+-----------------+------------------+---------------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
COMMENT

Schritt 2: Snapshot-Backup vom Leader herunterladen

Laden Sie das Snapshot-Backup herunter , um das Downgrade bei Problemen rückgängig machen zu können.

Schritt 3: Zielversion des Downgrades validieren

Validieren Sie die Zielversion des Downgrades, bevor Sie das Downgrade aktivieren:

  • Wir unterstützen nur Downgrades um jeweils eine Nebenversion. Ein Downgrade von v3.6 auf v3.4 ist beispielsweise nicht zulässig.
  • Fahren Sie erst mit dem nächsten Schritt fort, wenn die Validierung erfolgreich war.
etcdctl downgrade validate 3.5
<<COMMENT
Downgrade validate success, cluster version 3.6
COMMENT

Schritt 4: Downgrade aktivieren

etcdctl downgrade enable 3.5
<<COMMENT
Downgrade enable success, cluster version 3.6
COMMENT

Nach dem Aktivieren des Downgrades beginnt der Cluster, das Protokoll von v3.5 zu verwenden, der Zielversion des Downgrades. Außerdem migriert etcd das Schema automatisch auf die Zielversion des Downgrades, was normalerweise sehr schnell geschieht. Prüfen Sie den Endpunktstatus und bestätigen Sie, dass die Speicherversion aller Server auf v3.5 migriert wurde, bevor Sie mit dem nächsten Schritt fortfahren.

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint status -w=table
<<COMMENT
+-----------------+------------------+---------------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
|    ENDPOINT     |        ID        |    VERSION    | STORAGE VERSION | DB SIZE | IN USE | PERCENTAGE NOT IN USE | QUOTA | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS | DOWNGRADE TARGET VERSION | DOWNGRADE ENABLED |
+-----------------+------------------+---------------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
|  localhost:2379 | 8211f1d0f64f3269 | 3.6.0-alpha.0 |           3.5.0 |   20 kB |  16 kB |                   20% |   0 B |      true |      false |         2 |         12 |                 12 |        |                    3.5.0 |              true |
| localhost:22379 | 91bc3c398fb3c146 | 3.6.0-alpha.0 |           3.5.0 |   20 kB |  16 kB |                   20% |   0 B |     false |      false |         2 |         12 |                 12 |        |                    3.5.0 |              true |
| localhost:32379 | fd422379fda50e48 | 3.6.0-alpha.0 |           3.5.0 |   20 kB |  16 kB |                   20% |   0 B |     false |      false |         2 |         12 |                 12 |        |                    3.5.0 |              true |
+-----------------+------------------+---------------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
COMMENT
Hinweis

Sobald das Downgrade aktiviert wurde, verwendet der Cluster weiterhin das Protokoll von v3.5, auch wenn auf allen Servern noch die v3.6-Binärdatei läuft, sofern das Downgrade nicht mit etcdctl downgrade cancel abgebrochen wird.

Schritt 5: Einen bestehenden etcd-Server stoppen

Prüfen Sie vor dem Stoppen des Servers, ob er der Leader ist. Wir empfehlen, den Leader zuletzt herunterzustufen.

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint status -w=table
<<COMMENT
+-----------------+------------------+---------------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
|    ENDPOINT     |        ID        |    VERSION    | STORAGE VERSION | DB SIZE | IN USE | PERCENTAGE NOT IN USE | QUOTA | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS | DOWNGRADE TARGET VERSION | DOWNGRADE ENABLED |
+-----------------+------------------+---------------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
|  localhost:2379 | 8211f1d0f64f3269 | 3.6.0-alpha.0 |           3.5.0 |   20 kB |  16 kB |                   20% |   0 B |      true |      false |         2 |         12 |                 12 |        |                    3.5.0 |              true |
| localhost:22379 | 91bc3c398fb3c146 | 3.6.0-alpha.0 |           3.5.0 |   20 kB |  16 kB |                   20% |   0 B |     false |      false |         2 |         12 |                 12 |        |                    3.5.0 |              true |
| localhost:32379 | fd422379fda50e48 | 3.6.0-alpha.0 |           3.5.0 |   20 kB |  16 kB |                   20% |   0 B |     false |      false |         2 |         12 |                 12 |        |                    3.5.0 |              true |
+-----------------+------------------+---------------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
COMMENT

Wenn der zu stoppende Server der Leader ist, können Sie einen Teil der Ausfallzeit vermeiden, indem Sie vor dem Stoppen dieses Servers mit move-leader die Führungsrolle auf einen anderen Server übertragen.

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 move-leader 91bc3c398fb3c146

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint status -w=table
<<COMMENT
+-----------------+------------------+---------------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
|    ENDPOINT     |        ID        |    VERSION    | STORAGE VERSION | DB SIZE | IN USE | PERCENTAGE NOT IN USE | QUOTA | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS | DOWNGRADE TARGET VERSION | DOWNGRADE ENABLED |
+-----------------+------------------+---------------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
|  localhost:2379 | 8211f1d0f64f3269 | 3.6.0-alpha.0 |           3.5.0 |   20 kB |  16 kB |                   20% |   0 B |     false |      false |         3 |         13 |                 13 |        |                    3.5.0 |              true |
| localhost:22379 | 91bc3c398fb3c146 | 3.6.0-alpha.0 |           3.5.0 |   20 kB |  16 kB |                   20% |   0 B |      true |      false |         3 |         13 |                 13 |        |                    3.5.0 |              true |
| localhost:32379 | fd422379fda50e48 | 3.6.0-alpha.0 |           3.5.0 |   20 kB |  16 kB |                   20% |   0 B |     false |      false |         3 |         13 |                 13 |        |                    3.5.0 |              true |
+-----------------+------------------+---------------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
COMMENT

Wenn ein etcd-Prozess gestoppt wird, protokollieren die anderen Cluster-Mitglieder erwartete Fehler. Dies ist normal, da die Verbindung zu einem Cluster-Mitglied (vorübergehend) unterbrochen wurde:

{"level":"warn","ts":"2025-02-28T17:35:43.795069Z","caller":"etcdserver/cluster_util.go:259","msg":"failed to reach the peer URL","address":"http://127.0.0.1:12380/version","remote-member-id":"8211f1d0f64f3269","error":"Get \"http://127.0.0.1:12380/version\": dial tcp 127.0.0.1:12380: connect: connection refused"}
{"level":"warn","ts":"2025-02-28T17:35:43.795149Z","caller":"etcdserver/cluster_util.go:160","msg":"failed to get version","remote-member-id":"8211f1d0f64f3269","error":"Get \"http://127.0.0.1:12380/version\": dial tcp 127.0.0.1:12380: connect: connection refused"}
{"level":"warn","ts":"2025-02-28T17:35:44.368651Z","caller":"rafthttp/probing_status.go:68","msg":"prober detected unhealthy status","round-tripper-name":"ROUND_TRIPPER_SNAPSHOT","remote-peer-id":"8211f1d0f64f3269","rtt":"483.01µs","error":"dial tcp 127.0.0.1:12380: connect: connection refused"}
{"level":"warn","ts":"2025-02-28T17:35:44.368726Z","caller":"rafthttp/probing_status.go:68","msg":"prober detected unhealthy status","round-tripper-name":"ROUND_TRIPPER_RAFT_MESSAGE","remote-peer-id":"8211f1d0f64f3269","rtt":"735.659µs","error":"dial tcp 127.0.0.1:12380: connect: connection refused"}

Schritt 6: Den etcd-Server mit derselben Konfiguration neu starten (ohne die in v3.5 entfernten oder ersetzten Flags)

Starten Sie den etcd-Server mit derselben Konfiguration, aber mit der neuen etcd-Binärdatei neu.

-etcd-3.6/bin --name s1 \
+etcd-3.5/bin --name s1 \
  --data-dir /tmp/etcd/s1 \
  --listen-client-urls http://localhost:2379 \
  --advertise-client-urls http://localhost:2379 \
  --listen-peer-urls http://localhost:2380 \
  --initial-advertise-peer-urls http://localhost:2380 \
  --initial-cluster s1=http://localhost:2380,s2=http://localhost:22380,s3=http://localhost:32380 \
  --initial-cluster-token tkn \
  --initial-cluster-state existing

Prüfen Sie, ob jedes Mitglied und anschließend der gesamte Cluster mit der neuen etcd-v3.5-Binärdatei wieder fehlerfrei ist:

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint status -w=table
<<COMMENT
+-----------------+------------------+---------------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
|    ENDPOINT     |        ID        |    VERSION    | STORAGE VERSION | DB SIZE | IN USE | PERCENTAGE NOT IN USE | QUOTA | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS | DOWNGRADE TARGET VERSION | DOWNGRADE ENABLED |
+-----------------+------------------+---------------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
|  localhost:2379 | 8211f1d0f64f3269 |        3.5.18 |                 |   20 kB |  16 kB |                   20% |   0 B |     false |      false |         3 |         14 |                 14 |        |                          |             false |
| localhost:22379 | 91bc3c398fb3c146 | 3.6.0-alpha.0 |           3.5.0 |   20 kB |  16 kB |                   20% |   0 B |      true |      false |         3 |         14 |                 14 |        |                    3.5.0 |              true |
| localhost:32379 | fd422379fda50e48 | 3.6.0-alpha.0 |           3.5.0 |   20 kB |  16 kB |                   20% |   0 B |     false |      false |         3 |         14 |                 14 |        |                    3.5.0 |              true |
+-----------------+------------------+---------------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
COMMENT

etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
<<COMMENT
localhost:22379 is healthy: successfully committed proposal: took = 4.650967ms
localhost:2379 is healthy: successfully committed proposal: took = 4.634377ms
localhost:32379 is healthy: successfully committed proposal: took = 5.047777ms
COMMENT
Hinweis

Beim v3.5-Server wird DOWNGRADE ENABLED als false angezeigt, weil die Downgrade-Informationen im Statusendpunkt von v3.5 nicht implementiert sind. Für den Cluster ist das Downgrade zu diesem Zeitpunkt weiterhin aktiviert.

Schritt 7: Schritt 5 und Schritt 6 für die übrigen Mitglieder wiederholen

Sobald alle Mitglieder heruntergestuft wurden, prüfen Sie den Zustand und Status des Clusters und bestätigen Sie, dass die Nebenversion aller Mitglieder v3.5 und die Speicherversion leer ist:

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint status -w=table
<<COMMENT
+-----------------+------------------+---------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
|    ENDPOINT     |        ID        | VERSION | STORAGE VERSION | DB SIZE | IN USE | PERCENTAGE NOT IN USE | QUOTA | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS | DOWNGRADE TARGET VERSION | DOWNGRADE ENABLED |
+-----------------+------------------+---------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
|  localhost:2379 | 8211f1d0f64f3269 |  3.5.18 |                 |   20 kB |  16 kB |                   20% |   0 B |     false |      false |         3 |         26 |                 26 |        |                          |             false |
| localhost:22379 | 91bc3c398fb3c146 |  3.5.18 |                 |   20 kB |  16 kB |                   20% |   0 B |      true |      false |         3 |         26 |                 26 |        |                          |             false |
| localhost:32379 | fd422379fda50e48 |  3.5.18 |                 |   20 kB |  16 kB |                   20% |   0 B |     false |      false |         3 |         26 |                 26 |        |                          |             false |
+-----------------+------------------+---------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
COMMENT

etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
<<COMMENT
localhost:22379 is healthy: successfully committed proposal: took = 4.650967ms
localhost:2379 is healthy: successfully committed proposal: took = 4.634377ms
localhost:32379 is healthy: successfully committed proposal: took = 5.047777ms
COMMENT

curl http://localhost:2379/version
<<COMMENT
{"etcdserver":"3.5.18","etcdcluster":"3.5.0"}
COMMENT

curl http://localhost:22379/version
<<COMMENT
{"etcdserver":"3.5.18","etcdcluster":"3.5.0"}
COMMENT

curl http://localhost:32379/version
<<COMMENT
{"etcdserver":"3.5.18","etcdcluster":"3.5.0"}
COMMENT

Im Protokoll des Leaders sollten Sie eine Meldung ähnlich der folgenden sehen können:

{"level":"info","ts":"2025-02-28T17:59:50.019862Z","caller":"etcdserver/server.go:2749","msg":"the cluster has been downgraded","cluster-version":"3.5.0"}

16.4 - Downgrade von etcd 3.5 auf 3.4

Verfahren, Checklisten und Hinweise zum Downgrade von etcd 3.5 auf 3.4

Im Allgemeinen kann das Downgrade von etcd 3.5 auf 3.4 als schrittweises Downgrade ohne Ausfallzeit erfolgen:

  • Die etcd-3.5-Prozesse nacheinander stoppen und durch etcd-3.4-Prozesse ersetzen.
  • Sobald ein 3.4-Prozess gestartet wurde, stehen dem Cluster die neuen Funktionen von 3.5 nicht mehr zur Verfügung.

Lesen Sie zur Vorbereitung den Rest dieses Leitfadens, bevor Sie mit dem Downgrade beginnen .

Checklisten für das Downgrade

Warnung

Wenn in Ihrem Cluster die Authentifizierung aktiviert ist, wird ein schrittweises Downgrade von 3.5 nicht unterstützt, da 3.5 ein Format von WAL-Einträgen zur Authentifizierung ändert . Sie können den Anweisungen zur Authentifizierung folgen, um zunächst die Authentifizierung zu deaktivieren und alle Benutzer zu löschen.

Wichtige inkompatible Änderungen von 3.5 auf 3.4:

Unterschiede bei Flags

Wenn Sie eines der folgenden Flags in Ihren 3.5-Konfigurationen verwenden, entfernen Sie es beim Downgrade auf 3.4, benennen Sie es um oder ändern Sie den Standardwert entsprechend.

Hinweis

Der Vergleich basiert auf den Versionen 3.5.14 und v.3.4.33. Die tatsächlichen Unterschiede hängen von Ihrer Patch-Version ab; prüfen Sie sie zunächst mit diff <(etcd-3.5/bin/etcd -h | grep \\-\\-) <(etcd-3.4/bin/etcd -h | grep \\-\\-).

# flags not available in 3.4
-etcd --socket-reuse-port
-etcd --socket-reuse-address
-etcd --raft-read-timeout
-etcd --raft-write-timeout
-etcd --v2-deprecation
-etcd --client-cert-file
-etcd --client-key-file
-etcd --peer-client-cert-file
-etcd --peer-client-key-file
-etcd --self-signed-cert-validity
-etcd --enable-log-rotation --log-rotation-config-json=some.json
-etcd --experimental-enable-distributed-tracing --experimental-distributed-tracing-address='localhost:4317' --experimental-distributed-tracing-service-name='etcd' --experimental-distributed-tracing-instance-id='' --experimental-distributed-tracing-sampling-rate='0'
-etcd --experimental-compact-hash-check-enabled --experimental-compact-hash-check-time='1m'
-etcd --experimental-downgrade-check-time
-etcd --experimental-memory-mlock
-etcd --experimental-txn-mode-write-with-shared-buffer
-etcd --experimental-bootstrap-defrag-threshold-megabytes
-etcd --experimental-stop-grpc-service-on-defrag

# same flag with different names
-etcd --backend-bbolt-freelist-type=map
+etcd --experimental-backend-bbolt-freelist-type=array

# same flag different defaults
-etcd --pre-vote=true
+etcd --pre-vote=false

-etcd --logger=zap
+etcd --logger=capnslog

etcd --logger zap

3.4 verwendet standardmäßig --logger=capnslog, während 3.5 standardmäßig --logger=zap verwendet.

Wenn Sie weiterhin zap verwenden möchten, müssen Sie es ausdrücklich angeben.

+etcd --logger=zap --log-outputs=stderr

+# to write logs to stderr and a.log file at the same time
+etcd --logger=zap --log-outputs=stderr,a.log

Unterschiede bei Prometheus-Metriken

# metrics not available in 3.4
-etcd_debugging_mvcc_db_compaction_last

Checklisten für das Server-Downgrade

Downgrade-Voraussetzungen

Damit das schrittweise Downgrade reibungslos verläuft, muss der laufende Cluster fehlerfrei sein. Prüfen Sie den Zustand des Clusters mit dem Befehl etcdctl endpoint health, bevor Sie fortfahren.

Die 3.4-Version, auf die das Downgrade erfolgen soll, muss >= 3.4.32 sein.

Vorbereitung

Testen Sie vor einem etcd-Downgrade immer die von etcd abhängigen Dienste in einer Staging-Umgebung, bevor Sie das Downgrade in der Produktionsumgebung durchführen.

Laden Sie vor Beginn das Snapshot-Backup herunter . Falls beim Downgrade etwas schiefgeht, können Sie mit diesem Backup ein Rollback auf die bestehende etcd-Version durchführen. Beachten Sie, dass der Befehl snapshot nur die v3-Daten sichert. Informationen zu v2-Daten finden Sie unter Backup des v2-Datenspeichers .

Laden Sie vor Beginn das neueste Release von etcd 3.4 herunter und stellen Sie sicher, dass seine Version >= 3.4.32 ist.

Gemischte Versionen

Während des Downgrades unterstützt ein etcd-Cluster Mitglieder mit gemischten etcd-Versionen und verwendet das Protokoll der niedrigsten gemeinsamen Version. Der Cluster gilt als heruntergestuft, sobald eines seiner Mitglieder auf Version 3.4 heruntergestuft wurde. Intern handeln die etcd-Mitglieder untereinander die Gesamtversion des Clusters aus, die die gemeldete Version und die unterstützten Funktionen bestimmt.

Einschränkungen

Hinweis: Wenn der Cluster nur v3-Daten und keine v2-Daten enthält, gilt diese Einschränkung nicht.

Wenn der Cluster einen v2-Datenbestand von mehr als 50MB bereitstellt, kann es bis zu zwei Minuten dauern, bis jedes neu heruntergestufte Mitglied zum bestehenden Cluster aufgeschlossen hat. Prüfen Sie die Größe eines aktuellen Snapshots, um die Gesamtdatenmenge abzuschätzen. Anders ausgedrückt ist es am sichersten, zwischen den Downgrades der einzelnen Mitglieder jeweils 2 Minuten zu warten.

Bei einer deutlich größeren Gesamtdatenmenge von 100MB oder mehr kann dieser einmalige Vorgang noch länger dauern. Administratoren sehr großer etcd-Cluster dieser Größenordnung können vor dem Downgrade das etcd-Team kontaktieren; wir beraten Sie gern zum Vorgehen.

Rollback

Wenn ein Mitglied auf 3.4 heruntergestuft wurde, wird die Cluster-Version auf 3.4 heruntergestuft, und der Betrieb ist mit „3.4“ kompatibel. Für ein Rollback müssten Sie den Anweisungen zum Upgrade von etcd 3.4 auf 3.5 folgen.

Laden Sie das Snapshot-Backup herunter , um das Downgrade auch nach einem vollständig abgeschlossenen Downgrade des Clusters rückgängig machen zu können.

Downgrade-Verfahren

Dieses Beispiel zeigt das Downgrade eines etcd-3.5-Clusters mit 3 Mitgliedern, der auf einem lokalen Rechner läuft.

Schritt 1: Downgrade-Voraussetzungen prüfen

Ist der Cluster fehlerfrei und läuft er mit 3.5.x?

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint health
<<COMMENT
localhost:2379 is healthy: successfully committed proposal: took = 2.118638ms
localhost:22379 is healthy: successfully committed proposal: took = 3.631388ms
localhost:32379 is healthy: successfully committed proposal: took = 2.157051ms
COMMENT

curl http://localhost:2379/version
<<COMMENT
{"etcdserver":"3.5.0","etcdcluster":"3.5.0"}
COMMENT

curl http://localhost:22379/version
<<COMMENT
{"etcdserver":"3.5.0","etcdcluster":"3.5.0"}
COMMENT

curl http://localhost:32379/version
<<COMMENT
{"etcdserver":"3.5.0","etcdcluster":"3.5.0"}
COMMENT

Schritt 2: Snapshot-Backup vom Leader herunterladen

Laden Sie das Snapshot-Backup herunter , um das Downgrade bei Problemen rückgängig machen zu können.

Schritt 3: Einen bestehenden etcd-Server stoppen

Prüfen Sie vor dem Stoppen des Servers, ob er der Leader ist.

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint status -w=table
<<COMMENT
+-----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
|    ENDPOINT     |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+-----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
|  localhost:2379 | 8211f1d0f64f3269 |  3.5.13 |   20 kB |      true |      false |         2 |          9 |                  9 |        |
| localhost:22379 | 91bc3c398fb3c146 |  3.5.13 |   20 kB |     false |      false |         2 |          9 |                  9 |        |
| localhost:32379 | fd422379fda50e48 |  3.5.13 |   20 kB |     false |      false |         2 |          9 |                  9 |        |
+-----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
COMMENT

Wenn der zu stoppende Server der Leader ist, können Sie einen Teil der Ausfallzeit vermeiden, indem Sie vor dem Stoppen dieses Servers mit move-leader die Führungsrolle auf einen anderen Server übertragen.

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 move-leader 91bc3c398fb3c146

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint status -w=table
<<COMMENT
+-----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
|    ENDPOINT     |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+-----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
|  localhost:2379 | 8211f1d0f64f3269 |  3.5.13 |   20 kB |     false |      false |         3 |         11 |                 11 |        |
| localhost:22379 | 91bc3c398fb3c146 |  3.5.13 |   20 kB |      true |      false |         3 |         11 |                 11 |        |
| localhost:32379 | fd422379fda50e48 |  3.5.13 |   20 kB |     false |      false |         3 |         11 |                 11 |        |
+-----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
COMMENT

Wenn ein etcd-Prozess gestoppt wird, protokollieren die anderen Cluster-Mitglieder erwartete Fehler. Dies ist normal, da die Verbindung zu einem Cluster-Mitglied (vorübergehend) unterbrochen wurde:

{"level":"info","ts":"2024-05-14T20:25:47.051124Z","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"91bc3c398fb3c146 became leader at term 3"}
{"level":"info","ts":"2024-05-14T20:25:47.051139Z","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"raft.node: 91bc3c398fb3c146 elected leader 91bc3c398fb3c146 at term 3"}

^C{"level":"warn","ts":"2024-05-14T20:27:09.094119Z","caller":"rafthttp/stream.go:421","msg":"lost TCP streaming connection with remote peer","stream-reader-type":"stream MsgApp v2","local-member-id":"91bc3c398fb3c146","remote-peer-id":"8211f1d0f64f3269","error":"EOF"}
{"level":"warn","ts":"2024-05-14T20:27:09.09427Z","caller":"rafthttp/stream.go:421","msg":"lost TCP streaming connection with remote peer","stream-reader-type":"stream Message","local-member-id":"91bc3c398fb3c146","remote-peer-id":"8211f1d0f64f3269","error":"EOF"}
{"level":"warn","ts":"2024-05-14T20:27:09.095535Z","caller":"rafthttp/peer_status.go:66","msg":"peer became inactive (message send to peer failed)","peer-id":"8211f1d0f64f3269","error":"failed to dial 8211f1d0f64f3269 on stream MsgApp v2 (peer 8211f1d0f64f3269 failed to find local node 91bc3c398fb3c146)"}
{"level":"warn","ts":"2024-05-14T20:27:09.43915Z","caller":"rafthttp/stream.go:223","msg":"lost TCP streaming connection with remote peer","stream-writer-type":"stream Message","local-member-id":"91bc3c398fb3c146","remote-peer-id":"8211f1d0f64f3269"}
{"level":"warn","ts":"2024-05-14T20:27:11.085646Z","caller":"etcdserver/cluster_util.go:294","msg":"failed to reach the peer URL","address":"http://127.0.0.1:12380/version","remote-member-id":"8211f1d0f64f3269","error":"Get \"http://127.0.0.1:12380/version\": dial tcp 127.0.0.1:12380: connect: connection refused"}
{"level":"warn","ts":"2024-05-14T20:27:11.085718Z","caller":"etcdserver/cluster_util.go:158","msg":"failed to get version","remote-member-id":"8211f1d0f64f3269","error":"Get \"http://127.0.0.1:12380/version\": dial tcp 127.0.0.1:12380: connect: connection refused"}
{"level":"warn","ts":"2024-05-14T20:27:13.557385Z","caller":"rafthttp/probing_status.go:68","msg":"prober detected unhealthy status","round-tripper-name":"ROUND_TRIPPER_SNAPSHOT","remote-peer-id":"8211f1d0f64f3269","rtt":"416.079µs","error":"dial tcp 127.0.0.1:12380: connect: connection refused"}

Schritt 4: Den etcd-Server mit derselben Konfiguration + --next-cluster-version-compatible neu starten

Starten Sie den etcd-Server mit derselben Konfiguration, aber mit der neuen etcd-Binärdatei und --next-cluster-version-compatible neu.

-etcd-3.5/bin --name s1 \
+etcd-3.4/bin --name s1 \
  --data-dir /tmp/etcd/s1 \
  --listen-client-urls http://localhost:2379 \
  --advertise-client-urls http://localhost:2379 \
  --listen-peer-urls http://localhost:2380 \
  --initial-advertise-peer-urls http://localhost:2380 \
  --initial-cluster s1=http://localhost:2380,s2=http://localhost:22380,s3=http://localhost:32380 \
  --initial-cluster-token tkn \
  --initial-cluster-state existing
  --next-cluster-version-compatible

Das neue etcd 3.4 veröffentlicht seine Informationen im Cluster. Zu diesem Zeitpunkt beginnt der Cluster, das Protokoll von 3.4 zu verwenden, der niedrigsten gemeinsamen Version.

> `{"level":"info","ts":"2024-05-13T21:05:43.981445Z","caller":"membership/cluster.go:561","msg":"set initial cluster version","cluster-id":"ef37ad9dc622a7c4","local-member-id":"8211f1d0f64f3269","cluster-version":"3.0"}`

> `{"level":"info","ts":"2024-05-13T21:05:43.982188Z","caller":"api/capability.go:77","msg":"enabled capabilities for version","cluster-version":"3.0"}`

> `{"level":"info","ts":"2024-05-13T21:05:43.982312Z","caller":"membership/cluster.go:549","msg":"updated cluster version","cluster-id":"ef37ad9dc622a7c4","local-member-id":"8211f1d0f64f3269","from":"3.0","from":"3.5"}`

> `{"level":"info","ts":"2024-05-13T21:05:43.982376Z","caller":"api/capability.go:77","msg":"enabled capabilities for version","cluster-version":"3.5"}`

> `{"level":"info","ts":"2024-05-13T21:05:44.000672Z","caller":"etcdserver/server.go:2152","msg":"published local member to cluster through raft","local-member-id":"8211f1d0f64f3269","local-member-attributes":"{Name:infra1 ClientURLs:[http://127.0.0.1:2379]}","request-path":"/0/members/8211f1d0f64f3269/attributes","cluster-id":"ef37ad9dc622a7c4","publish-timeout":"7s"}`

> `{"level":"info","ts":"2024-05-13T21:05:46.452631Z","caller":"membership/cluster.go:549","msg":"updated cluster version","cluster-id":"ef37ad9dc622a7c4","local-member-id":"8211f1d0f64f3269","from":"3.5","from":"3.4"}`

Prüfen Sie, ob jedes Mitglied und anschließend der gesamte Cluster mit der neuen etcd-3.4-Binärdatei wieder fehlerfrei ist:

etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
<<COMMENT
localhost:32379 is healthy: successfully committed proposal: took = 2.337471ms
localhost:22379 is healthy: successfully committed proposal: took = 1.130717ms
localhost:2379 is healthy: successfully committed proposal: took = 2.124843ms
COMMENT

Noch nicht heruntergestufte Mitglieder protokollieren Informationen wie die folgenden:

{"level":"info","ts":"2024-05-13T21:05:46.450764Z","caller":"etcdserver/server.go:2633","msg":"updating cluster version using v2 API","from":"3.5","to":"3.4"}
{"level":"info","ts":"2024-05-13T21:05:46.452419Z","caller":"membership/cluster.go:576","msg":"updated cluster version","cluster-id":"ef37ad9dc622a7c4","local-member-id":"91bc3c398fb3c146","from":"3.5","to":"3.4"}
{"level":"info","ts":"2024-05-13T21:05:46.452547Z","caller":"etcdserver/server.go:2652","msg":"cluster version is updated","cluster-version":"3.4"}

Schritt 5: Schritt 3 und Schritt 4 für die übrigen Mitglieder wiederholen

Sobald alle Mitglieder heruntergestuft wurden, prüfen Sie den Zustand und die Version des Clusters:

endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
<<COMMENT
localhost:2379 is healthy: successfully committed proposal: took = 492.834µs
localhost:22379 is healthy: successfully committed proposal: took = 1.015025ms
localhost:32379 is healthy: successfully committed proposal: took = 1.853077ms
COMMENT

curl http://localhost:2379/version
<<COMMENT
{"etcdserver":"3.4.32","etcdcluster":"3.4.0"}
COMMENT

curl http://localhost:22379/version
<<COMMENT
{"etcdserver":"3.4.32","etcdcluster":"3.4.0"}
COMMENT

curl http://localhost:32379/version
<<COMMENT
{"etcdserver":"3.4.32","etcdcluster":"3.4.0"}
COMMENT

17 - Upgrades

Upgrades von etcd-Clustern und -Anwendungen

17.1 - Upgrades von etcd-Clustern und -Anwendungen

Dokumentationsübersicht zu Upgrades von etcd-Clustern und -Anwendungen

Dieser Abschnitt enthält Dokumente speziell zu Upgrades von etcd-Clustern und -Anwendungen.

Upgrade-Richtlinie

Beachten Sie vor einem Upgrade, dass etcd nur die folgenden beiden Upgrade-Fälle unterstützt:

  • Patch-Upgrade: Upgrade zwischen Patch-Releases innerhalb derselben Nebenversion (z. B. 3.7.0 - 3.7.1).
  • Upgrade der Nebenversion: Upgrade um jeweils eine Nebenversion (z. B. 3.6 - 3.7). Upgrades, die eine Nebenversion überspringen, werden nicht unterstützt und schlagen wahrscheinlich fehl. Aktualisieren Sie auf die neueste Patch-Version, bevor Sie auf die nächste Nebenversion aktualisieren.

Upgrade eines etcd-v3.x-Clusters

Upgrade von etcd v2.3

17.2 - Upgrade von etcd v3.6 auf v3.7

Verfahren, Checklisten und Hinweise zum Upgrade von etcd v3.6 auf v3.7

Im Allgemeinen kann das Upgrade von etcd v3.6 auf v3.7 als Rolling Upgrade ohne Ausfallzeit erfolgen:

  • Die etcd-v3.6-Prozesse nacheinander stoppen und durch etcd-v3.7-Prozesse ersetzen.
  • Sobald alle v3.7-Prozesse laufen, stehen dem Cluster die neuen Funktionen von v3.7 zur Verfügung.

Lesen Sie zur Vorbereitung den Rest dieses Leitfadens, bevor Sie mit dem Upgrade beginnen .

Checklisten für das Upgrade

3.6 aktualisieren

Wichtig

Stellen Sie vor dem Upgrade auf 3.7 sicher, dass alle Ihre 3.6-Mitglieder auf 3.6.11 oder höher aktualisiert sind. Frühere 3.6-Patch-Releases sind möglicherweise nicht mit einem Rolling Upgrade auf 3.7 kompatibel.

V2-Speicher

Der v2-Speicher wurde in v3.7 vollständig entfernt. Die v2-HTTP-API (--enable-v2), die v2-auf-v3-Emulation (--experimental-enable-v2v3), der v2-Discovery-Dienst, das Paket client/v2 und das Laden von v2-Snapshot-Dateien sind sämtlich entfallen. Siehe die Verweise auf inkompatible Änderungen in CHANGELOG-3.7 .

Wenn Sie von einem 3.6-Cluster aktualisieren, sind diese Flags bereits nicht mehr vorhanden, und es sind keine Maßnahmen erforderlich. Wenn Sie von einem älteren Release mit benutzerdefinierten v2-Daten wechseln, folgen Sie vor dem Upgrade dem v2-Migrationsleitfaden .

Go-Refactoring

v3.7 enthält umfangreiche interne Umstrukturierungen, die normale Upgrades nicht betreffen, bei Upgrades benutzerdefinierter Integrationen jedoch berücksichtigt werden sollten:

  • Migration von gogo/protobuf zur Standardimplementierung google.golang.org/protobuf (verfolgt in #14533 ).
  • Migration der veralteten Bibliotheken für Protokollierung und Tags aus go-grpc-middleware v1 zu den v2-Interceptors (#20420 ).
  • Die OpenTelemetry-gRPC-Interceptors wurden auf otelgrpc v0.61.0 aktualisiert; dabei wurden die veralteten UnaryServerInterceptor und StreamServerInterceptor durch NewServerHandler ersetzt (#20017 ).

Wenn Sie etcd als Bibliothek einbetten, gegen die clientv3-API bauen oder von internen Paketen abhängen, prüfen Sie vor dem Upgrade das Änderungsprotokoll .

Entfernte Flags

Alle veralteten --experimental-*-Flags wurden in v3.7 entfernt (#19959 ). In v3.6 wurde jedes davon entweder durch ein gleichnamiges nicht experimentelles Flag oder durch einen --feature-gates-Eintrag ersetzt. Wenn Sie noch eines dieser Flags gesetzt haben, ersetzen Sie es vor dem Rolling Upgrade auf v3.7 durch die entsprechende v3.6-Variante; andernfalls kann der v3.7-Prozess nicht starten.

-etcd --experimental-bootstrap-defrag-threshold-megabytes
-etcd --experimental-compact-hash-check-enabled
-etcd --experimental-compact-hash-check-time
-etcd --experimental-compaction-batch-limit
-etcd --experimental-compaction-sleep-interval
-etcd --experimental-corrupt-check-time
-etcd --experimental-distributed-tracing-address
-etcd --experimental-distributed-tracing-instance-id
-etcd --experimental-distributed-tracing-sampling-rate
-etcd --experimental-distributed-tracing-service-name
-etcd --experimental-downgrade-check-time
-etcd --experimental-enable-distributed-tracing
-etcd --experimental-enable-lease-checkpoint
-etcd --experimental-enable-lease-checkpoint-persist
-etcd --experimental-initial-corrupt-check
-etcd --experimental-memory-mlock
-etcd --experimental-peer-skip-client-san-verification
-etcd --experimental-snapshot-catchup-entries
-etcd --experimental-stop-grpc-service-on-defrag
-etcd --experimental-txn-mode-write-with-shared-buffer
-etcd --experimental-warning-apply-duration
-etcd --experimental-warning-unary-request-duration
-etcd --experimental-watch-progress-notify-interval

Die Zuordnung jedes entfernten Flags zu seinem nicht experimentellen Gegenstück oder --feature-gates-Eintrag finden Sie im Upgrade-Leitfaden von v3.5 auf v3.6 .

Hinzugefügte Flags

Keine.

Flags mit neuen Standardwerten

Keine.

Checklisten für das Server-Upgrade

Upgrade-Voraussetzungen

Um eine bestehende etcd-Installation auf v3.7 zu aktualisieren, muss der laufende Cluster v3.6.11 oder höher verwenden. Falls er eine ältere Nebenversion verwendet, führen Sie zunächst ein Upgrade auf v3.6 durch; etcd unterstützt nur Upgrades um jeweils eine Nebenversion.

Außerdem muss der laufende Cluster fehlerfrei sein, damit das Rolling Upgrade reibungslos verläuft. Prüfen Sie den Zustand des Clusters mit dem Befehl etcdctl endpoint health, bevor Sie fortfahren.

Vorbereitung

Testen Sie vor einem etcd-Upgrade immer die von etcd abhängigen Dienste in einer Staging-Umgebung, bevor Sie das Upgrade in der Produktionsumgebung durchführen.

Laden Sie vor Beginn das Snapshot-Backup herunter . Falls beim Upgrade etwas schiefgeht, können Sie mit diesem Backup ein Rollback auf die bestehende etcd-Version durchführen.

Gemischte Versionen

Während des Upgrades unterstützt ein etcd-Cluster Mitglieder mit gemischten etcd-Versionen und verwendet das Protokoll der niedrigsten gemeinsamen Version. Der Cluster gilt erst als aktualisiert, wenn alle Mitglieder auf Version v3.7 aktualisiert wurden. Intern handeln die etcd-Mitglieder untereinander die Gesamtversion des Clusters aus, die die gemeldete Version und die unterstützten Funktionen bestimmt.

Rollback

Erstellen Sie vor dem Upgrade Ihres etcd-Clusters ein Snapshot-Backup des Clusters und laden Sie es herunter . Mit diesem Snapshot lässt sich der Cluster bei Bedarf in seinen Zustand vor dem Upgrade zurückversetzen. Falls während des Upgrades Probleme auftreten, sollten Benutzer zunächst deren Ursache ermitteln und beheben. Solange sich der Cluster noch in einem Zustand mit gemischten Versionen befindet, also mindestens ein Mitglied weiterhin v3.6 verwendet, können sie entweder die Binärdatei oder das Image durch die alte Version v3.6 ersetzen oder den Cluster direkt aus dem Snapshot wiederherstellen. In diesem gemischten Zustand arbeitet der Cluster weiterhin als v3.6-Cluster, sodass ein Rollback ohne formelles Downgrade-Verfahren möglich ist.

Sobald jedoch alle Mitglieder auf v3.7 aktualisiert wurden, gilt der Cluster als vollständig aktualisiert, und ein Rollback durch Austausch der Binärdateien ist nicht mehr möglich. Falls das Upgrade schiefgeht, bestehen in diesem Fall die einzigen Recovery-Möglichkeiten darin, den vor dem Upgrade erstellten Snapshot wiederherzustellen oder dem offiziellen Downgrade-Leitfaden zu folgen.

Upgrade-Verfahren

Dieses Beispiel zeigt das Upgrade eines etcd-v3.6-Clusters mit 3 Mitgliedern, der auf einem lokalen Rechner läuft. Die folgende Ausgabe stammt aus einem tatsächlichen Durchlauf mit etcd v3.6.12 und etcd v3.7.0-rc.0 auf einem einzelnen Host mit drei Loopback-Ports.

Schritt 1: Upgrade-Voraussetzungen prüfen

Ist der Cluster fehlerfrei und läuft er mit v3.6.11 oder höher?

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint health
<<COMMENT
localhost:2379 is healthy: successfully committed proposal: took = 7.681459ms
localhost:22379 is healthy: successfully committed proposal: took = 7.691750ms
localhost:32379 is healthy: successfully committed proposal: took = 7.698000ms
COMMENT

curl http://localhost:2379/version
<<COMMENT
{"etcdserver":"3.6.12","etcdcluster":"3.6.0","storage":"3.6.0"}
COMMENT

Schritt 2: Snapshot-Backup vom Leader herunterladen

Laden Sie das Snapshot-Backup herunter , um bei Problemen ein Downgrade durchführen zu können.

Der etcd-Leader enthält garantiert die neuesten Anwendungsdaten. Rufen Sie den Snapshot daher vom Leader ab:

for p in 2379 22379 32379; do
  echo -n "localhost:$p leader="
  curl -sL http://localhost:$p/metrics | grep "^etcd_server_is_leader " | awk '{print $2}'
done
<<COMMENT
localhost:2379 leader=1
localhost:22379 leader=0
localhost:32379 leader=0
COMMENT

etcdctl --endpoints=localhost:2379 snapshot save backup.db
<<COMMENT
{"level":"info","ts":"2026-06-02T07:01:41.863225+0300","caller":"snapshot/v3_snapshot.go:83","msg":"created temporary db file","path":"backup.db.part"}
{"level":"info","ts":"2026-06-02T07:01:41.866451+0300","logger":"client","caller":"v3@v3.6.12/maintenance.go:236","msg":"opened snapshot stream; downloading"}
{"level":"info","ts":"2026-06-02T07:01:41.874080+0300","caller":"snapshot/v3_snapshot.go:96","msg":"fetching snapshot","endpoint":"localhost:2379"}
{"level":"info","ts":"2026-06-02T07:01:41.877203+0300","caller":"snapshot/v3_snapshot.go:111","msg":"fetched snapshot","endpoint":"localhost:2379","size":"98 kB","took":"13.822583ms","etcd-version":"3.6.0"}
{"level":"info","ts":"2026-06-02T07:01:41.877303+0300","caller":"snapshot/v3_snapshot.go:121","msg":"saved","path":"backup.db"}
Snapshot saved at backup.db
Server version 3.6.0
COMMENT

Schritt 3: Einen bestehenden etcd-Server stoppen

Wenn ein etcd-Prozess gestoppt wird, protokollieren die anderen Cluster-Mitglieder erwartete Fehler. Dies ist normal, da die Verbindung zu einem Cluster-Mitglied (vorübergehend) unterbrochen wurde. Der Leader überträgt die Führungsrolle, bevor er sich beendet:

{"level":"info","ts":"2026-06-02T07:01:54.949299+0300","caller":"etcdserver/server.go:1274","msg":"leadership transfer finished","local-member-id":"7339c4e5e833c029","old-leader-member-id":"7339c4e5e833c029","new-leader-member-id":"b548c2511513015","took":"101.052625ms"}
{"level":"info","ts":"2026-06-02T07:01:54.949369+0300","caller":"etcdserver/server.go:2349","msg":"server has stopped; stopping cluster version's monitor"}
{"level":"info","ts":"2026-06-02T07:01:55.503219+0300","caller":"embed/etcd.go:626","msg":"stopped serving peer traffic","address":"127.0.0.1:2380"}

Schritt 4: Den etcd-Server mit derselben Konfiguration neu starten

Starten Sie den etcd-Server mit derselben Konfiguration, aber mit der neuen etcd-Binärdatei neu.

-etcd-old --name ${name} \
+etcd-new --name ${name} \
  --data-dir /path/to/${name}.etcd \
  --listen-client-urls http://localhost:2379 \
  --advertise-client-urls http://localhost:2379 \
  --listen-peer-urls http://localhost:2380 \
  --initial-advertise-peer-urls http://localhost:2380 \
  --initial-cluster s1=http://localhost:2380,s2=http://localhost:22380,s3=http://localhost:32380 \
  --initial-cluster-token tkn \
  --initial-cluster-state new

Das neue etcd v3.7 veröffentlicht seine Informationen im Cluster. Zu diesem Zeitpunkt verwendet der Cluster weiterhin das Protokoll von v3.6, der niedrigsten gemeinsamen Version.

{"level":"info","ts":"2026-06-02T07:01:58.920780+0300","caller":"membership/cluster.go:296","msg":"set cluster version from store","cluster-version":"3.6"}

{"level":"info","ts":"2026-06-02T07:01:58.979186+0300","caller":"etcdserver/server.go:1828","msg":"published local member to cluster through raft","local-member-id":"7339c4e5e833c029","local-member-attributes":"{Name:s1 ClientURLs:[http://localhost:2379]}","cluster-id":"7dee9ba76d59ed53","publish-timeout":"7s"}

Prüfen Sie, ob jedes Mitglied und anschließend der gesamte Cluster mit der neuen etcd-v3.7-Binärdatei wieder fehlerfrei ist:

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint status -w table
<<COMMENT
+-----------------+------------------+------------+-----------------+---------+--------+-----------+
|    ENDPOINT     |        ID        |  VERSION   | STORAGE VERSION | DB SIZE | LEADER | RAFT TERM |
+-----------------+------------------+------------+-----------------+---------+--------+-----------+
|  localhost:2379 | 7339c4e5e833c029 | 3.7.0-rc.0 |           3.6.0 |   98 kB |  false |         3 |
| localhost:22379 | 729934363faa4a24 |     3.6.12 |           3.6.0 |   98 kB |  false |         3 |
| localhost:32379 |  b548c2511513015 |     3.6.12 |           3.6.0 |   98 kB |   true |         3 |
+-----------------+------------------+------------+-----------------+---------+--------+-----------+
COMMENT

Noch nicht aktualisierte Mitglieder und das aktualisierte Mitglied protokollieren Meldungen zum Zustand mit gemischten Versionen, bis der gesamte Cluster aktualisiert wurde. Dies ist zu erwarten und endet, sobald alle etcd-Cluster-Mitglieder auf v3.7 aktualisiert wurden.

Schritt 5: Schritt 3 und Schritt 4 für die übrigen Mitglieder wiederholen

Sobald alle Mitglieder aktualisiert wurden, meldet der Cluster den erfolgreichen Abschluss des Upgrades auf v3.7:

{"level":"info","ts":"2026-06-02T07:02:36.054783+0300","caller":"etcdserver/server.go:2311","msg":"updating cluster version using v3 API","from":"3.6","to":"3.7"}

{"level":"info","ts":"2026-06-02T07:02:36.059345+0300","caller":"membership/cluster.go:593","msg":"updated cluster version","cluster-id":"7dee9ba76d59ed53","local-member-id":"7339c4e5e833c029","from":"3.6","to":"3.7"}

{"level":"info","ts":"2026-06-02T07:02:36.059409+0300","caller":"etcdserver/server.go:2326","msg":"cluster version is updated","cluster-version":"3.7"}

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint health
<<COMMENT
localhost:2379 is healthy: successfully committed proposal: took = 550.833µs
localhost:32379 is healthy: successfully committed proposal: took = 733.458µs
localhost:22379 is healthy: successfully committed proposal: took = 714.416µs
COMMENT

curl http://localhost:2379/version
<<COMMENT
{"etcdserver":"3.7.0-rc.0","etcdcluster":"3.7.0","storage":"3.7.0"}
COMMENT

curl http://localhost:22379/version
<<COMMENT
{"etcdserver":"3.7.0-rc.0","etcdcluster":"3.7.0","storage":"3.7.0"}
COMMENT

curl http://localhost:32379/version
<<COMMENT
{"etcdserver":"3.7.0-rc.0","etcdcluster":"3.7.0","storage":"3.7.0"}
COMMENT

17.3 - Upgrade von etcd v3.5 auf v3.6

Verfahren, Checklisten und Hinweise zum Upgrade von etcd v3.5 auf v3.6

Im Allgemeinen kann das Upgrade von etcd v3.5 auf v3.6 als Rolling Upgrade ohne Ausfallzeit erfolgen:

  • Die etcd-v3.5-Prozesse nacheinander stoppen und durch etcd-v3.6-Prozesse ersetzen.
  • Sobald alle v3.6-Prozesse laufen, stehen dem Cluster die neuen Funktionen von v3.6 zur Verfügung.

Lesen Sie zur Vorbereitung den Rest dieses Leitfadens, bevor Sie mit dem Upgrade beginnen .

Checklisten für das Upgrade

3.5 aktualisieren

Wichtig

Stellen Sie vor dem Upgrade auf 3.6 sicher, dass alle Ihre 3.5-Mitglieder auf 3.5.32 oder höher aktualisiert sind . Die Patch-Releases 3.5.24 bis 3.5.26 beheben mehrere mögliche Upgrade-Hindernisse; 3.5.32 ergänzt --v2-deprecation=write-only-skip-check und erweitert etcdutl check v2store um die Prüfung von WAL-Einträgen zusätzlich zum v2-Snapshot.

V2-Speicher

Hinweis

Wenn das Flag --enable-v2 nicht konfiguriert oder auf false gesetzt ist, sind keine weiteren Maßnahmen erforderlich.

Wenn --enable-v2 konfiguriert ist, führen Sie den Befehl etcdutl check v2store aus, um zu prüfen, ob der v2store Daten enthält, die nicht zur Mitgliedschaft gehören (benutzerdefinierte Daten). Sind keine benutzerdefinierten Daten vorhanden, kann das Flag gefahrlos entfernt werden. Andernfalls finden Sie weitere Einzelheiten im v2-Migrationsleitfaden .

Hinzugefügte Flags

+etcd --discovery-token ''
+etcd --discovery-endpoints ''
+etcd --discovery-dial-timeout '2s'
+etcd --discovery-request-timeout '5s'
+etcd --discovery-keepalive-time '2s'
+etcd --discovery-keepalive-timeout '6s'
+etcd --discovery-insecure-transport 'true'
+etcd --discovery-insecure-skip-tls-verify 'false'
+etcd --discovery-cert ''
+etcd --discovery-key ''
+etcd --discovery-cacert ''
+etcd --discovery-user ''
+etcd --discovery-password ''
+etcd --feature-gates
+etcd --log-format

Entfernte Flags

-etcd --enable-v2
-etcd --experimental-enable-v2v3
-etcd --proxy
-etcd --proxy-failure-wait
-etcd --proxy-refresh-interval
-etcd --proxy-dial-timeout
-etcd --proxy-write-timeout
-etcd --proxy-read-timeout

Veraltete Flags

Das Flag etcd --experimental-bootstrap-defrag-threshold-megabytes ist veraltet.


-etcd --experimental-bootstrap-defrag-threshold-megabytes

+etcd --bootstrap-defrag-threshold-megabytes

Das Flag etcd --experimental-compaction-batch-limit ist veraltet.


-etcd --experimental-compaction-batch-limit

+etcd --compaction-batch-limit

Das Flag etcd --experimental-compact-hash-check-time ist veraltet.


-etcd --experimental-compact-hash-check-time

+etcd --compact-hash-check-time

Das Flag etcd --experimental-compaction-sleep-interval ist veraltet.


-etcd --experimental-compaction-sleep-interval

+etcd --compaction-sleep-interval

Das Flag etcd --experimental-corrupt-check-time ist veraltet.


-etcd --experimental-corrupt-check-time

+etcd --corrupt-check-time

Das Flag etcd --experimental-enable-distributed-tracing ist veraltet.


-etcd --experimental-enable-distributed-tracing

+etcd --enable-distributed-tracing

Das Flag etcd --experimental-distributed-tracing-address ist veraltet.


-etcd --experimental-distributed-tracing-address

+etcd --distributed-tracing-address

Das Flag etcd --experimental-distributed-tracing-instance-id ist veraltet.


-etcd --experimental-distributed-tracing-instance-id

+etcd --distributed-tracing-instance-id

Das Flag etcd --experimental-distributed-tracing-sampling-rate ist veraltet.


-etcd --experimental-distributed-tracing-sampling-rate

+etcd --distributed-tracing-sampling-rate

Das Flag etcd --experimental-distributed-tracing-service-name ist veraltet.


-etcd --experimental-distributed-tracing-service-name

+etcd --distributed-tracing-service-name

Das Flag etcd --experimental-downgrade-check-time ist veraltet.


-etcd --experimental-downgrade-check-time

+etcd --downgrade-check-time

Das Flag etcd --experimental-max-learners ist veraltet.


-etcd --experimental-max-learners

+etcd --max-learners

Das Flag etcd --experimental-memory-mlock ist veraltet.


-etcd --experimental-memory-mlock

+etcd --memory-mlock

Das Flag etcd --experimental-peer-skip-client-san-verification ist veraltet.


-etcd --experimental-peer-skip-client-san-verification

+etcd --peer-skip-client-san-verification

Das Flag etcd --experimental-snapshot-catchup-entries ist veraltet.


-etcd --experimental-snapshot-catchup-entries

+etcd --snapshot-catchup-entries

Das Flag etcd --experimental-warning-apply-duration ist veraltet.


-etcd --experimental-warning-apply-duration

+etcd --warning-apply-duration

Das Flag etcd --experimental-warning-unary-request-duration ist veraltet.


-etcd --experimental-warning-unary-request-duration

+etcd --warning-unary-request-duration

Das Flag etcd --experimental-watch-progress-notify-interval ist veraltet.


-etcd --experimental-watch-progress-notify-interval

+etcd --watch-progress-notify-interval

Experimentelle v3.5-Flags durch Funktionsschalter ersetzen

Entsprechender Funktionsschalter für etcd --experimental-compact-hash-check-enabled=true


-etcd --experimental-compact-hash-check-enabled=true

+etcd --feature-gates=CompactHashCheck=true

Entsprechender Funktionsschalter für etcd --experimental-initial-corrupt-check=true


-etcd --experimental-initial-corrupt-check=true

+etcd --feature-gates=InitialCorruptCheck=true

Entsprechender Funktionsschalter für etcd --experimental-enable-lease-checkpoint=true


-etcd --experimental-enable-lease-checkpoint=true

+etcd --feature-gates=LeaseCheckpoint=true

Entsprechender Funktionsschalter für etcd --experimental-enable-lease-checkpoint-persist=true


-etcd --experimental-enable-lease-checkpoint-persist=true

+etcd --feature-gates=LeaseCheckpointPersist=true

Entsprechender Funktionsschalter für etcd --experimental-stop-grpc-service-on-defrag=true


-etcd --experimental-stop-grpc-service-on-defrag=true

+etcd --feature-gates=StopGRPCServiceOnDefrag=true

Entsprechender Funktionsschalter für etcd --experimental-txn-mode-write-with-shared-buffer=false


-etcd --experimental-txn-mode-write-with-shared-buffer=false

+etcd --feature-gates=TxnModeWriteWithSharedBuffer=false

Flags mit neuen Standardwerten

Ursprüngliches Standard-Flag etcd --snapshot-count=100000


-etcd --snapshot-count=100000

+etcd --snapshot-count=10000

Ursprüngliches Standard-Flag etcd --v2-deprecation='not-yet'


-etcd --v2-deprecation='not-yet'

+etcd --v2-deprecation='write-only'

Ursprüngliches Standard-Flag etcd --discovery-fallback='proxy'


-etcd --discovery-fallback='proxy'

+etcd --discovery-fallback='exit'

Unterschiede bei Prometheus-Metriken

# metrics added in v3.6
+etcd_network_known_peers
+etcd_server_feature_enabled

Checklisten für das Server-Upgrade

Upgrade-Voraussetzungen

Um eine bestehende etcd-Installation auf v3.6 zu aktualisieren, muss der laufende Cluster Version v3.5 oder höher verwenden. Falls er eine ältere Version als v3.5 verwendet, führen Sie vor dem Upgrade auf v3.6 zunächst ein Upgrade auf v3.5 durch.

Außerdem muss der laufende Cluster fehlerfrei sein, damit das Rolling Upgrade reibungslos verläuft. Prüfen Sie den Zustand des Clusters mit dem Befehl etcdctl endpoint health, bevor Sie fortfahren.

Vorbereitung

Testen Sie vor einem etcd-Upgrade immer die von etcd abhängigen Dienste in einer Staging-Umgebung, bevor Sie das Upgrade in der Produktionsumgebung durchführen.

Laden Sie vor Beginn das Snapshot-Backup herunter . Falls beim Upgrade etwas schiefgeht, können Sie mit diesem Backup ein Rollback auf die bestehende etcd-Version durchführen. Beachten Sie, dass der Befehl snapshot nur die v3-Daten sichert.

Gemischte Versionen

Während des Upgrades unterstützt ein etcd-Cluster Mitglieder mit gemischten etcd-Versionen und verwendet das Protokoll der niedrigsten gemeinsamen Version. Der Cluster gilt erst als aktualisiert, wenn alle Mitglieder auf Version v3.6 aktualisiert wurden. Intern handeln die etcd-Mitglieder untereinander die Gesamtversion des Clusters aus, die die gemeldete Version und die unterstützten Funktionen bestimmt.

Rollback

Erstellen Sie vor dem Upgrade Ihres etcd-Clusters ein Snapshot-Backup des Clusters und laden Sie es herunter . Mit diesem Snapshot lässt sich der Cluster bei Bedarf in seinen Zustand vor dem Upgrade zurückversetzen. Falls während des Upgrades Probleme auftreten, sollten Benutzer zunächst deren Ursache ermitteln und beheben. Solange sich der Cluster noch in einem Zustand mit gemischten Versionen befindet, also mindestens ein Mitglied weiterhin v3.5 verwendet, können sie entweder die Binärdatei oder das Image durch die alte Version v3.5 ersetzen oder den Cluster direkt aus dem Snapshot wiederherstellen. In diesem gemischten Zustand arbeitet der Cluster weiterhin als v3.5-Cluster, sodass ein Rollback ohne formelles Downgrade-Verfahren möglich ist.

Sobald jedoch alle Mitglieder auf v3.6 aktualisiert wurden, gilt der Cluster als vollständig aktualisiert. Der bloße Austausch der Binärdateien ist dann kein gültiges Rollback-Verfahren mehr. Für die Recovery kann entweder der vor dem Upgrade erstellte Snapshot wiederhergestellt oder der offizielle Downgrade-Leitfaden befolgt werden, um zur ursprünglichen Version zurückzukehren und dabei Konsistenz zu gewährleisten sowie Datenbeschädigungen zu vermeiden.

Upgrade-Verfahren

Dieses Beispiel zeigt das Upgrade eines etcd-v3.5-Clusters mit 3 Mitgliedern, der auf einem lokalen Rechner läuft.

Schritt 1: Upgrade-Voraussetzungen prüfen

Ist der Cluster fehlerfrei und läuft er mit v3.5.x?

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint health
<<COMMENT
localhost:2379 is healthy: successfully committed proposal: took = 2.555774ms
localhost:32379 is healthy: successfully committed proposal: took = 2.631133ms
localhost:22379 is healthy: successfully committed proposal: took = 3.020958ms
COMMENT

curl http://localhost:2379/version
<<COMMENT
{"etcdserver":"3.5.18","etcdcluster":"3.5.0"}
COMMENT

curl http://localhost:22379/version
<<COMMENT
{"etcdserver":"3.5.18","etcdcluster":"3.5.0"}
COMMENT

curl http://localhost:32379/version
<<COMMENT
{"etcdserver":"3.5.18","etcdcluster":"3.5.0"}
COMMENT

Schritt 2: Snapshot-Backup vom Leader herunterladen

Laden Sie das Snapshot-Backup herunter , um bei Problemen ein Downgrade durchführen zu können.

Der etcd-Leader enthält garantiert die neuesten Anwendungsdaten. Rufen Sie den Snapshot daher vom Leader ab:

curl -sL http://localhost:2379/metrics | grep etcd_server_is_leader
<<COMMENT
# HELP etcd_server_is_leader Whether or not this member is a leader. 1 if is, 0 otherwise.
# TYPE etcd_server_is_leader gauge
etcd_server_is_leader 1
COMMENT

curl -sL http://localhost:22379/metrics | grep etcd_server_is_leader
<<COMMENT
etcd_server_is_leader 0
COMMENT

curl -sL http://localhost:32379/metrics | grep etcd_server_is_leader
<<COMMENT
etcd_server_is_leader 0
COMMENT

etcdctl --endpoints=localhost:2379 snapshot save backup.db
<<COMMENT
{"level":"info","ts":"2025-03-01T04:34:10.336768+0530","caller":"snapshot/v3_snapshot.go:65","msg":"created temporary db file","path":"backup.db.part"}
{"level":"info","ts":"2025-03-01T04:34:10.342373+0530","logger":"client","caller":"v3@v3.5.18/maintenance.go:212","msg":"opened snapshot stream; downloading"}
{"level":"info","ts":"2025-03-01T04:34:10.342433+0530","caller":"snapshot/v3_snapshot.go:73","msg":"fetching snapshot","endpoint":"localhost:2379"}
{"level":"info","ts":"2025-03-01T04:34:10.346482+0530","logger":"client","caller":"v3@v3.5.18/maintenance.go:220","msg":"completed snapshot read; closing"}
{"level":"info","ts":"2025-03-01T04:34:10.348801+0530","caller":"snapshot/v3_snapshot.go:88","msg":"fetched snapshot","endpoint":"localhost:2379","size":"20 kB","took":"now"}
{"level":"info","ts":"2025-03-01T04:34:10.348933+0530","caller":"snapshot/v3_snapshot.go:97","msg":"saved","path":"backup.db"}
Snapshot saved at backup.db
COMMENT

Schritt 3: Einen bestehenden etcd-Server stoppen

Wenn ein etcd-Prozess gestoppt wird, protokollieren die anderen Cluster-Mitglieder erwartete Fehler. Dies ist normal, da die Verbindung zu einem Cluster-Mitglied (vorübergehend) unterbrochen wurde:

{"level":"info","ts":"2025-03-01T04:31:50.654520+0530","caller":"etcdserver/server.go:2676","msg":"cluster version is updated","cluster-version":"3.5"}
{"level":"info","ts":"2025-03-01T04:34:10.345927+0530","caller":"v3rpc/maintenance.go:130","msg":"sending database snapshot to client","total-bytes":20480,"size":"20 kB"}
{"level":"info","ts":"2025-03-01T04:34:10.346094+0530","caller":"v3rpc/maintenance.go:170","msg":"sending database sha256 checksum to client","total-bytes":20480,"checksum-size":32}
{"level":"info","ts":"2025-03-01T04:34:10.346108+0530","caller":"v3rpc/maintenance.go:179","msg":"successfully sent database snapshot to client","total-bytes":20480,"size":"20 kB","took":"now"}
^C
{"level":"info","ts":"2025-03-01T04:35:01.443045+0530","caller":"osutil/interrupt_unix.go:64","msg":"received signal; shutting down","signal":"interrupt"}
{"level":"info","ts":"2025-03-01T04:35:01.443088+0530","caller":"embed/etcd.go:408","msg":"closing etcd server","name":"node1","data-dir":"/tmp/etcd-node1","advertise-peer-urls":["http://127.0.0.1:2380"],"advertise-client-urls":["http://127.0.0.1:2379"]}
{"level":"info","ts":"2025-03-01T04:35:01.443417+0530","caller":"etcdserver/server.go:1503","msg":"leadership transfer starting","local-member-id":"bf9071f4639c75cc","current-leader-member-id":"bf9071f4639c75cc","transferee-member-id":"91bc3c398fb3c146"}
{"level":"info","ts":"2025-03-01T04:35:01.443441+0530","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"bf9071f4639c75cc [term 2] starts to transfer leadership to 91bc3c398fb3c146"}
{"level":"info","ts":"2025-03-01T04:35:01.443455+0530","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"bf9071f4639c75cc sends MsgTimeoutNow to 91bc3c398fb3c146 immediately as 91bc3c398fb3c146 already has up-to-date log"}
{"level":"warn","ts":"2025-03-01T04:35:01.443517+0530","caller":"embed/serve.go:179","msg":"stopping insecure grpc server due to error","error":"accept tcp 127.0.0.1:2379: use of closed network connection"}
{"level":"warn","ts":"2025-03-01T04:35:01.443548+0530","caller":"embed/serve.go:181","msg":"stopped insecure grpc server due to error","error":"accept tcp 127.0.0.1:2379: use of closed network connection"}
{"level":"info","ts":"2025-03-01T04:35:01.445536+0530","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"bf9071f4639c75cc [term: 2] received a MsgVote message with higher term from 91bc3c398fb3c146 [term: 3]"}
{"level":"info","ts":"2025-03-01T04:35:01.445556+0530","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"bf9071f4639c75cc became follower at term 3"}
{"level":"info","ts":"2025-03-01T04:35:01.445565+0530","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"bf9071f4639c75cc [logterm: 2, index: 12, vote: 0] cast MsgVote for 91bc3c398fb3c146 [logterm: 2, index: 12] at term 3"}
{"level":"info","ts":"2025-03-01T04:35:01.445572+0530","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"raft.node: bf9071f4639c75cc lost leader bf9071f4639c75cc at term 3"}
{"level":"info","ts":"2025-03-01T04:35:01.446773+0530","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"raft.node: bf9071f4639c75cc elected leader 91bc3c398fb3c146 at term 3"}
{"level":"info","ts":"2025-03-01T04:35:01.544062+0530","caller":"etcdserver/server.go:1520","msg":"leadership transfer finished","local-member-id":"bf9071f4639c75cc","old-leader-member-id":"bf9071f4639c75cc","new-leader-member-id":"91bc3c398fb3c146","took":"100.640374ms"}
{"level":"info","ts":"2025-03-01T04:35:01.544160+0530","caller":"rafthttp/peer.go:330","msg":"stopping remote peer","remote-peer-id":"91bc3c398fb3c146"}
{"level":"warn","ts":"2025-03-01T04:35:01.544956+0530","caller":"rafthttp/stream.go:286","msg":"closed TCP streaming connection with remote peer","stream-writer-type":"stream MsgApp v2","remote-peer-id":"91bc3c398fb3c146"}
{"level":"info","ts":"2025-03-01T04:35:01.544984+0530","caller":"rafthttp/stream.go:294","msg":"stopped TCP streaming connection with remote peer","stream-writer-type":"stream MsgApp v2","remote-peer-id":"91bc3c398fb3c146"}
{"level":"warn","ts":"2025-03-01T04:35:01.545050+0530","caller":"rafthttp/stream.go:286","msg":"closed TCP streaming connection with remote peer","stream-writer-type":"stream Message","remote-peer-id":"91bc3c398fb3c146"}
{"level":"info","ts":"2025-03-01T04:35:01.545065+0530","caller":"rafthttp/stream.go:294","msg":"stopped TCP streaming connection with remote peer","stream-writer-type":"stream Message","remote-peer-id":"91bc3c398fb3c146"}
{"level":"info","ts":"2025-03-01T04:35:01.545099+0530","caller":"rafthttp/pipeline.go:85","msg":"stopped HTTP pipelining with remote peer","local-member-id":"bf9071f4639c75cc","remote-peer-id":"91bc3c398fb3c146"}
{"level":"warn","ts":"2025-03-01T04:35:01.545156+0530","caller":"rafthttp/stream.go:421","msg":"lost TCP streaming connection with remote peer","stream-reader-type":"stream MsgApp v2","local-member-id":"bf9071f4639c75cc","remote-peer-id":"91bc3c398fb3c146","error":"context canceled"}
{"level":"warn","ts":"2025-03-01T04:35:01.545178+0530","caller":"rafthttp/peer_status.go:66","msg":"peer became inactive (message send to peer failed)","peer-id":"91bc3c398fb3c146","error":"failed to read 91bc3c398fb3c146 on stream MsgApp v2 (context canceled)"}
{"level":"info","ts":"2025-03-01T04:35:01.545199+0530","caller":"rafthttp/stream.go:442","msg":"stopped stream reader with remote peer","stream-reader-type":"stream MsgApp v2","local-member-id":"bf9071f4639c75cc","remote-peer-id":"91bc3c398fb3c146"}
{"level":"warn","ts":"2025-03-01T04:35:01.545246+0530","caller":"rafthttp/stream.go:421","msg":"lost TCP streaming connection with remote peer","stream-reader-type":"stream Message","local-member-id":"bf9071f4639c75cc","remote-peer-id":"91bc3c398fb3c146","error":"context canceled"}
{"level":"info","ts":"2025-03-01T04:35:01.545263+0530","caller":"rafthttp/stream.go:442","msg":"stopped stream reader with remote peer","stream-reader-type":"stream Message","local-member-id":"bf9071f4639c75cc","remote-peer-id":"91bc3c398fb3c146"}
{"level":"info","ts":"2025-03-01T04:35:01.545272+0530","caller":"rafthttp/peer.go:335","msg":"stopped remote peer","remote-peer-id":"91bc3c398fb3c146"}
{"level":"info","ts":"2025-03-01T04:35:01.545282+0530","caller":"rafthttp/peer.go:330","msg":"stopping remote peer","remote-peer-id":"fd422379fda50e48"}
{"level":"warn","ts":"2025-03-01T04:35:01.545307+0530","caller":"rafthttp/stream.go:286","msg":"closed TCP streaming connection with remote peer","stream-writer-type":"stream MsgApp v2","remote-peer-id":"fd422379fda50e48"}
{"level":"info","ts":"2025-03-01T04:35:01.545328+0530","caller":"rafthttp/stream.go:294","msg":"stopped TCP streaming connection with remote peer","stream-writer-type":"stream MsgApp v2","remote-peer-id":"fd422379fda50e48"}
{"level":"warn","ts":"2025-03-01T04:35:01.545359+0530","caller":"rafthttp/stream.go:286","msg":"closed TCP streaming connection with remote peer","stream-writer-type":"stream Message","remote-peer-id":"fd422379fda50e48"}
{"level":"info","ts":"2025-03-01T04:35:01.545379+0530","caller":"rafthttp/stream.go:294","msg":"stopped TCP streaming connection with remote peer","stream-writer-type":"stream Message","remote-peer-id":"fd422379fda50e48"}
{"level":"info","ts":"2025-03-01T04:35:01.545410+0530","caller":"rafthttp/pipeline.go:85","msg":"stopped HTTP pipelining with remote peer","local-member-id":"bf9071f4639c75cc","remote-peer-id":"fd422379fda50e48"}
{"level":"warn","ts":"2025-03-01T04:35:01.545467+0530","caller":"rafthttp/stream.go:421","msg":"lost TCP streaming connection with remote peer","stream-reader-type":"stream MsgApp v2","local-member-id":"bf9071f4639c75cc","remote-peer-id":"fd422379fda50e48","error":"context canceled"}
{"level":"warn","ts":"2025-03-01T04:35:01.545485+0530","caller":"rafthttp/peer_status.go:66","msg":"peer became inactive (message send to peer failed)","peer-id":"fd422379fda50e48","error":"failed to read fd422379fda50e48 on stream MsgApp v2 (context canceled)"}
{"level":"info","ts":"2025-03-01T04:35:01.545504+0530","caller":"rafthttp/stream.go:442","msg":"stopped stream reader with remote peer","stream-reader-type":"stream MsgApp v2","local-member-id":"bf9071f4639c75cc","remote-peer-id":"fd422379fda50e48"}
{"level":"warn","ts":"2025-03-01T04:35:01.545560+0530","caller":"rafthttp/stream.go:421","msg":"lost TCP streaming connection with remote peer","stream-reader-type":"stream Message","local-member-id":"bf9071f4639c75cc","remote-peer-id":"fd422379fda50e48","error":"context canceled"}
{"level":"info","ts":"2025-03-01T04:35:01.545577+0530","caller":"rafthttp/stream.go:442","msg":"stopped stream reader with remote peer","stream-reader-type":"stream Message","local-member-id":"bf9071f4639c75cc","remote-peer-id":"fd422379fda50e48"}
{"level":"info","ts":"2025-03-01T04:35:01.545592+0530","caller":"rafthttp/peer.go:335","msg":"stopped remote peer","remote-peer-id":"fd422379fda50e48"}
{"level":"warn","ts":"2025-03-01T04:35:01.545669+0530","caller":"rafthttp/http.go:413","msg":"failed to find remote peer in cluster","local-member-id":"bf9071f4639c75cc","remote-peer-id-stream-handler":"bf9071f4639c75cc","remote-peer-id-from":"91bc3c398fb3c146","cluster-id":"59a05384c9b79ee"}
{"level":"warn","ts":"2025-03-01T04:35:01.545698+0530","caller":"rafthttp/http.go:413","msg":"failed to find remote peer in cluster","local-member-id":"bf9071f4639c75cc","remote-peer-id-stream-handler":"bf9071f4639c75cc","remote-peer-id-from":"fd422379fda50e48","cluster-id":"59a05384c9b79ee"}
{"level":"warn","ts":"2025-03-01T04:35:01.545732+0530","caller":"rafthttp/http.go:413","msg":"failed to find remote peer in cluster","local-member-id":"bf9071f4639c75cc","remote-peer-id-stream-handler":"bf9071f4639c75cc","remote-peer-id-from":"91bc3c398fb3c146","cluster-id":"59a05384c9b79ee"}
{"level":"warn","ts":"2025-03-01T04:35:01.545765+0530","caller":"rafthttp/http.go:413","msg":"failed to find remote peer in cluster","local-member-id":"bf9071f4639c75cc","remote-peer-id-stream-handler":"bf9071f4639c75cc","remote-peer-id-from":"fd422379fda50e48","cluster-id":"59a05384c9b79ee"}
{"level":"info","ts":"2025-03-01T04:35:01.549658+0530","caller":"embed/etcd.go:613","msg":"stopping serving peer traffic","address":"127.0.0.1:2380"}
{"level":"info","ts":"2025-03-01T04:35:02.550532+0530","caller":"embed/etcd.go:618","msg":"stopped serving peer traffic","address":"127.0.0.1:2380"}
{"level":"info","ts":"2025-03-01T04:35:02.550561+0530","caller":"embed/etcd.go:410","msg":"closed etcd server","name":"node1","data-dir":"/tmp/etcd-node1","advertise-peer-urls":["http://127.0.0.1:2380"],"advertise-client-urls":["http://127.0.0.1:2379"]}

Schritt 4: Den etcd-Server mit derselben Konfiguration neu starten

Starten Sie den etcd-Server mit derselben Konfiguration, aber mit der neuen etcd-Binärdatei neu.

-etcd-old --name ${name} \
+etcd-new --name ${name} \
  --data-dir /path/to/${name}.etcd \
  --listen-client-urls http://localhost:2379 \
  --advertise-client-urls http://localhost:2379 \
  --listen-peer-urls http://localhost:2380 \
  --initial-advertise-peer-urls http://localhost:2380 \
  --initial-cluster s1=http://localhost:2380,s2=http://localhost:22380,s3=http://localhost:32380 \
  --initial-cluster-token tkn \
  --initial-cluster-state new

Das neue etcd v3.6 veröffentlicht seine Informationen im Cluster. Zu diesem Zeitpunkt verwendet der Cluster weiterhin das Protokoll von v3.5, der niedrigsten gemeinsamen Version.

{"level":"info","ts":"2025-03-01T04:40:36.828+0530","caller":"api/capability.go:76","msg":"enabled capabilities for version","cluster-version":"3.5"}

{"level":"info","ts":"2025-03-01T04:40:36.889+0530","caller":"membership/cluster.go:539","msg":"updated cluster version","cluster-id":"59a05384c9b79ee","local-member-id":"bf9071f4639c75cc","from":"3.0","to":"3.5"}

{"level":"info","ts":"2025-03-01T04:40:36.828+0530","caller":"api/capability.go:76","msg":"enabled capabilities for version","cluster-version":"3.5"}

{"level":"info","ts":"2025-03-01T04:40:36.894+0530","caller":"etcdserver/server.go:1686","msg":"published local member to cluster through raft","local-member-id":"bf9071f4639c75cc","local-member-attributes":"{Name:node1 ClientURLs:[http://127.0.0.1:2379]}","cluster-id":"59a05384c9b79ee","publish-timeout":"7s"}

Prüfen Sie, ob jedes Mitglied und anschließend der gesamte Cluster mit der neuen etcd-v3.6-Binärdatei wieder fehlerfrei ist:

etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
<<COMMENT
localhost:2379 is healthy: successfully committed proposal: took = 1.704998ms
localhost:22379 is healthy: successfully committed proposal: took = 2.331754ms
localhost:32379 is healthy: successfully committed proposal: took = 2.490705ms
COMMENT

Noch nicht aktualisierte Mitglieder protokollieren Warnungen wie die folgenden, bis der gesamte Cluster aktualisiert wurde.

Dies ist zu erwarten und endet, sobald alle etcd-Cluster-Mitglieder auf v3.6 aktualisiert wurden:

{"level":"warn","ts":"2025-03-01T04:40:37.545960+0530","caller":"etcdserver/cluster_util.go:189","msg":"leader found higher-versioned member","local-member-version":"3.5.18","remote-member-id":"bf9071f4639c75cc","remote-member-version":"3.6.0-alpha.0"}

Schritt 5: Schritt 3 und Schritt 4 für die übrigen Mitglieder wiederholen

Sobald alle Mitglieder aktualisiert wurden, meldet der Cluster den erfolgreichen Abschluss des Upgrades auf v3.6:

Mitglied 1:

{"level":"info","ts":"2025-03-01T04:58:32.375+0530","caller":"etcdserver/server.go:2149","msg":"updating cluster version using v3 API","from":"3.5","to":"3.6"} {"level":"info","ts":"2025-03-01T04:58:32.377+0530","caller":"etcdserver/server.go:2164","msg":"cluster version is updated","cluster-version":"3.6"}

Mitglied 2:

{"level":"info","ts":"2025-03-01T04:58:32.377+0530","caller":"membership/cluster.go:539","msg":"updated cluster version","cluster-id":"59a05384c9b79ee","local-member-id":"91bc3c398fb3c146","from":"3.5","to":"3.6"}

Mitglied 3:

{"level":"info","ts":"2025-03-01T04:58:32.377+0530","caller":"membership/cluster.go:539","msg":"updated cluster version","cluster-id":"59a05384c9b79ee","local-member-id":"fd422379fda50e48","from":"3.5","to":"3.6"}

endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
<<COMMENT
localhost:2379 is healthy: successfully committed proposal: took = 492.834µs
localhost:22379 is healthy: successfully committed proposal: took = 1.015025ms
localhost:32379 is healthy: successfully committed proposal: took = 1.853077ms
COMMENT

curl http://localhost:2379/version
<<COMMENT
{"etcdserver":"3.6.0-alpha.0","etcdcluster":"3.6.0"}
COMMENT

curl http://localhost:22379/version
<<COMMENT
{"etcdserver":"3.6.0-alpha.0","etcdcluster":"3.6.0"}
COMMENT

curl http://localhost:32379/version
<<COMMENT
{"etcdserver":"3.6.0-alpha.0","etcdcluster":"3.6.0"}
COMMENT

17.4 - Upgrade von etcd 3.4 auf 3.5

Verfahren, Checklisten und Hinweise zum Upgrade von etcd 3.4 auf 3.5

Im Allgemeinen kann das Upgrade von etcd 3.4 auf 3.5 als Rolling Upgrade ohne Ausfallzeit erfolgen:

  • Die etcd-v3.4-Prozesse nacheinander stoppen und durch etcd-v3.5-Prozesse ersetzen.
  • Sobald alle v3.5-Prozesse laufen, stehen dem Cluster die neuen Funktionen von v3.5 zur Verfügung.

Lesen Sie zur Vorbereitung den Rest dieses Leitfadens, bevor Sie mit dem Upgrade beginnen .

Checklisten für das Upgrade

Warnung

Bei der Migration von v2 ohne v3-Daten löst der etcd-Server v3.2+ eine Panic aus, wenn etcd aus vorhandenen Snapshots wiederhergestellt wird, aber keine v3-Datei ETCD_DATA_DIR/member/snap/db vorhanden ist. Dies tritt auf, wenn der Server von v2 migriert wurde, ohne zuvor v3-Daten zu enthalten. Dadurch wird auch ein versehentlicher Verlust von v3-Daten verhindert (z. B. könnte die Datei db verschoben worden sein). etcd verlangt, dass weitere Migrationen nach der Migration auf v3 nur mit v3-Daten erfolgen können. Führen Sie kein Upgrade auf neuere v3-Versionen durch, bevor der v3.0-Server v3-Daten enthält.

Warnung

Wenn in Ihrem Cluster die Authentifizierung aktiviert ist, wird ein Rolling Upgrade von 3.4 oder einer älteren Version nicht unterstützt, da 3.5 ein Format von WAL-Einträgen zur Authentifizierung ändert .

Wichtige inkompatible Änderungen in 3.5.

Veraltete Prometheus-Metrik etcd_debugging_mvcc_db_total_size_in_bytes

v3.5 hat die Prometheus-Metrik etcd_debugging_mvcc_db_total_size_in_bytes in etcd_mvcc_db_total_size_in_bytes überführt, um die Überwachung des etcd-Speichers zu fördern. Außerdem stuft v3.5 etcd_debugging_mvcc_db_total_size_in_bytes vollständig als veraltet ein.

-etcd_debugging_mvcc_db_total_size_in_bytes
+etcd_mvcc_db_total_size_in_bytes

Beachten Sie, dass Metriken im Namensraum etcd_debugging_* als experimentell gekennzeichnet sind. Im Zuge der Verbesserung des Überwachungsleitfadens können wir weitere Metriken hochstufen.

Veraltete Prometheus-Metrik etcd_debugging_mvcc_put_total

v3.5 hat die Prometheus-Metrik etcd_debugging_mvcc_put_total in etcd_mvcc_put_total überführt, um die Überwachung des etcd-Speichers zu fördern. Außerdem stuft v3.5 etcd_debugging_mvcc_put_total vollständig als veraltet ein.

-etcd_debugging_mvcc_put_total
+etcd_mvcc_put_total

Beachten Sie, dass Metriken im Namensraum etcd_debugging_* als experimentell gekennzeichnet sind. Im Zuge der Verbesserung des Überwachungsleitfadens können wir weitere Metriken hochstufen.

Veraltete Prometheus-Metrik etcd_debugging_mvcc_delete_total

v3.5 hat die Prometheus-Metrik etcd_debugging_mvcc_delete_total in etcd_mvcc_delete_total überführt, um die Überwachung des etcd-Speichers zu fördern. Außerdem stuft v3.5 etcd_debugging_mvcc_delete_total vollständig als veraltet ein.

-etcd_debugging_mvcc_delete_total
+etcd_mvcc_delete_total

Beachten Sie, dass Metriken im Namensraum etcd_debugging_* als experimentell gekennzeichnet sind. Im Zuge der Verbesserung des Überwachungsleitfadens können wir weitere Metriken hochstufen.

Veraltete Prometheus-Metrik etcd_debugging_mvcc_txn_total

v3.5 hat die Prometheus-Metrik etcd_debugging_mvcc_txn_total in etcd_mvcc_txn_total überführt, um die Überwachung des etcd-Speichers zu fördern. Außerdem stuft v3.5 etcd_debugging_mvcc_txn_total vollständig als veraltet ein.

-etcd_debugging_mvcc_txn_total
+etcd_mvcc_txn_total

Beachten Sie, dass Metriken im Namensraum etcd_debugging_* als experimentell gekennzeichnet sind. Im Zuge der Verbesserung des Überwachungsleitfadens können wir weitere Metriken hochstufen.

Veraltete Prometheus-Metrik etcd_debugging_mvcc_range_total

v3.5 hat die Prometheus-Metrik etcd_debugging_mvcc_range_total in etcd_mvcc_range_total überführt, um die Überwachung des etcd-Speichers zu fördern. Außerdem stuft v3.5 etcd_debugging_mvcc_range_total vollständig als veraltet ein.

-etcd_debugging_mvcc_range_total
+etcd_mvcc_range_total

Beachten Sie, dass Metriken im Namensraum etcd_debugging_* als experimentell gekennzeichnet sind. Im Zuge der Verbesserung des Überwachungsleitfadens können wir weitere Metriken hochstufen.

etcd --logger capnslog ist veraltet

v3.5 verwendet standardmäßig --logger=zap, um mehrere Protokollausgaben und strukturierte Protokollierung zu unterstützen.

etcd --logger=capnslog ist seit v3.5 veraltet, und jetzt ist --logger=zap der Standard.

-etcd --logger=capnslog
+etcd --logger=zap --log-outputs=stderr

+# to write logs to stderr and a.log file at the same time
+etcd --logger=zap --log-outputs=stderr,a.log

v3.4 unterstützt zusätzlich etcd --logger=zap für strukturierte Protokollierung und mehrere Protokollausgaben. Das Hauptziel ist, die automatisierte Überwachung von etcd zu fördern, statt erst bei auftretenden Fehlern die Serverprotokolle durchzusehen. Die künftige Entwicklung soll die Protokollausgabe von etcd auf ein Minimum reduzieren und die Überwachung mit Metriken und Alarmen erleichtern. etcd --logger=capnslog wird in v3.5 als veraltet eingestuft.

etcd --log-output ist veraltet

v3.4 hat etcd --log-output in --log-outputs umbenannt , um mehrere Protokollausgaben zu unterstützen.

etcd --log-output ist seit v3.5 veraltet.

-etcd --log-output=stderr
+etcd --log-outputs=stderr

Veraltetes Flag etcd --debug (jetzt --log-level=debug)

Das Flag etcd --debug ist veraltet.

-etcd --debug
+etcd --log-level debug

etcd --log-package-levels ist veraltet

Das Flag etcd --log-package-levels für capnslog ist veraltet.

Jetzt ist etcd --logger=zap der Standard.

-etcd --log-package-levels 'etcdmain=CRITICAL,etcdserver=DEBUG'
+etcd --logger=zap --log-outputs=stderr

[CLIENT-URL]/config/local/log ist veraltet

Der Endpunkt /config/local/log wird in v3.5 als veraltet eingestuft, ebenso das Flag etcd --log-package-levels.

-$ curl http://127.0.0.1:2379/config/local/log -XPUT -d '{"Level":"DEBUG"}'
-# debug logging enabled

Geänderte HTTP-Endpunkte des gRPC-Gateways (/v3beta ist veraltet)

Vorher

curl -L http://localhost:2379/v3beta/kv/put \
  -X POST -d '{"key": "Zm9v", "value": "YmFy"}'

Nachher

curl -L http://localhost:2379/v3/kv/put \
  -X POST -d '{"key": "Zm9v", "value": "YmFy"}'

/v3beta wurde im Release 3.5 entfernt.

Checklisten für das Server-Upgrade

Upgrade-Voraussetzungen

Um eine bestehende etcd-Installation auf 3.5 zu aktualisieren, muss der laufende Cluster Version 3.4 oder höher verwenden. Falls er eine ältere Version als 3.4 verwendet, führen Sie vor dem Upgrade auf 3.5 zunächst ein Upgrade auf 3.4 durch.

Außerdem muss der laufende Cluster fehlerfrei sein, damit das Rolling Upgrade reibungslos verläuft. Prüfen Sie den Zustand des Clusters mit dem Befehl etcdctl endpoint health, bevor Sie fortfahren.

Vorbereitung

Testen Sie vor einem etcd-Upgrade immer die von etcd abhängigen Dienste in einer Staging-Umgebung, bevor Sie das Upgrade in der Produktionsumgebung durchführen.

Laden Sie vor Beginn das Snapshot-Backup herunter . Falls beim Upgrade etwas schiefgeht, können Sie mit diesem Backup ein Downgrade auf die bestehende etcd-Version durchführen. Beachten Sie, dass der Befehl snapshot nur die v3-Daten sichert. Informationen zu v2-Daten finden Sie unter Backup des v2-Datenspeichers .

Gemischte Versionen

Während des Upgrades unterstützt ein etcd-Cluster Mitglieder mit gemischten etcd-Versionen und verwendet das Protokoll der niedrigsten gemeinsamen Version. Der Cluster gilt erst als aktualisiert, wenn alle Mitglieder auf Version 3.5 aktualisiert wurden. Intern handeln die etcd-Mitglieder untereinander die Gesamtversion des Clusters aus, die die gemeldete Version und die unterstützten Funktionen bestimmt.

Einschränkungen

Hinweis: Wenn der Cluster nur v3-Daten und keine v2-Daten enthält, gilt diese Einschränkung nicht.

Wenn der Cluster einen v2-Datenbestand von mehr als 50MB bereitstellt, kann es bis zu zwei Minuten dauern, bis jedes neu aktualisierte Mitglied zum bestehenden Cluster aufgeschlossen hat. Prüfen Sie die Größe eines aktuellen Snapshots, um die Gesamtdatenmenge abzuschätzen. Anders ausgedrückt ist es am sichersten, zwischen den Upgrades der einzelnen Mitglieder jeweils 2 Minuten zu warten.

Bei einer deutlich größeren Gesamtdatenmenge von 100MB oder mehr kann dieser einmalige Vorgang noch länger dauern. Administratoren sehr großer etcd-Cluster dieser Größenordnung können vor dem Upgrade das etcd-Team kontaktieren; wir beraten Sie gern zum Vorgehen.

Downgrade

Wenn alle Mitglieder auf v3.5 aktualisiert wurden, wird der Cluster auf v3.5 aktualisiert; ein Downgrade aus diesem abgeschlossenen Zustand ist nicht möglich. Solange jedoch noch ein einziges Mitglied v3.4 verwendet, bleiben der Cluster und sein Betrieb auf „v3.4“. Aus diesem Zustand mit gemischten Versionen ist es möglich, auf allen Mitgliedern wieder eine etcd-v3.4-Binärdatei zu verwenden.

Laden Sie das Snapshot-Backup herunter , um ein Downgrade des Clusters auch nach einem vollständig abgeschlossenen Upgrade zu ermöglichen.

Upgrade-Verfahren

Dieses Beispiel zeigt das Upgrade eines etcd-v3.4-Clusters mit 3 Mitgliedern, der auf einem lokalen Rechner läuft.

Schritt 1: Upgrade-Voraussetzungen prüfen

Ist der Cluster fehlerfrei und läuft er mit v3.4.x?

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint health
<<COMMENT
localhost:2379 is healthy: successfully committed proposal: took = 2.118638ms
localhost:22379 is healthy: successfully committed proposal: took = 3.631388ms
localhost:32379 is healthy: successfully committed proposal: took = 2.157051ms
COMMENT

curl http://localhost:2379/version
<<COMMENT
{"etcdserver":"3.4.0","etcdcluster":"3.4.0"}
COMMENT

curl http://localhost:22379/version
<<COMMENT
{"etcdserver":"3.4.0","etcdcluster":"3.4.0"}
COMMENT

curl http://localhost:32379/version
<<COMMENT
{"etcdserver":"3.4.0","etcdcluster":"3.4.0"}
COMMENT

Schritt 2: Snapshot-Backup vom Leader herunterladen

Laden Sie das Snapshot-Backup herunter , um bei Problemen ein Downgrade durchführen zu können.

Der etcd-Leader enthält garantiert die neuesten Anwendungsdaten. Rufen Sie den Snapshot daher vom Leader ab:

curl -sL http://localhost:2379/metrics | grep etcd_server_is_leader
<<COMMENT
# HELP etcd_server_is_leader Whether or not this member is a leader. 1 if is, 0 otherwise.
# TYPE etcd_server_is_leader gauge
etcd_server_is_leader 1
COMMENT

curl -sL http://localhost:22379/metrics | grep etcd_server_is_leader
<<COMMENT
etcd_server_is_leader 0
COMMENT

curl -sL http://localhost:32379/metrics | grep etcd_server_is_leader
<<COMMENT
etcd_server_is_leader 0
COMMENT

etcdctl --endpoints=localhost:2379 snapshot save backup.db
<<COMMENT
{"level":"info","ts":1526585787.148433,"caller":"snapshot/v3_snapshot.go:109","msg":"created temporary db file","path":"backup.db.part"}
{"level":"info","ts":1526585787.1485257,"caller":"snapshot/v3_snapshot.go:120","msg":"fetching snapshot","endpoint":"localhost:2379"}
{"level":"info","ts":1526585787.1519694,"caller":"snapshot/v3_snapshot.go:133","msg":"fetched snapshot","endpoint":"localhost:2379","took":0.003502721}
{"level":"info","ts":1526585787.1520295,"caller":"snapshot/v3_snapshot.go:142","msg":"saved","path":"backup.db"}
Snapshot saved at backup.db
COMMENT

Schritt 3: Einen bestehenden etcd-Server stoppen

Wenn ein etcd-Prozess gestoppt wird, protokollieren die anderen Cluster-Mitglieder erwartete Fehler. Dies ist normal, da die Verbindung zu einem Cluster-Mitglied (vorübergehend) unterbrochen wurde:

{"level":"info","ts":1526587281.2001143,"caller":"etcdserver/server.go:2249","msg":"updating cluster version","from":"3.0","to":"3.4"}
{"level":"info","ts":1526587281.2010646,"caller":"membership/cluster.go:473","msg":"updated cluster version","cluster-id":"7dee9ba76d59ed53","local-member-id":"7339c4e5e833c029","from":"3.0","from":"3.4"}
{"level":"info","ts":1526587281.2012327,"caller":"api/capability.go:76","msg":"enabled capabilities for version","cluster-version":"3.4"}
{"level":"info","ts":1526587281.2013083,"caller":"etcdserver/server.go:2272","msg":"cluster version is updated","cluster-version":"3.4"}



^C{"level":"info","ts":1526587299.0717514,"caller":"osutil/interrupt_unix.go:63","msg":"received signal; shutting down","signal":"interrupt"}
{"level":"info","ts":1526587299.0718873,"caller":"embed/etcd.go:285","msg":"closing etcd server","name":"s1","data-dir":"/tmp/etcd/s1","advertise-peer-urls":["http://localhost:2380"],"advertise-client-urls":["http://localhost:2379"]}
{"level":"info","ts":1526587299.0722554,"caller":"etcdserver/server.go:1341","msg":"leadership transfer starting","local-member-id":"7339c4e5e833c029","current-leader-member-id":"7339c4e5e833c029","transferee-member-id":"729934363faa4a24"}
{"level":"info","ts":1526587299.0723994,"caller":"raft/raft.go:1107","msg":"7339c4e5e833c029 [term 3] starts to transfer leadership to 729934363faa4a24"}
{"level":"info","ts":1526587299.0724802,"caller":"raft/raft.go:1113","msg":"7339c4e5e833c029 sends MsgTimeoutNow to 729934363faa4a24 immediately as 729934363faa4a24 already has up-to-date log"}
{"level":"info","ts":1526587299.0737045,"caller":"raft/raft.go:797","msg":"7339c4e5e833c029 [term: 3] received a MsgVote message with higher term from 729934363faa4a24 [term: 4]"}
{"level":"info","ts":1526587299.0737681,"caller":"raft/raft.go:656","msg":"7339c4e5e833c029 became follower at term 4"}
{"level":"info","ts":1526587299.073831,"caller":"raft/raft.go:882","msg":"7339c4e5e833c029 [logterm: 3, index: 9, vote: 0] cast MsgVote for 729934363faa4a24 [logterm: 3, index: 9] at term 4"}
{"level":"info","ts":1526587299.0738947,"caller":"raft/node.go:312","msg":"raft.node: 7339c4e5e833c029 lost leader 7339c4e5e833c029 at term 4"}
{"level":"info","ts":1526587299.0748374,"caller":"raft/node.go:306","msg":"raft.node: 7339c4e5e833c029 elected leader 729934363faa4a24 at term 4"}
{"level":"info","ts":1526587299.1726425,"caller":"etcdserver/server.go:1362","msg":"leadership transfer finished","local-member-id":"7339c4e5e833c029","old-leader-member-id":"7339c4e5e833c029","new-leader-member-id":"729934363faa4a24","took":0.100389359}
{"level":"info","ts":1526587299.1728148,"caller":"rafthttp/peer.go:333","msg":"stopping remote peer","remote-peer-id":"b548c2511513015"}
{"level":"warn","ts":1526587299.1751974,"caller":"rafthttp/stream.go:291","msg":"closed TCP streaming connection with remote peer","stream-writer-type":"stream MsgApp v2","remote-peer-id":"b548c2511513015"}
{"level":"warn","ts":1526587299.1752589,"caller":"rafthttp/stream.go:301","msg":"stopped TCP streaming connection with remote peer","stream-writer-type":"stream MsgApp v2","remote-peer-id":"b548c2511513015"}
{"level":"warn","ts":1526587299.177348,"caller":"rafthttp/stream.go:291","msg":"closed TCP streaming connection with remote peer","stream-writer-type":"stream Message","remote-peer-id":"b548c2511513015"}
{"level":"warn","ts":1526587299.1774004,"caller":"rafthttp/stream.go:301","msg":"stopped TCP streaming connection with remote peer","stream-writer-type":"stream Message","remote-peer-id":"b548c2511513015"}
{"level":"info","ts":1526587299.177515,"caller":"rafthttp/pipeline.go:86","msg":"stopped HTTP pipelining with remote peer","local-member-id":"7339c4e5e833c029","remote-peer-id":"b548c2511513015"}
{"level":"warn","ts":1526587299.1777067,"caller":"rafthttp/stream.go:436","msg":"lost TCP streaming connection with remote peer","stream-reader-type":"stream MsgApp v2","local-member-id":"7339c4e5e833c029","remote-peer-id":"b548c2511513015","error":"read tcp 127.0.0.1:34636->127.0.0.1:32380: use of closed network connection"}
{"level":"info","ts":1526587299.1778402,"caller":"rafthttp/stream.go:459","msg":"stopped stream reader with remote peer","stream-reader-type":"stream MsgApp v2","local-member-id":"7339c4e5e833c029","remote-peer-id":"b548c2511513015"}
{"level":"warn","ts":1526587299.1780295,"caller":"rafthttp/stream.go:436","msg":"lost TCP streaming connection with remote peer","stream-reader-type":"stream Message","local-member-id":"7339c4e5e833c029","remote-peer-id":"b548c2511513015","error":"read tcp 127.0.0.1:34634->127.0.0.1:32380: use of closed network connection"}
{"level":"info","ts":1526587299.1780987,"caller":"rafthttp/stream.go:459","msg":"stopped stream reader with remote peer","stream-reader-type":"stream Message","local-member-id":"7339c4e5e833c029","remote-peer-id":"b548c2511513015"}
{"level":"info","ts":1526587299.1781602,"caller":"rafthttp/peer.go:340","msg":"stopped remote peer","remote-peer-id":"b548c2511513015"}
{"level":"info","ts":1526587299.1781986,"caller":"rafthttp/peer.go:333","msg":"stopping remote peer","remote-peer-id":"729934363faa4a24"}
{"level":"warn","ts":1526587299.1802843,"caller":"rafthttp/stream.go:291","msg":"closed TCP streaming connection with remote peer","stream-writer-type":"stream MsgApp v2","remote-peer-id":"729934363faa4a24"}
{"level":"warn","ts":1526587299.1803446,"caller":"rafthttp/stream.go:301","msg":"stopped TCP streaming connection with remote peer","stream-writer-type":"stream MsgApp v2","remote-peer-id":"729934363faa4a24"}
{"level":"warn","ts":1526587299.1824749,"caller":"rafthttp/stream.go:291","msg":"closed TCP streaming connection with remote peer","stream-writer-type":"stream Message","remote-peer-id":"729934363faa4a24"}
{"level":"warn","ts":1526587299.18255,"caller":"rafthttp/stream.go:301","msg":"stopped TCP streaming connection with remote peer","stream-writer-type":"stream Message","remote-peer-id":"729934363faa4a24"}
{"level":"info","ts":1526587299.18261,"caller":"rafthttp/pipeline.go:86","msg":"stopped HTTP pipelining with remote peer","local-member-id":"7339c4e5e833c029","remote-peer-id":"729934363faa4a24"}
{"level":"warn","ts":1526587299.1827736,"caller":"rafthttp/stream.go:436","msg":"lost TCP streaming connection with remote peer","stream-reader-type":"stream MsgApp v2","local-member-id":"7339c4e5e833c029","remote-peer-id":"729934363faa4a24","error":"read tcp 127.0.0.1:51482->127.0.0.1:22380: use of closed network connection"}
{"level":"info","ts":1526587299.182845,"caller":"rafthttp/stream.go:459","msg":"stopped stream reader with remote peer","stream-reader-type":"stream MsgApp v2","local-member-id":"7339c4e5e833c029","remote-peer-id":"729934363faa4a24"}
{"level":"warn","ts":1526587299.1830168,"caller":"rafthttp/stream.go:436","msg":"lost TCP streaming connection with remote peer","stream-reader-type":"stream Message","local-member-id":"7339c4e5e833c029","remote-peer-id":"729934363faa4a24","error":"context canceled"}
{"level":"warn","ts":1526587299.1831107,"caller":"rafthttp/peer_status.go:65","msg":"peer became inactive","peer-id":"729934363faa4a24","error":"failed to read 729934363faa4a24 on stream Message (context canceled)"}
{"level":"info","ts":1526587299.1831737,"caller":"rafthttp/stream.go:459","msg":"stopped stream reader with remote peer","stream-reader-type":"stream Message","local-member-id":"7339c4e5e833c029","remote-peer-id":"729934363faa4a24"}
{"level":"info","ts":1526587299.1832306,"caller":"rafthttp/peer.go:340","msg":"stopped remote peer","remote-peer-id":"729934363faa4a24"}
{"level":"warn","ts":1526587299.1837125,"caller":"rafthttp/http.go:424","msg":"failed to find remote peer in cluster","local-member-id":"7339c4e5e833c029","remote-peer-id-stream-handler":"7339c4e5e833c029","remote-peer-id-from":"b548c2511513015","cluster-id":"7dee9ba76d59ed53"}
{"level":"warn","ts":1526587299.1840093,"caller":"rafthttp/http.go:424","msg":"failed to find remote peer in cluster","local-member-id":"7339c4e5e833c029","remote-peer-id-stream-handler":"7339c4e5e833c029","remote-peer-id-from":"b548c2511513015","cluster-id":"7dee9ba76d59ed53"}
{"level":"warn","ts":1526587299.1842315,"caller":"rafthttp/http.go:424","msg":"failed to find remote peer in cluster","local-member-id":"7339c4e5e833c029","remote-peer-id-stream-handler":"7339c4e5e833c029","remote-peer-id-from":"729934363faa4a24","cluster-id":"7dee9ba76d59ed53"}
{"level":"warn","ts":1526587299.1844475,"caller":"rafthttp/http.go:424","msg":"failed to find remote peer in cluster","local-member-id":"7339c4e5e833c029","remote-peer-id-stream-handler":"7339c4e5e833c029","remote-peer-id-from":"729934363faa4a24","cluster-id":"7dee9ba76d59ed53"}
{"level":"info","ts":1526587299.2056687,"caller":"embed/etcd.go:473","msg":"stopping serving peer traffic","address":"127.0.0.1:2380"}
{"level":"info","ts":1526587299.205819,"caller":"embed/etcd.go:480","msg":"stopped serving peer traffic","address":"127.0.0.1:2380"}
{"level":"info","ts":1526587299.2058413,"caller":"embed/etcd.go:289","msg":"closed etcd server","name":"s1","data-dir":"/tmp/etcd/s1","advertise-peer-urls":["http://localhost:2380"],"advertise-client-urls":["http://localhost:2379"]}

Schritt 4: Den etcd-Server mit derselben Konfiguration neu starten

Starten Sie den etcd-Server mit derselben Konfiguration, aber mit der neuen etcd-Binärdatei neu.

-etcd-old --name s1 \
+etcd-new --name s1 \
  --data-dir /tmp/etcd/s1 \
  --listen-client-urls http://localhost:2379 \
  --advertise-client-urls http://localhost:2379 \
  --listen-peer-urls http://localhost:2380 \
  --initial-advertise-peer-urls http://localhost:2380 \
  --initial-cluster s1=http://localhost:2380,s2=http://localhost:22380,s3=http://localhost:32380 \
  --initial-cluster-token tkn \
  --initial-cluster-state new

Das neue etcd v3.5 veröffentlicht seine Informationen im Cluster. Zu diesem Zeitpunkt verwendet der Cluster weiterhin das Protokoll von v3.4, der niedrigsten gemeinsamen Version.

{"level":"info","ts":1526586617.1647713,"caller":"membership/cluster.go:485","msg":"set initial cluster version","cluster-id":"7dee9ba76d59ed53","local-member-id":"7339c4e5e833c029","cluster-version":"3.0"}

{"level":"info","ts":1526586617.1648536,"caller":"api/capability.go:76","msg":"enabled capabilities for version","cluster-version":"3.0"}

{"level":"info","ts":1526586617.1649303,"caller":"membership/cluster.go:473","msg":"updated cluster version","cluster-id":"7dee9ba76d59ed53","local-member-id":"7339c4e5e833c029","from":"3.0","from":"3.4"}

{"level":"info","ts":1526586617.1649797,"caller":"api/capability.go:76","msg":"enabled capabilities for version","cluster-version":"3.4"}

{"level":"info","ts":1526586617.2107732,"caller":"etcdserver/server.go:1770","msg":"published local member to cluster through raft","local-member-id":"7339c4e5e833c029","local-member-attributes":"{Name:s1 ClientURLs:[http://localhost:2379]}","request-path":"/0/members/7339c4e5e833c029/attributes","cluster-id":"7dee9ba76d59ed53","publish-timeout":7}

Prüfen Sie, ob jedes Mitglied und anschließend der gesamte Cluster mit der neuen etcd-v3.5-Binärdatei wieder fehlerfrei ist:

etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
<<COMMENT
localhost:32379 is healthy: successfully committed proposal: took = 2.337471ms
localhost:22379 is healthy: successfully committed proposal: took = 1.130717ms
localhost:2379 is healthy: successfully committed proposal: took = 2.124843ms
COMMENT

Noch nicht aktualisierte Mitglieder protokollieren Warnungen wie die folgenden, bis der gesamte Cluster aktualisiert wurde.

Dies ist zu erwarten und endet, sobald alle etcd-Cluster-Mitglieder auf v3.5 aktualisiert wurden:

:41.942121 W | etcdserver: member 7339c4e5e833c029 has a higher version 3.5.0
:45.945154 W | etcdserver: the local etcd version 3.4.0 is not up-to-date

Schritt 5: Schritt 3 und Schritt 4 für die übrigen Mitglieder wiederholen

Sobald alle Mitglieder aktualisiert wurden, meldet der Cluster den erfolgreichen Abschluss des Upgrades auf 3.5:

Mitglied 1:

{"level":"info","ts":1526586949.0920913,"caller":"api/capability.go:76","msg":"enabled capabilities for version","cluster-version":"3.5"} {"level":"info","ts":1526586949.0921566,"caller":"etcdserver/server.go:2272","msg":"cluster version is updated","cluster-version":"3.5"}

Mitglied 2:

{"level":"info","ts":1526586949.092117,"caller":"membership/cluster.go:473","msg":"updated cluster version","cluster-id":"7dee9ba76d59ed53","local-member-id":"729934363faa4a24","from":"3.4","from":"3.5"} {"level":"info","ts":1526586949.0923078,"caller":"api/capability.go:76","msg":"enabled capabilities for version","cluster-version":"3.5"}

Mitglied 3:

{"level":"info","ts":1526586949.0921423,"caller":"membership/cluster.go:473","msg":"updated cluster version","cluster-id":"7dee9ba76d59ed53","local-member-id":"b548c2511513015","from":"3.4","from":"3.5"} {"level":"info","ts":1526586949.0922918,"caller":"api/capability.go:76","msg":"enabled capabilities for version","cluster-version":"3.5"}

endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
<<COMMENT
localhost:2379 is healthy: successfully committed proposal: took = 492.834µs
localhost:22379 is healthy: successfully committed proposal: took = 1.015025ms
localhost:32379 is healthy: successfully committed proposal: took = 1.853077ms
COMMENT

curl http://localhost:2379/version
<<COMMENT
{"etcdserver":"3.5.0","etcdcluster":"3.5.0"}
COMMENT

curl http://localhost:22379/version
<<COMMENT
{"etcdserver":"3.5.0","etcdcluster":"3.5.0"}
COMMENT

curl http://localhost:32379/version
<<COMMENT
{"etcdserver":"3.5.0","etcdcluster":"3.5.0"}
COMMENT

17.5 - Upgrade von etcd 3.3 auf 3.4

Verfahren, Checklisten und Hinweise zum Upgrade von etcd 3.3 auf 3.4

Im Allgemeinen kann das Upgrade von etcd 3.3 auf 3.4 als Rolling Upgrade ohne Ausfallzeit erfolgen:

  • Die etcd-v3.3-Prozesse nacheinander stoppen und durch etcd-v3.4-Prozesse ersetzen.
  • Sobald alle v3.4-Prozesse laufen, stehen dem Cluster die neuen Funktionen von v3.4 zur Verfügung.

Lesen Sie zur Vorbereitung den Rest dieses Leitfadens, bevor Sie mit dem Upgrade beginnen .

Checklisten für das Upgrade

Warnung

Bei der Migration von v2 ohne v3-Daten löst der etcd-Server v3.2+ eine Panic aus, wenn etcd aus vorhandenen Snapshots wiederhergestellt wird, aber keine v3-Datei ETCD_DATA_DIR/member/snap/db vorhanden ist. Dies tritt auf, wenn der Server von v2 migriert wurde, ohne zuvor v3-Daten zu enthalten. Dadurch wird auch ein versehentlicher Verlust von v3-Daten verhindert (z. B. könnte die Datei db verschoben worden sein). etcd verlangt, dass weitere Migrationen nach der Migration auf v3 nur mit v3-Daten erfolgen können. Führen Sie kein Upgrade auf neuere v3-Versionen durch, bevor der v3.0-Server v3-Daten enthält.

Wichtige inkompatible Änderungen in 3.4.

ETCDCTL_API=3 etcdctl wird zum Standard

ETCDCTL_API=3 ist jetzt der Standard.

etcdctl set foo bar
Error: unknown command "set" for "etcdctl"

-etcdctl set foo bar
+ETCDCTL_API=2 etcdctl set foo bar
bar

ETCDCTL_API=3 etcdctl put foo bar
OK

-ETCDCTL_API=3 etcdctl put foo bar
+etcdctl put foo bar

etcd --enable-v2=false wird zum Standard

etcd --enable-v2=false ist jetzt der Standard.

Das bedeutet, dass der etcd-v3.4-Server keine v2-API-Anfragen bedient, sofern nicht etcd --enable-v2=true angegeben wird.

Wenn die v2-API verwendet wurde, aktivieren Sie die v2-API unbedingt in v3.4:

-etcd
+etcd --enable-v2=true

Andere HTTP-APIs funktionieren weiterhin (z. B. [CLIENT-URL]/metrics, [CLIENT-URL]/health, v3-gRPC-Gateway).

Veraltete Flags etcd --ca-file und etcd --peer-ca-file

Die Flags --ca-file und --peer-ca-file sind veraltet; sie sind bereits seit v2.1 veraltet.

Beachten Sie, dass das Setzen dieses Parameters auch die Client-Zertifikatsauthentifizierung automatisch aktiviert, unabhängig vom Wert von --client-cert-auth.

-etcd --ca-file ca-client.crt
+etcd --trusted-ca-file ca-client.crt
-etcd --peer-ca-file ca-peer.crt
+etcd --peer-trusted-ca-file ca-peer.crt

Veralteter Fehler grpc.ErrClientConnClosing

grpc.ErrClientConnClosing ist seit gRPC >= 1.10 veraltet .

import (
+	"go.etcd.io/etcd/clientv3"

	"google.golang.org/grpc"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
)

_, err := kvc.Get(ctx, "a")
-if err == grpc.ErrClientConnClosing {
+if clientv3.IsConnCanceled(err) {

// or
+s, ok := status.FromError(err)
+if ok {
+  if s.Code() == codes.Canceled

grpc.WithBlock für den Verbindungsaufbau des Clients erforderlich

Der neue Client-Balancer verwendet einen asynchronen Resolver, um Endpunkte an die gRPC-Funktion zum Verbindungsaufbau zu übergeben. Daher benötigt der v3.4-Client die Option grpc.WithBlock beim Verbindungsaufbau, um zu warten, bis die zugrunde liegende Verbindung hergestellt ist.

import (
	"time"
	"go.etcd.io/etcd/clientv3"
+	"google.golang.org/grpc"
)

+// "grpc.WithBlock()" to block until the underlying connection is up
ccfg := clientv3.Config{
  Endpoints:            []string{"localhost:2379"},
  DialTimeout:          time.Second,
+ DialOptions:          []grpc.DialOption{grpc.WithBlock()},
  DialKeepAliveTime:    time.Second,
  DialKeepAliveTimeout: 500 * time.Millisecond,
}

Prometheus-Metrik etcd_debugging_mvcc_db_total_size_in_bytes wird als veraltet eingestuft

v3.4 überführt die Prometheus-Metrik etcd_debugging_mvcc_db_total_size_in_bytes in etcd_mvcc_db_total_size_in_bytes, um die Überwachung des etcd-Speichers zu fördern.

etcd_debugging_mvcc_db_total_size_in_bytes wird in v3.4 aus Gründen der Abwärtskompatibilität weiterhin bereitgestellt. In v3.5 wird sie vollständig als veraltet eingestuft.

-etcd_debugging_mvcc_db_total_size_in_bytes
+etcd_mvcc_db_total_size_in_bytes

Beachten Sie, dass Metriken im Namensraum etcd_debugging_* als experimentell gekennzeichnet sind. Im Zuge der Verbesserung des Überwachungsleitfadens können wir weitere Metriken hochstufen.

Prometheus-Metrik etcd_debugging_mvcc_put_total wird als veraltet eingestuft

v3.4 überführt die Prometheus-Metrik etcd_debugging_mvcc_put_total in etcd_mvcc_put_total, um die Überwachung des etcd-Speichers zu fördern.

etcd_debugging_mvcc_put_total wird in v3.4 aus Gründen der Abwärtskompatibilität weiterhin bereitgestellt. In v3.5 wird sie vollständig als veraltet eingestuft.

-etcd_debugging_mvcc_put_total
+etcd_mvcc_put_total

Beachten Sie, dass Metriken im Namensraum etcd_debugging_* als experimentell gekennzeichnet sind. Im Zuge der Verbesserung des Überwachungsleitfadens können wir weitere Metriken hochstufen.

Prometheus-Metrik etcd_debugging_mvcc_delete_total wird als veraltet eingestuft

v3.4 überführt die Prometheus-Metrik etcd_debugging_mvcc_delete_total in etcd_mvcc_delete_total, um die Überwachung des etcd-Speichers zu fördern.

etcd_debugging_mvcc_delete_total wird in v3.4 aus Gründen der Abwärtskompatibilität weiterhin bereitgestellt. In v3.5 wird sie vollständig als veraltet eingestuft.

-etcd_debugging_mvcc_delete_total
+etcd_mvcc_delete_total

Beachten Sie, dass Metriken im Namensraum etcd_debugging_* als experimentell gekennzeichnet sind. Im Zuge der Verbesserung des Überwachungsleitfadens können wir weitere Metriken hochstufen.

Prometheus-Metrik etcd_debugging_mvcc_txn_total wird als veraltet eingestuft

v3.4 überführt die Prometheus-Metrik etcd_debugging_mvcc_txn_total in etcd_mvcc_txn_total, um die Überwachung des etcd-Speichers zu fördern.

etcd_debugging_mvcc_txn_total wird in v3.4 aus Gründen der Abwärtskompatibilität weiterhin bereitgestellt. In v3.5 wird sie vollständig als veraltet eingestuft.

-etcd_debugging_mvcc_txn_total
+etcd_mvcc_txn_total

Beachten Sie, dass Metriken im Namensraum etcd_debugging_* als experimentell gekennzeichnet sind. Im Zuge der Verbesserung des Überwachungsleitfadens können wir weitere Metriken hochstufen.

Prometheus-Metrik etcd_debugging_mvcc_range_total wird als veraltet eingestuft

v3.4 überführt die Prometheus-Metrik etcd_debugging_mvcc_range_total in etcd_mvcc_range_total, um die Überwachung des etcd-Speichers zu fördern.

etcd_debugging_mvcc_range_total wird in v3.4 aus Gründen der Abwärtskompatibilität weiterhin bereitgestellt. In v3.5 wird sie vollständig als veraltet eingestuft.

-etcd_debugging_mvcc_range_total
+etcd_mvcc_range_total

Beachten Sie, dass Metriken im Namensraum etcd_debugging_* als experimentell gekennzeichnet sind. Im Zuge der Verbesserung des Überwachungsleitfadens können wir weitere Metriken hochstufen.

Flag etcd --log-output wird als veraltet eingestuft (jetzt --log-outputs)

etcd --log-output wird in --log-outputs umbenannt , um mehrere Protokollausgaben zu unterstützen. etcd --logger=capnslog unterstützt nicht mehrere Protokollausgaben.

etcd --log-output wird in v3.5 als veraltet eingestuft. etcd --logger=capnslog wird in v3.5 als veraltet eingestuft.

-etcd --log-output=stderr
+etcd --log-outputs=stderr

+# to write logs to stderr and a.log file at the same time
+# only "--logger=zap" supports multiple writers
+etcd --logger=zap --log-outputs=stderr,a.log

v3.4 unterstützt zusätzlich etcd --logger=zap --log-outputs=stderr für strukturierte Protokollierung und mehrere Protokollausgaben. Das Hauptziel ist, die automatisierte Überwachung von etcd zu fördern, statt erst bei auftretenden Fehlern die Serverprotokolle durchzusehen. Die künftige Entwicklung soll die Protokollausgabe von etcd auf ein Minimum reduzieren und die Überwachung mit Metriken und Alarmen erleichtern. etcd --logger=capnslog wird in v3.5 als veraltet eingestuft.

Feldtyp von log-outputs in etcd --config-file in []string geändert

Da log-outputs (früherer Feldname log-output) jetzt mehrere Ausgabeziele akzeptiert, muss das Feld log-outputs in der YAML-Konfigurationsdatei von etcd wie unten gezeigt auf den Typ []string geändert werden:

 # Specify 'stdout' or 'stderr' to skip journald logging even when running under systemd.
-log-output: default
+log-outputs: [default]

embed.Config.LogOutput in embed.Config.LogOutputs umbenannt

embed.Config.LogOutput wurde in embed.Config.LogOutputs umbenannt , um mehrere Protokollausgaben zu unterstützen. Außerdem wurde der Typ von embed.Config.LogOutput von string in []string geändert , um mehrere Protokollausgaben zu unterstützen.

import "github.com/coreos/etcd/embed"

cfg := &embed.Config{Debug: false}
-cfg.LogOutput = "stderr"
+cfg.LogOutputs = []string{"stderr"}

v3.5 stuft capnslog als veraltet ein

v3.5 wird das Flag etcd --log-package-levels für capnslog als veraltet einstufen; etcd --logger=zap --log-outputs=stderr wird zum Standard. v3.5 wird den Endpunkt [CLIENT-URL]/config/local/log als veraltet einstufen.

-etcd
+etcd --logger zap

Flag etcd --debug wird als veraltet eingestuft (jetzt --log-level=debug)

v3.4 stuft das Flag etcd --debug als veraltet ein. Verwenden Sie stattdessen das Flag etcd --log-level=debug.

-etcd --debug
+etcd --logger zap --log-level debug

Veraltetes Feld pkg/transport.TLSInfo.CAFile

Das Feld pkg/transport.TLSInfo.CAFile ist veraltet.

import "github.com/coreos/etcd/pkg/transport"

tlsInfo := transport.TLSInfo{
    CertFile: "/tmp/test-certs/test.pem",
    KeyFile: "/tmp/test-certs/test-key.pem",
-   CAFile: "/tmp/test-certs/trusted-ca.pem",
+   TrustedCAFile: "/tmp/test-certs/trusted-ca.pem",
}
tlsConfig, err := tlsInfo.ClientConfig()
if err != nil {
    panic(err)
}

embed.Config.SnapCount in embed.Config.SnapshotCount geändert

Zur Übereinstimmung mit dem Flag-Namen etcd --snapshot-count wurde das Feld embed.Config.SnapCount in embed.Config.SnapshotCount umbenannt:

import "github.com/coreos/etcd/embed"

cfg := embed.NewConfig()
-cfg.SnapCount = 100000
+cfg.SnapshotCount = 100000

etcdserver.ServerConfig.SnapCount in etcdserver.ServerConfig.SnapshotCount geändert

Zur Übereinstimmung mit dem Flag-Namen etcd --snapshot-count wurde das Feld etcdserver.ServerConfig.SnapCount in etcdserver.ServerConfig.SnapshotCount umbenannt:

import "github.com/coreos/etcd/etcdserver"

srvcfg := etcdserver.ServerConfig{
-  SnapCount: 100000,
+  SnapshotCount: 100000,

Geänderte Funktionssignatur im Paket wal

Die Funktionssignaturen von wal wurden geändert, um einen strukturierten Logger zu unterstützen.

import "github.com/coreos/etcd/wal"
+import "go.uber.org/zap"

+lg, _ = zap.NewProduction()

-wal.Open(dirpath, snap)
+wal.Open(lg, dirpath, snap)

-wal.OpenForRead(dirpath, snap)
+wal.OpenForRead(lg, dirpath, snap)

-wal.Repair(dirpath)
+wal.Repair(lg, dirpath)

-wal.Create(dirpath, metadata)
+wal.Create(lg, dirpath, metadata)

Geänderter Typ IntervalTree im Paket pkg/adt

pkg/adt.IntervalTree ist jetzt als interface definiert.

import (
    "fmt"

    "go.etcd.io/etcd/pkg/adt"
)

func main() {
-    ivt := &adt.IntervalTree{}
+    ivt := adt.NewIntervalTree()

embed.Config.SetupLogging ist veraltet

embed.Config.SetupLogging wurde entfernt, um fehlerhafte Protokollierungskonfigurationen zu verhindern; die Einrichtung erfolgt jetzt automatisch.

import "github.com/coreos/etcd/embed"

cfg := &embed.Config{Debug: false}
-cfg.SetupLogging()

Geänderte HTTP-Endpunkte des gRPC-Gateways (/v3beta durch /v3 ersetzt)

Vorher

curl -L http://localhost:2379/v3beta/kv/put \
  -X POST -d '{"key": "Zm9v", "value": "YmFy"}'

Nachher

curl -L http://localhost:2379/v3/kv/put \
  -X POST -d '{"key": "Zm9v", "value": "YmFy"}'

Anfragen an /v3beta-Endpunkte werden an /v3 umgeleitet; /v3beta wird im Release 3.5 entfernt.

Veraltete Container-Image-Tags

latest und Image-Tags für Nebenversionen sind veraltet:

-docker pull gcr.io/etcd-development/etcd:latest
+docker pull gcr.io/etcd-development/etcd:v3.4.0

-docker pull gcr.io/etcd-development/etcd:v3.4
+docker pull gcr.io/etcd-development/etcd:v3.4.0

-docker pull gcr.io/etcd-development/etcd:v3.4
+docker pull gcr.io/etcd-development/etcd:v3.4.1

-docker pull gcr.io/etcd-development/etcd:v3.4
+docker pull gcr.io/etcd-development/etcd:v3.4.2

Checklisten für das Server-Upgrade

Upgrade-Voraussetzungen

Um eine bestehende etcd-Installation auf 3.4 zu aktualisieren, muss der laufende Cluster Version 3.3 oder höher verwenden. Falls er eine ältere Version als 3.3 verwendet, führen Sie vor dem Upgrade auf 3.4 zunächst ein Upgrade auf 3.3 durch.

Außerdem muss der laufende Cluster fehlerfrei sein, damit das Rolling Upgrade reibungslos verläuft. Prüfen Sie den Zustand des Clusters mit dem Befehl etcdctl endpoint health, bevor Sie fortfahren.

Vorbereitung

Testen Sie vor einem etcd-Upgrade immer die von etcd abhängigen Dienste in einer Staging-Umgebung, bevor Sie das Upgrade in der Produktionsumgebung durchführen.

Laden Sie vor Beginn das Snapshot-Backup herunter . Falls beim Upgrade etwas schiefgeht, können Sie mit diesem Backup ein Downgrade auf die bestehende etcd-Version durchführen. Beachten Sie, dass der Befehl snapshot nur die v3-Daten sichert. Informationen zu v2-Daten finden Sie unter Backup des v2-Datenspeichers .

Gemischte Versionen

Während des Upgrades unterstützt ein etcd-Cluster Mitglieder mit gemischten etcd-Versionen und verwendet das Protokoll der niedrigsten gemeinsamen Version. Der Cluster gilt erst als aktualisiert, wenn alle Mitglieder auf Version 3.4 aktualisiert wurden. Intern handeln die etcd-Mitglieder untereinander die Gesamtversion des Clusters aus, die die gemeldete Version und die unterstützten Funktionen bestimmt.

Einschränkungen

Hinweis: Wenn der Cluster nur v3-Daten und keine v2-Daten enthält, gilt diese Einschränkung nicht.

Wenn der Cluster einen v2-Datenbestand von mehr als 50MB bereitstellt, kann es bis zu zwei Minuten dauern, bis jedes neu aktualisierte Mitglied zum bestehenden Cluster aufgeschlossen hat. Prüfen Sie die Größe eines aktuellen Snapshots, um die Gesamtdatenmenge abzuschätzen. Anders ausgedrückt ist es am sichersten, zwischen den Upgrades der einzelnen Mitglieder jeweils 2 Minuten zu warten.

Bei einer deutlich größeren Gesamtdatenmenge von 100MB oder mehr kann dieser einmalige Vorgang noch länger dauern. Administratoren sehr großer etcd-Cluster dieser Größenordnung können vor dem Upgrade das etcd-Team kontaktieren; wir beraten Sie gern zum Vorgehen.

Downgrade

Wenn alle Mitglieder auf v3.4 aktualisiert wurden, wird der Cluster auf v3.4 aktualisiert; ein Downgrade aus diesem abgeschlossenen Zustand ist nicht möglich. Solange jedoch noch ein einziges Mitglied v3.3 verwendet, bleiben der Cluster und sein Betrieb auf „v3.3“. Aus diesem Zustand mit gemischten Versionen ist es möglich, auf allen Mitgliedern wieder eine etcd-v3.3-Binärdatei zu verwenden.

Laden Sie das Snapshot-Backup herunter , um ein Downgrade des Clusters auch nach einem vollständig abgeschlossenen Upgrade zu ermöglichen.

Upgrade-Verfahren

Dieses Beispiel zeigt das Upgrade eines etcd-v3.3-Clusters mit 3 Mitgliedern, der auf einem lokalen Rechner läuft.

Schritt 1: Upgrade-Voraussetzungen prüfen

Ist der Cluster fehlerfrei und läuft er mit v3.3.x?

etcdctl --endpoints=localhost:2379,localhost:22379,localhost:32379 endpoint health
<<COMMENT
localhost:2379 is healthy: successfully committed proposal: took = 2.118638ms
localhost:22379 is healthy: successfully committed proposal: took = 3.631388ms
localhost:32379 is healthy: successfully committed proposal: took = 2.157051ms
COMMENT

curl http://localhost:2379/version
<<COMMENT
{"etcdserver":"3.3.5","etcdcluster":"3.3.0"}
COMMENT

curl http://localhost:22379/version
<<COMMENT
{"etcdserver":"3.3.5","etcdcluster":"3.3.0"}
COMMENT

curl http://localhost:32379/version
<<COMMENT
{"etcdserver":"3.3.5","etcdcluster":"3.3.0"}
COMMENT

Schritt 2: Snapshot-Backup vom Leader herunterladen

Laden Sie das Snapshot-Backup herunter , um bei Problemen ein Downgrade durchführen zu können.

Der etcd-Leader enthält garantiert die neuesten Anwendungsdaten. Rufen Sie den Snapshot daher vom Leader ab:

curl -sL http://localhost:2379/metrics | grep etcd_server_is_leader
<<COMMENT
# HELP etcd_server_is_leader Whether or not this member is a leader. 1 if is, 0 otherwise.
# TYPE etcd_server_is_leader gauge
etcd_server_is_leader 1
COMMENT

curl -sL http://localhost:22379/metrics | grep etcd_server_is_leader
<<COMMENT
etcd_server_is_leader 0
COMMENT

curl -sL http://localhost:32379/metrics | grep etcd_server_is_leader
<<COMMENT
etcd_server_is_leader 0
COMMENT

etcdctl --endpoints=localhost:2379 snapshot save backup.db
<<COMMENT
{"level":"info","ts":1526585787.148433,"caller":"snapshot/v3_snapshot.go:109","msg":"created temporary db file","path":"backup.db.part"}
{"level":"info","ts":1526585787.1485257,"caller":"snapshot/v3_snapshot.go:120","msg":"fetching snapshot","endpoint":"localhost:2379"}
{"level":"info","ts":1526585787.1519694,"caller":"snapshot/v3_snapshot.go:133","msg":"fetched snapshot","endpoint":"localhost:2379","took":0.003502721}
{"level":"info","ts":1526585787.1520295,"caller":"snapshot/v3_snapshot.go:142","msg":"saved","path":"backup.db"}
Snapshot saved at backup.db
COMMENT

Schritt 3: Einen bestehenden etcd-Server stoppen

Wenn ein etcd-Prozess gestoppt wird, protokollieren die anderen Cluster-Mitglieder erwartete Fehler. Dies ist normal, da die Verbindung zu einem Cluster-Mitglied (vorübergehend) unterbrochen wurde:

10.237579 I | etcdserver: updating the cluster version from 3.0 to 3.3
10.238315 N | etcdserver/membership: updated the cluster version from 3.0 to 3.3
10.238451 I | etcdserver/api: enabled capabilities for version 3.3


^C21.192174 N | pkg/osutil: received interrupt signal, shutting down...
21.192459 I | etcdserver: 7339c4e5e833c029 starts leadership transfer from 7339c4e5e833c029 to 729934363faa4a24
21.192569 I | raft: 7339c4e5e833c029 [term 8] starts to transfer leadership to 729934363faa4a24
21.192619 I | raft: 7339c4e5e833c029 sends MsgTimeoutNow to 729934363faa4a24 immediately as 729934363faa4a24 already has up-to-date log
WARNING: 2018/05/17 12:45:21 grpc: addrConn.resetTransport failed to create client transport: connection error: desc = "transport: Error while dialing dial tcp: operation was canceled"; Reconnecting to {localhost:2379 0  <nil>}
WARNING: 2018/05/17 12:45:21 grpc: addrConn.transportMonitor exits due to: grpc: the connection is closing
21.193589 I | raft: 7339c4e5e833c029 [term: 8] received a MsgVote message with higher term from 729934363faa4a24 [term: 9]
21.193626 I | raft: 7339c4e5e833c029 became follower at term 9
21.193651 I | raft: 7339c4e5e833c029 [logterm: 8, index: 9, vote: 0] cast MsgVote for 729934363faa4a24 [logterm: 8, index: 9] at term 9
21.193675 I | raft: raft.node: 7339c4e5e833c029 lost leader 7339c4e5e833c029 at term 9
21.194424 I | raft: raft.node: 7339c4e5e833c029 elected leader 729934363faa4a24 at term 9
21.292898 I | etcdserver: 7339c4e5e833c029 finished leadership transfer from 7339c4e5e833c029 to 729934363faa4a24 (took 100.436391ms)
21.292975 I | rafthttp: stopping peer 729934363faa4a24...
21.293206 I | rafthttp: closed the TCP streaming connection with peer 729934363faa4a24 (stream MsgApp v2 writer)
21.293225 I | rafthttp: stopped streaming with peer 729934363faa4a24 (writer)
21.293437 I | rafthttp: closed the TCP streaming connection with peer 729934363faa4a24 (stream Message writer)
21.293459 I | rafthttp: stopped streaming with peer 729934363faa4a24 (writer)
21.293514 I | rafthttp: stopped HTTP pipelining with peer 729934363faa4a24
21.293590 W | rafthttp: lost the TCP streaming connection with peer 729934363faa4a24 (stream MsgApp v2 reader)
21.293610 I | rafthttp: stopped streaming with peer 729934363faa4a24 (stream MsgApp v2 reader)
21.293680 W | rafthttp: lost the TCP streaming connection with peer 729934363faa4a24 (stream Message reader)
21.293700 I | rafthttp: stopped streaming with peer 729934363faa4a24 (stream Message reader)
21.293711 I | rafthttp: stopped peer 729934363faa4a24
21.293720 I | rafthttp: stopping peer b548c2511513015...
21.293987 I | rafthttp: closed the TCP streaming connection with peer b548c2511513015 (stream MsgApp v2 writer)
21.294063 I | rafthttp: stopped streaming with peer b548c2511513015 (writer)
21.294467 I | rafthttp: closed the TCP streaming connection with peer b548c2511513015 (stream Message writer)
21.294561 I | rafthttp: stopped streaming with peer b548c2511513015 (writer)
21.294742 I | rafthttp: stopped HTTP pipelining with peer b548c2511513015
21.294867 W | rafthttp: lost the TCP streaming connection with peer b548c2511513015 (stream MsgApp v2 reader)
21.294892 I | rafthttp: stopped streaming with peer b548c2511513015 (stream MsgApp v2 reader)
21.294990 W | rafthttp: lost the TCP streaming connection with peer b548c2511513015 (stream Message reader)
21.295004 E | rafthttp: failed to read b548c2511513015 on stream Message (context canceled)
21.295013 I | rafthttp: peer b548c2511513015 became inactive
21.295024 I | rafthttp: stopped streaming with peer b548c2511513015 (stream Message reader)
21.295035 I | rafthttp: stopped peer b548c2511513015

Schritt 4: Den etcd-Server mit derselben Konfiguration neu starten

Starten Sie den etcd-Server mit derselben Konfiguration, aber mit der neuen etcd-Binärdatei neu.

-etcd-old --name s1 \
+etcd-new --name s1 \
  --data-dir /tmp/etcd/s1 \
  --listen-client-urls http://localhost:2379 \
  --advertise-client-urls http://localhost:2379 \
  --listen-peer-urls http://localhost:2380 \
  --initial-advertise-peer-urls http://localhost:2380 \
  --initial-cluster s1=http://localhost:2380,s2=http://localhost:22380,s3=http://localhost:32380 \
  --initial-cluster-token tkn \
+ --initial-cluster-state new \
+ --logger zap \
+ --log-outputs stderr

Das neue etcd v3.4 veröffentlicht seine Informationen im Cluster. Zu diesem Zeitpunkt verwendet der Cluster weiterhin das Protokoll von v3.3, der niedrigsten gemeinsamen Version.

{"level":"info","ts":1526586617.1647713,"caller":"membership/cluster.go:485","msg":"set initial cluster version","cluster-id":"7dee9ba76d59ed53","local-member-id":"7339c4e5e833c029","cluster-version":"3.0"}

{"level":"info","ts":1526586617.1648536,"caller":"api/capability.go:76","msg":"enabled capabilities for version","cluster-version":"3.0"}

{"level":"info","ts":1526586617.1649303,"caller":"membership/cluster.go:473","msg":"updated cluster version","cluster-id":"7dee9ba76d59ed53","local-member-id":"7339c4e5e833c029","from":"3.0","from":"3.3"}

{"level":"info","ts":1526586617.1649797,"caller":"api/capability.go:76","msg":"enabled capabilities for version","cluster-version":"3.3"}

{"level":"info","ts":1526586617.2107732,"caller":"etcdserver/server.go:1770","msg":"published local member to cluster through raft","local-member-id":"7339c4e5e833c029","local-member-attributes":"{Name:s1 ClientURLs:[http://localhost:2379]}","request-path":"/0/members/7339c4e5e833c029/attributes","cluster-id":"7dee9ba76d59ed53","publish-timeout":7}

Prüfen Sie, ob jedes Mitglied und anschließend der gesamte Cluster mit der neuen etcd-v3.4-Binärdatei wieder fehlerfrei ist:

etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
<<COMMENT
localhost:32379 is healthy: successfully committed proposal: took = 2.337471ms
localhost:22379 is healthy: successfully committed proposal: took = 1.130717ms
localhost:2379 is healthy: successfully committed proposal: took = 2.124843ms
COMMENT

Noch nicht aktualisierte Mitglieder protokollieren Warnungen wie die folgenden, bis der gesamte Cluster aktualisiert wurde.

Dies ist zu erwarten und endet, sobald alle etcd-Cluster-Mitglieder auf v3.4 aktualisiert wurden:

:41.942121 W | etcdserver: member 7339c4e5e833c029 has a higher version 3.4.0
:45.945154 W | etcdserver: the local etcd version 3.3.5 is not up-to-date

Schritt 5: Schritt 3 und Schritt 4 für die übrigen Mitglieder wiederholen

Sobald alle Mitglieder aktualisiert wurden, meldet der Cluster den erfolgreichen Abschluss des Upgrades auf 3.4:

Mitglied 1:

{"level":"info","ts":1526586949.0920913,"caller":"api/capability.go:76","msg":"enabled capabilities for version","cluster-version":"3.4"} {"level":"info","ts":1526586949.0921566,"caller":"etcdserver/server.go:2272","msg":"cluster version is updated","cluster-version":"3.4"}

Mitglied 2:

{"level":"info","ts":1526586949.092117,"caller":"membership/cluster.go:473","msg":"updated cluster version","cluster-id":"7dee9ba76d59ed53","local-member-id":"729934363faa4a24","from":"3.3","from":"3.4"} {"level":"info","ts":1526586949.0923078,"caller":"api/capability.go:76","msg":"enabled capabilities for version","cluster-version":"3.4"}

Mitglied 3:

{"level":"info","ts":1526586949.0921423,"caller":"membership/cluster.go:473","msg":"updated cluster version","cluster-id":"7dee9ba76d59ed53","local-member-id":"b548c2511513015","from":"3.3","from":"3.4"} {"level":"info","ts":1526586949.0922918,"caller":"api/capability.go:76","msg":"enabled capabilities for version","cluster-version":"3.4"}

endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
<<COMMENT
localhost:2379 is healthy: successfully committed proposal: took = 492.834µs
localhost:22379 is healthy: successfully committed proposal: took = 1.015025ms
localhost:32379 is healthy: successfully committed proposal: took = 1.853077ms
COMMENT

curl http://localhost:2379/version
<<COMMENT
{"etcdserver":"3.4.0","etcdcluster":"3.4.0"}
COMMENT

curl http://localhost:22379/version
<<COMMENT
{"etcdserver":"3.4.0","etcdcluster":"3.4.0"}
COMMENT

curl http://localhost:32379/version
<<COMMENT
{"etcdserver":"3.4.0","etcdcluster":"3.4.0"}
COMMENT

17.6 - Upgrade von etcd 3.2 auf 3.3

Verfahren, Checklisten und Hinweise zum Upgrade von etcd 3.2 auf 3.3

Im Allgemeinen kann das Upgrade von etcd 3.2 auf 3.3 als Rolling Upgrade ohne Ausfallzeit erfolgen:

  • Die etcd-v3.2-Prozesse nacheinander stoppen und durch etcd-v3.3-Prozesse ersetzen.
  • Sobald alle v3.3-Prozesse laufen, stehen dem Cluster die neuen Funktionen von v3.3 zur Verfügung.

Lesen Sie zur Vorbereitung den Rest dieses Leitfadens, bevor Sie mit dem Upgrade beginnen .

Checklisten für das Upgrade

Warnung

Bei der Migration von v2 ohne v3-Daten löst der etcd-Server v3.2+ eine Panic aus, wenn etcd aus vorhandenen Snapshots wiederhergestellt wird, aber keine v3-Datei ETCD_DATA_DIR/member/snap/db vorhanden ist. Dies tritt auf, wenn der Server von v2 migriert wurde, ohne zuvor v3-Daten zu enthalten. Dadurch wird auch ein versehentlicher Verlust von v3-Daten verhindert (z. B. könnte die Datei db verschoben worden sein). etcd verlangt, dass weitere Migrationen nach der Migration auf v3 nur mit v3-Daten erfolgen können. Führen Sie kein Upgrade auf neuere v3-Versionen durch, bevor der v3.0-Server v3-Daten enthält.

Warnung

Wenn Sie Authentifizierung aktivieren und Leases mit kurzer TTL verwenden, tritt mit hoher Wahrscheinlichkeit ein Problem auf, das zu Dateninkonsistenzen führt. Es wird dringend empfohlen, zunächst auf 3.2.31+ zu aktualisieren, um dieses Problem zu beheben, und erst anschließend auf 3.3. Wenn ein Benutzer ohne Berechtigung während des Upgrades eine LeaseRevoke-Anfrage an den 3.3-Knoten sendet, kann dies außerdem weiterhin Datenbeschädigungen verursachen. Stellen Sie daher vor dem Upgrade am besten sicher, dass solche unzulässigen Aufrufe in Ihrer Umgebung nicht vorkommen. Einzelheiten finden Sie in #11691 .

Wichtige inkompatible Änderungen in 3.3.

Werttyp des Flags etcd --auto-compaction-retention in string geändert

Das Flag --auto-compaction-retention wurde so geändert, dass es Zeichenfolgenwerte akzeptiert , und zwar mit feinerer Granularität . Da --auto-compaction-retention jetzt Zeichenfolgenwerte akzeptiert, muss das Feld auto-compaction-retention in der YAML-Konfigurationsdatei von etcd auf den Typ string geändert werden. Bisher konnte --config-file etcd.config.yaml das Feld auto-compaction-retention: 24 enthalten; jetzt muss es auto-compaction-retention: "24" oder auto-compaction-retention: "24h" lauten. Bei der Konfiguration --auto-compaction-mode periodic --auto-compaction-retention "24h" muss der Zeitdauerwert des Flags --auto-compaction-retention für die Go-Funktion time.ParseDuration gültig sein.

# etcd.config.yaml
+auto-compaction-mode: periodic
-auto-compaction-retention: 24
+auto-compaction-retention: "24"
+# Or
+auto-compaction-retention: "24h"

*etcdserver.ServerConfig in etcdserver.ServerConfig geändert

etcdserver.EtcdServer hat den Typ seines Mitgliedsfelds von *etcdserver.ServerConfig in etcdserver.ServerConfig geändert. Außerdem akzeptiert etcdserver.NewServer jetzt etcdserver.ServerConfig anstelle von *etcdserver.ServerConfig.

Vorher und nachher (z. B. k8s.io/kubernetes/test/e2e_node/services/etcd.go )

import "github.com/coreos/etcd/etcdserver"

type EtcdServer struct {
	*etcdserver.EtcdServer
-	config *etcdserver.ServerConfig
+	config etcdserver.ServerConfig
}

func NewEtcd(dataDir string) *EtcdServer {
-	config := &etcdserver.ServerConfig{
+	config := etcdserver.ServerConfig{
		DataDir: dataDir,
        ...
	}
	return &EtcdServer{config: config}
}

func (e *EtcdServer) Start() error {
	var err error
	e.EtcdServer, err = etcdserver.NewServer(e.config)
    ...

Feld embed.Config.LogOutput hinzugefügt

Warnung

Beachten Sie, dass dieses Feld in v3.4 in embed.Config.LogOutputs mit dem Typ []string umbenannt wurde. Weitere Einzelheiten finden Sie im Upgrade-Leitfaden für v3.4 .

Das Feld LogOutput wurde zu embed.Config hinzugefügt:

package embed

type Config struct {
 	Debug bool `json:"debug"`
 	LogPkgLevels string `json:"log-package-levels"`
+	LogOutput string `json:"log-output"`
 	...

Bisher wurden gRPC-Serverwarnungen in etcdserver protokolliert.

WARNING: 2017/11/02 11:35:51 grpc: addrConn.resetTransport failed to create client transport: connection error: desc = "transport: Error while dialing dial tcp: operation was canceled"; Reconnecting to {localhost:2379 <nil>}
WARNING: 2017/11/02 11:35:51 grpc: addrConn.resetTransport failed to create client transport: connection error: desc = "transport: Error while dialing dial tcp: operation was canceled"; Reconnecting to {localhost:2379 <nil>}

Ab v3.3 sind gRPC-Serverprotokolle standardmäßig deaktiviert.

Warnung

Beachten Sie, dass die Methode embed.Config.SetupLogging seit v3.4 veraltet ist. Weitere Einzelheiten finden Sie im Upgrade-Leitfaden für v3.4 .

import "github.com/coreos/etcd/embed"

cfg := &embed.Config{Debug: false}
cfg.SetupLogging()

Setzen Sie das Feld embed.Config.Debug auf true, um gRPC-Serverprotokolle zu aktivieren.

Geänderte Antwort des Endpunkts /health

Bisher gab [endpoint]:[client-port]/health einen manuell serialisierten JSON-Wert zurück. 3.3 definiert jetzt die Struktur etcdhttp.Health .

Beachten Sie, dass etcdhttp.Health in v3.3.0-rc.0, v3.3.0-rc.1 und v3.3.0-rc.2 die booleschen Felder "health" und "errors" besitzt. Aus Gründen der Abwärtskompatibilität haben wir das Feld "health" auf den Typ string zurückgesetzt und das Feld "errors" entfernt. Weitere Zustandsinformationen werden über separate APIs bereitgestellt.

$ curl http://localhost:2379/health
{"health":"true"}

Geänderte HTTP-Endpunkte des gRPC-Gateways (/v3alpha durch /v3beta ersetzt)

Vorher

curl -L http://localhost:2379/v3alpha/kv/put \
  -X POST -d '{"key": "Zm9v", "value": "YmFy"}'

Nachher

curl -L http://localhost:2379/v3beta/kv/put \
  -X POST -d '{"key": "Zm9v", "value": "YmFy"}'

Anfragen an /v3alpha-Endpunkte werden an /v3beta umgeleitet; /v3alpha wird im Release 3.4 entfernt.

Geänderte Obergrenzen für die Anfragegröße

3.3 erlaubt jetzt benutzerdefinierte Größenlimits für Anfragen sowohl auf der Server- als auch auf der Clientseite. In früheren Versionen (v3.2.10, v3.2.11) war die Größe der Antworten an Clients auf nur 4 MiB begrenzt.

Serverseitige Anfragelimits lassen sich mit dem Flag --max-request-bytes konfigurieren:

# limits request size to 1.5 KiB
etcd --max-request-bytes 1536

# client writes exceeding 1.5 KiB will be rejected
etcdctl put foo [LARGE VALUE...]
# etcdserver: request is too large

Oder konfigurieren Sie das Feld embed.Config.MaxRequestBytes:

import "github.com/coreos/etcd/embed"
import "github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"

// limit requests to 5 MiB
cfg := embed.NewConfig()
cfg.MaxRequestBytes = 5 * 1024 * 1024

// client writes exceeding 5 MiB will be rejected
_, err := cli.Put(ctx, "foo", [LARGE VALUE...])
err == rpctypes.ErrRequestTooLarge

Ohne Angabe beträgt das serverseitige Limit standardmäßig 1.5 MiB.

Clientseitige Anfragelimits müssen anhand der serverseitigen Limits konfiguriert werden.

# limits request size to 1 MiB
etcd --max-request-bytes 1048576
import "github.com/coreos/etcd/clientv3"

cli, _ := clientv3.New(clientv3.Config{
    Endpoints: []string{"127.0.0.1:2379"},
    MaxCallSendMsgSize: 2 * 1024 * 1024,
    MaxCallRecvMsgSize: 3 * 1024 * 1024,
})


// client writes exceeding "--max-request-bytes" will be rejected from etcd server
_, err := cli.Put(ctx, "foo", strings.Repeat("a", 1*1024*1024+5))
err == rpctypes.ErrRequestTooLarge


// client writes exceeding "MaxCallSendMsgSize" will be rejected from client-side
_, err = cli.Put(ctx, "foo", strings.Repeat("a", 5*1024*1024))
err.Error() == "rpc error: code = ResourceExhausted desc = grpc: trying to send message larger than max (5242890 vs. 2097152)"


// some writes under limits
for i := range []int{0,1,2,3,4} {
    _, err = cli.Put(ctx, fmt.Sprintf("foo%d", i), strings.Repeat("a", 1*1024*1024-500))
    if err != nil {
        panic(err)
    }
}
// client reads exceeding "MaxCallRecvMsgSize" will be rejected from client-side
_, err = cli.Get(ctx, "foo", clientv3.WithPrefix())
err.Error() == "rpc error: code = ResourceExhausted desc = grpc: received message larger than max (5240509 vs. 3145728)"

Ohne Angabe beträgt das clientseitige Sendelimit standardmäßig 2 MiB (1.5 MiB + zusätzliche gRPC-Bytes) und das Empfangslimit math.MaxInt32. Weitere Einzelheiten finden Sie in der clientv3-godoc-Dokumentation .

Geänderte Funktionssignaturen der Wrapper für direkte gRPC-Clients

3.3 ändert die Funktionssignaturen des gRPC-Client-Wrappers von clientv3. Diese Änderung war erforderlich, um benutzerdefinierte grpc.CallOption für Nachrichtengrößenlimits zu unterstützen.

Vorher und nachher

-func NewKVFromKVClient(remote pb.KVClient) KV {
+func NewKVFromKVClient(remote pb.KVClient, c *Client) KV {

-func NewClusterFromClusterClient(remote pb.ClusterClient) Cluster {
+func NewClusterFromClusterClient(remote pb.ClusterClient, c *Client) Cluster {

-func NewLeaseFromLeaseClient(remote pb.LeaseClient, keepAliveTimeout time.Duration) Lease {
+func NewLeaseFromLeaseClient(remote pb.LeaseClient, c *Client, keepAliveTimeout time.Duration) Lease {

-func NewMaintenanceFromMaintenanceClient(remote pb.MaintenanceClient) Maintenance {
+func NewMaintenanceFromMaintenanceClient(remote pb.MaintenanceClient, c *Client) Maintenance {

-func NewWatchFromWatchClient(wc pb.WatchClient) Watcher {
+func NewWatchFromWatchClient(wc pb.WatchClient, c *Client) Watcher {

Geänderter Fehlertyp der clientv3-API Snapshot

Bisher gab die clientv3-API Snapshot unverarbeitete Fehler vom Typ [grpc/*status.statusError] zurück. v3.3 wandelt diese Fehler jetzt in die entsprechenden öffentlichen Fehlertypen um, um mit anderen APIs konsistent zu sein.

Vorher

import "context"

// reading snapshot with canceled context should error out
ctx, cancel := context.WithCancel(context.Background())
rc, _ := cli.Snapshot(ctx)
cancel()
_, err := io.Copy(f, rc)
err.Error() == "rpc error: code = Canceled desc = context canceled"

// reading snapshot with deadline exceeded should error out
ctx, cancel = context.WithTimeout(context.Background(), time.Second)
defer cancel()
rc, _ = cli.Snapshot(ctx)
time.Sleep(2 * time.Second)
_, err = io.Copy(f, rc)
err.Error() == "rpc error: code = DeadlineExceeded desc = context deadline exceeded"

Nachher

import "context"

// reading snapshot with canceled context should error out
ctx, cancel := context.WithCancel(context.Background())
rc, _ := cli.Snapshot(ctx)
cancel()
_, err := io.Copy(f, rc)
err == context.Canceled

// reading snapshot with deadline exceeded should error out
ctx, cancel = context.WithTimeout(context.Background(), time.Second)
defer cancel()
rc, _ = cli.Snapshot(ctx)
time.Sleep(2 * time.Second)
_, err = io.Copy(f, rc)
err == context.DeadlineExceeded

Geänderte Ausgabe des Befehls etcdctl lease timetolive

Bisher gab der Befehl lease timetolive LEASE_ID bei einer abgelaufenen Lease -1s als verbleibende Sekunden aus. 3.3 gibt jetzt klarere Meldungen aus.

Vorher

lease 2d8257079fa1bc0c granted with TTL(0s), remaining(-1s)

Nachher

lease 2d8257079fa1bc0c already expired

Geänderte Importe von golang.org/x/net/context

clientv3 hat golang.org/x/net/context als veraltet eingestuft. Wenn ein Projekt golang.org/x/net/context in anderem Code als eingebundene Abhängigkeit mitführt (z. B. in von etcd generiertem Protocol-Buffer-Code) und github.com/coreos/etcd/clientv3 importiert, wird zum Kompilieren Go 1.9+ benötigt.

Vorher

import "golang.org/x/net/context"
cli.Put(context.Background(), "f", "v")

Nachher

import "context"
cli.Put(context.Background(), "f", "v")

Geänderte gRPC-Abhängigkeit

3.3 benötigt jetzt grpc/grpc-go v1.7.5.

grpclog.Logger ist veraltet

grpclog.Logger ist zugunsten von grpclog.LoggerV2 veraltet. clientv3.Logger ist jetzt grpclog.LoggerV2.

Vorher

import "github.com/coreos/etcd/clientv3"
clientv3.SetLogger(log.New(os.Stderr, "grpc: ", 0))

Nachher

import "github.com/coreos/etcd/clientv3"
import "google.golang.org/grpc/grpclog"
clientv3.SetLogger(grpclog.NewLoggerV2(os.Stderr, os.Stderr, os.Stderr))

// log.New above cannot be used (not implement grpclog.LoggerV2 interface)
grpc.ErrClientConnTimeout ist veraltet

Bisher wurde bei Zeitüberschreitungen beim Verbindungsaufbau des Clients der Fehler grpc.ErrClientConnTimeout zurückgegeben. 3.3 gibt stattdessen context.DeadlineExceeded zurück (siehe #8504 ).

Vorher

// expect dial time-out on ipv4 blackhole
_, err := clientv3.New(clientv3.Config{
    Endpoints:   []string{"http://254.0.0.1:12345"},
    DialTimeout: 2 * time.Second
})
if err == grpc.ErrClientConnTimeout {
	// handle errors
}

Nachher

_, err := clientv3.New(clientv3.Config{
    Endpoints:   []string{"http://254.0.0.1:12345"},
    DialTimeout: 2 * time.Second
})
if err == context.DeadlineExceeded {
	// handle errors
}

Geänderte offizielle Container-Registry

etcd verwendet jetzt gcr.io/etcd-development/etcd als primäre und quay.io/coreos/etcd als sekundäre Container-Registry.

Vorher

docker pull quay.io/coreos/etcd:v3.2.5

Nachher

docker pull gcr.io/etcd-development/etcd:v3.3.0

Upgrades auf >= v3.3.14

v3.3.14 musste einige Funktionen aus 3.4 aufnehmen, wobei versucht wurde, die Unterschiede zwischen den Implementierungen des Client-Balancers möglichst gering zu halten. Dieses Release behebt „kube-apiserver 1.13.x verweigert die Arbeit, wenn der erste etcd-Server nicht verfügbar ist“ (kubernetes#72102) .

grpc.ErrClientConnClosing ist seit gRPC >= 1.10 veraltet .

import (
+	"go.etcd.io/etcd/clientv3"

	"google.golang.org/grpc"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
)

_, err := kvc.Get(ctx, "a")
-if err == grpc.ErrClientConnClosing {
+if clientv3.IsConnCanceled(err) {

// or
+s, ok := status.FromError(err)
+if ok {
+  if s.Code() == codes.Canceled

Der neue Client-Balancer verwendet einen asynchronen Resolver, um Endpunkte an die gRPC-Funktion zum Verbindungsaufbau zu übergeben. Daher benötigt v3.3.14 oder höher die Option grpc.WithBlock beim Verbindungsaufbau, um zu warten, bis die zugrunde liegende Verbindung hergestellt ist.

import (
	"time"
	"go.etcd.io/etcd/clientv3"
+	"google.golang.org/grpc"
)

+// "grpc.WithBlock()" to block until the underlying connection is up
ccfg := clientv3.Config{
  Endpoints:            []string{"localhost:2379"},
  DialTimeout:          time.Second,
+ DialOptions:          []grpc.DialOption{grpc.WithBlock()},
  DialKeepAliveTime:    time.Second,
  DialKeepAliveTimeout: 500 * time.Millisecond,
}

Eine vollständige Liste der Änderungen finden Sie im Änderungsprotokoll (CHANGELOG) .

Checklisten für das Server-Upgrade

Upgrade-Voraussetzungen

Um eine bestehende etcd-Installation auf 3.3 zu aktualisieren, muss der laufende Cluster Version 3.2 oder höher verwenden. Falls er eine ältere Version als 3.2 verwendet, führen Sie vor dem Upgrade auf 3.3 zunächst ein Upgrade auf 3.2 durch.

Außerdem muss der laufende Cluster fehlerfrei sein, damit das Rolling Upgrade reibungslos verläuft. Prüfen Sie den Zustand des Clusters mit dem Befehl etcdctl endpoint health, bevor Sie fortfahren.

Vorbereitung

Testen Sie vor einem etcd-Upgrade immer die von etcd abhängigen Dienste in einer Staging-Umgebung, bevor Sie das Upgrade in der Produktionsumgebung durchführen.

Erstellen Sie vor Beginn ein Backup der etcd-Daten . Falls beim Upgrade etwas schiefgeht, können Sie mit diesem Backup ein Downgrade auf die bestehende etcd-Version durchführen. Beachten Sie, dass der Befehl snapshot nur die v3-Daten sichert. Informationen zu v2-Daten finden Sie unter Backup des v2-Datenspeichers .

Gemischte Versionen

Während des Upgrades unterstützt ein etcd-Cluster Mitglieder mit gemischten etcd-Versionen und verwendet das Protokoll der niedrigsten gemeinsamen Version. Der Cluster gilt erst als aktualisiert, wenn alle Mitglieder auf Version 3.3 aktualisiert wurden. Intern handeln die etcd-Mitglieder untereinander die Gesamtversion des Clusters aus, die die gemeldete Version und die unterstützten Funktionen bestimmt.

Einschränkungen

Hinweis: Wenn der Cluster nur v3-Daten und keine v2-Daten enthält, gilt diese Einschränkung nicht.

Wenn der Cluster einen v2-Datenbestand von mehr als 50MB bereitstellt, kann es bis zu zwei Minuten dauern, bis jedes neu aktualisierte Mitglied zum bestehenden Cluster aufgeschlossen hat. Prüfen Sie die Größe eines aktuellen Snapshots, um die Gesamtdatenmenge abzuschätzen. Anders ausgedrückt ist es am sichersten, zwischen den Upgrades der einzelnen Mitglieder jeweils 2 Minuten zu warten.

Bei einer deutlich größeren Gesamtdatenmenge von 100MB oder mehr kann dieser einmalige Vorgang noch länger dauern. Administratoren sehr großer etcd-Cluster dieser Größenordnung können vor dem Upgrade das etcd-Team kontaktieren; wir beraten Sie gern zum Vorgehen.

Downgrade

Wenn alle Mitglieder auf v3.3 aktualisiert wurden, wird der Cluster auf v3.3 aktualisiert; ein Downgrade aus diesem abgeschlossenen Zustand ist nicht möglich. Solange jedoch noch ein einziges Mitglied v3.2 verwendet, bleiben der Cluster und sein Betrieb auf „v3.2“. Aus diesem Zustand mit gemischten Versionen ist es möglich, auf allen Mitgliedern wieder eine etcd-v3.2-Binärdatei zu verwenden.

Erstellen Sie ein Backup des Datenverzeichnisses aller etcd-Mitglieder, um ein Downgrade des Clusters auch nach einem vollständig abgeschlossenen Upgrade zu ermöglichen.

Upgrade-Verfahren

Dieses Beispiel zeigt das Upgrade eines etcd-v3.2-Clusters mit 3 Mitgliedern, der auf einem lokalen Rechner läuft.

1. Upgrade-Voraussetzungen prüfen

Ist der Cluster fehlerfrei und läuft er mit v3.2.x?

$ ETCDCTL_API=3 etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
localhost:2379 is healthy: successfully committed proposal: took = 6.600684ms
localhost:22379 is healthy: successfully committed proposal: took = 8.540064ms
localhost:32379 is healthy: successfully committed proposal: took = 8.763432ms

$ curl http://localhost:2379/version
{"etcdserver":"3.2.7","etcdcluster":"3.2.0"}

2. Den bestehenden etcd-Prozess stoppen

Wenn ein etcd-Prozess gestoppt wird, protokollieren die anderen Cluster-Mitglieder erwartete Fehler. Dies ist normal, da die Verbindung zu einem Cluster-Mitglied (vorübergehend) unterbrochen wurde:

14:13:31.491746 I | raft: c89feb932daef420 [term 3] received MsgTimeoutNow from 6d4f535bae3ab960 and starts an election to get leadership.
14:13:31.491769 I | raft: c89feb932daef420 became candidate at term 4
14:13:31.491788 I | raft: c89feb932daef420 received MsgVoteResp from c89feb932daef420 at term 4
14:13:31.491797 I | raft: c89feb932daef420 [logterm: 3, index: 9] sent MsgVote request to 6d4f535bae3ab960 at term 4
14:13:31.491805 I | raft: c89feb932daef420 [logterm: 3, index: 9] sent MsgVote request to 9eda174c7df8a033 at term 4
14:13:31.491815 I | raft: raft.node: c89feb932daef420 lost leader 6d4f535bae3ab960 at term 4
14:13:31.524084 I | raft: c89feb932daef420 received MsgVoteResp from 6d4f535bae3ab960 at term 4
14:13:31.524108 I | raft: c89feb932daef420 [quorum:2] has received 2 MsgVoteResp votes and 0 vote rejections
14:13:31.524123 I | raft: c89feb932daef420 became leader at term 4
14:13:31.524136 I | raft: raft.node: c89feb932daef420 elected leader c89feb932daef420 at term 4
14:13:31.592650 W | rafthttp: lost the TCP streaming connection with peer 6d4f535bae3ab960 (stream MsgApp v2 reader)
14:13:31.592825 W | rafthttp: lost the TCP streaming connection with peer 6d4f535bae3ab960 (stream Message reader)
14:13:31.693275 E | rafthttp: failed to dial 6d4f535bae3ab960 on stream Message (dial tcp [::1]:2380: getsockopt: connection refused)
14:13:31.693289 I | rafthttp: peer 6d4f535bae3ab960 became inactive
14:13:31.936678 W | rafthttp: lost the TCP streaming connection with peer 6d4f535bae3ab960 (stream Message writer)

An dieser Stelle empfiehlt es sich, ein Backup der etcd-Daten zu erstellen , um bei Problemen ein Downgrade durchführen zu können:

$ etcdctl snapshot save backup.db

3. Die etcd-v3.3-Binärdatei einsetzen und den neuen etcd-Prozess starten

Das neue etcd v3.3 veröffentlicht seine Informationen im Cluster:

14:14:25.363225 I | etcdserver: published {Name:s1 ClientURLs:[http://localhost:2379]} to cluster a9ededbffcb1b1f1

Prüfen Sie, ob jedes Mitglied und anschließend der gesamte Cluster mit der neuen etcd-v3.3-Binärdatei wieder fehlerfrei ist:

$ ETCDCTL_API=3 /etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
localhost:22379 is healthy: successfully committed proposal: took = 5.540129ms
localhost:32379 is healthy: successfully committed proposal: took = 7.321771ms
localhost:2379 is healthy: successfully committed proposal: took = 10.629901ms

Aktualisierte Mitglieder protokollieren Warnungen wie die folgenden, bis der gesamte Cluster aktualisiert ist. Dies ist zu erwarten und endet, sobald alle etcd-Cluster-Mitglieder auf v3.3 aktualisiert wurden:

14:15:17.071804 W | etcdserver: member c89feb932daef420 has a higher version 3.3.0
14:15:21.073110 W | etcdserver: the local etcd version 3.2.7 is not up-to-date
14:15:21.073142 W | etcdserver: member 6d4f535bae3ab960 has a higher version 3.3.0
14:15:21.073157 W | etcdserver: the local etcd version 3.2.7 is not up-to-date
14:15:21.073164 W | etcdserver: member c89feb932daef420 has a higher version 3.3.0

4. Schritt 2 bis Schritt 3 für alle anderen Mitglieder wiederholen

5. Abschluss

Sobald alle Mitglieder aktualisiert wurden, meldet der Cluster den erfolgreichen Abschluss des Upgrades auf 3.3:

14:15:54.536901 N | etcdserver/membership: updated the cluster version from 3.2 to 3.3
14:15:54.537035 I | etcdserver/api: enabled capabilities for version 3.3
$ ETCDCTL_API=3 /etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
localhost:2379 is healthy: successfully committed proposal: took = 2.312897ms
localhost:22379 is healthy: successfully committed proposal: took = 2.553476ms
localhost:32379 is healthy: successfully committed proposal: took = 2.517902ms

17.7 - Upgrade von etcd 3.1 auf 3.2

Verfahren, Checklisten und Hinweise zum Upgrade von etcd 3.1 auf 3.2

Im Allgemeinen kann das Upgrade von etcd 3.1 auf 3.2 als Rolling Upgrade ohne Ausfallzeit erfolgen:

  • Die etcd-v3.1-Prozesse nacheinander stoppen und durch etcd-v3.2-Prozesse ersetzen.
  • Sobald alle v3.2-Prozesse laufen, stehen dem Cluster die neuen Funktionen von v3.2 zur Verfügung.

Lesen Sie zur Vorbereitung den Rest dieses Leitfadens, bevor Sie mit dem Upgrade beginnen .

Checklisten für das Upgrade

Warnung

Bei der Migration von v2 ohne v3-Daten löst der etcd-Server v3.2+ eine Panic aus, wenn etcd aus vorhandenen Snapshots wiederhergestellt wird, aber keine v3-Datei ETCD_DATA_DIR/member/snap/db vorhanden ist. Dies tritt auf, wenn der Server von v2 migriert wurde, ohne zuvor v3-Daten zu enthalten. Dadurch wird auch ein versehentlicher Verlust von v3-Daten verhindert (z. B. könnte die Datei db verschoben worden sein). etcd verlangt, dass weitere Migrationen nach der Migration auf v3 nur mit v3-Daten erfolgen können. Führen Sie kein Upgrade auf neuere v3-Versionen durch, bevor der v3.0-Server v3-Daten enthält.

Wichtige inkompatible Änderungen in 3.2.

Geänderter Standardwert für snapshot-count

Ein höherer Wert für --snapshot-count hält bis zum Snapshot mehr Raft-Einträge im Speicher und führt dadurch zu wiederholt höherer Speichernutzung . Da der Leader die neuesten Raft-Einträge länger vorhält, hat ein langsamer Follower mehr Zeit, vor dem Snapshot des Leaders aufzuholen. --snapshot-count stellt einen Kompromiss zwischen höherer Speichernutzung und besserer Verfügbarkeit langsamer Follower dar.

Seit v3.2 wurde der Standardwert von --snapshot-count von 10,000 auf 100,000 geändert .

Geänderte gRPC-Abhängigkeit (>=3.2.10)

3.2.10 oder höher benötigt jetzt grpc/grpc-go v1.7.5 (<=3.2.9 benötigt v1.2.1).

grpclog.Logger ist veraltet

grpclog.Logger ist zugunsten von grpclog.LoggerV2 veraltet. clientv3.Logger ist jetzt grpclog.LoggerV2.

Vorher

import "github.com/coreos/etcd/clientv3"
clientv3.SetLogger(log.New(os.Stderr, "grpc: ", 0))

Nachher

import "github.com/coreos/etcd/clientv3"
import "google.golang.org/grpc/grpclog"
clientv3.SetLogger(grpclog.NewLoggerV2(os.Stderr, os.Stderr, os.Stderr))

// log.New above cannot be used (not implement grpclog.LoggerV2 interface)
grpc.ErrClientConnTimeout ist veraltet

Bisher wurde bei Zeitüberschreitungen beim Verbindungsaufbau des Clients der Fehler grpc.ErrClientConnTimeout zurückgegeben. 3.2 gibt stattdessen context.DeadlineExceeded zurück (siehe #8504 ).

Vorher

// expect dial time-out on ipv4 blackhole
_, err := clientv3.New(clientv3.Config{
    Endpoints:   []string{"http://254.0.0.1:12345"},
    DialTimeout: 2 * time.Second
})
if err == grpc.ErrClientConnTimeout {
	// handle errors
}

Nachher

_, err := clientv3.New(clientv3.Config{
    Endpoints:   []string{"http://254.0.0.1:12345"},
    DialTimeout: 2 * time.Second
})
if err == context.DeadlineExceeded {
	// handle errors
}

Geänderte Obergrenzen für die Anfragegröße (>=3.2.10)

3.2.10 und 3.2.11 erlauben benutzerdefinierte Größenlimits für Anfragen auf der Serverseite. >=3.2.12 erlaubt benutzerdefinierte Größenlimits für Anfragen sowohl auf der Server- als auch auf der Clientseite. In früheren Versionen (v3.2.10, v3.2.11) war die Größe der Antworten an Clients auf nur 4 MiB begrenzt.

Serverseitige Anfragelimits lassen sich mit dem Flag --max-request-bytes konfigurieren:

# limits request size to 1.5 KiB
etcd --max-request-bytes 1536

# client writes exceeding 1.5 KiB will be rejected
etcdctl put foo [LARGE VALUE...]
# etcdserver: request is too large

Oder konfigurieren Sie das Feld embed.Config.MaxRequestBytes:

import "github.com/coreos/etcd/embed"
import "github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"

// limit requests to 5 MiB
cfg := embed.NewConfig()
cfg.MaxRequestBytes = 5 * 1024 * 1024

// client writes exceeding 5 MiB will be rejected
_, err := cli.Put(ctx, "foo", [LARGE VALUE...])
err == rpctypes.ErrRequestTooLarge

Ohne Angabe beträgt das serverseitige Limit standardmäßig 1.5 MiB.

Clientseitige Anfragelimits müssen anhand der serverseitigen Limits konfiguriert werden.

# limits request size to 1 MiB
etcd --max-request-bytes 1048576
import "github.com/coreos/etcd/clientv3"

cli, _ := clientv3.New(clientv3.Config{
    Endpoints: []string{"127.0.0.1:2379"},
    MaxCallSendMsgSize: 2 * 1024 * 1024,
    MaxCallRecvMsgSize: 3 * 1024 * 1024,
})


// client writes exceeding "--max-request-bytes" will be rejected from etcd server
_, err := cli.Put(ctx, "foo", strings.Repeat("a", 1*1024*1024+5))
err == rpctypes.ErrRequestTooLarge


// client writes exceeding "MaxCallSendMsgSize" will be rejected from client-side
_, err = cli.Put(ctx, "foo", strings.Repeat("a", 5*1024*1024))
err.Error() == "rpc error: code = ResourceExhausted desc = grpc: trying to send message larger than max (5242890 vs. 2097152)"


// some writes under limits
for i := range []int{0,1,2,3,4} {
    _, err = cli.Put(ctx, fmt.Sprintf("foo%d", i), strings.Repeat("a", 1*1024*1024-500))
    if err != nil {
        panic(err)
    }
}
// client reads exceeding "MaxCallRecvMsgSize" will be rejected from client-side
_, err = cli.Get(ctx, "foo", clientv3.WithPrefix())
err.Error() == "rpc error: code = ResourceExhausted desc = grpc: received message larger than max (5240509 vs. 3145728)"

Ohne Angabe beträgt das clientseitige Sendelimit standardmäßig 2 MiB (1.5 MiB + zusätzliche gRPC-Bytes) und das Empfangslimit math.MaxInt32. Weitere Einzelheiten finden Sie in der clientv3-godoc-Dokumentation .

Geänderte Wrapper für direkte gRPC-Clients

3.2.12 oder höher ändert die Funktionssignaturen des gRPC-Client-Wrappers von clientv3. Diese Änderung war erforderlich, um benutzerdefinierte grpc.CallOption für Nachrichtengrößenlimits zu unterstützen.

Vorher und nachher

-func NewKVFromKVClient(remote pb.KVClient) KV {
+func NewKVFromKVClient(remote pb.KVClient, c *Client) KV {

-func NewClusterFromClusterClient(remote pb.ClusterClient) Cluster {
+func NewClusterFromClusterClient(remote pb.ClusterClient, c *Client) Cluster {

-func NewLeaseFromLeaseClient(remote pb.LeaseClient, keepAliveTimeout time.Duration) Lease {
+func NewLeaseFromLeaseClient(remote pb.LeaseClient, c *Client, keepAliveTimeout time.Duration) Lease {

-func NewMaintenanceFromMaintenanceClient(remote pb.MaintenanceClient) Maintenance {
+func NewMaintenanceFromMaintenanceClient(remote pb.MaintenanceClient, c *Client) Maintenance {

-func NewWatchFromWatchClient(wc pb.WatchClient) Watcher {
+func NewWatchFromWatchClient(wc pb.WatchClient, c *Client) Watcher {

Geänderte API clientv3.Lease.TimeToLive

Bisher gab die API clientv3.Lease.TimeToLive bei einer nicht vorhandenen Lease-ID lease.ErrLeaseNotFound zurück. 3.2 gibt stattdessen TTL=-1 in der Antwort und keinen Fehler zurück (siehe #7305 ).

Vorher

// when leaseID does not exist
resp, err := TimeToLive(ctx, leaseID)
resp == nil
err == lease.ErrLeaseNotFound

Nachher

// when leaseID does not exist
resp, err := TimeToLive(ctx, leaseID)
resp.TTL == -1
err == nil

clientv3.NewFromConfigFile nach clientv3.yaml.NewConfig verschoben

clientv3.NewFromConfigFile wurde nach yaml.NewConfig verschoben.

Vorher

import "github.com/coreos/etcd/clientv3"
clientv3.NewFromConfigFile

Nachher

import clientv3yaml "github.com/coreos/etcd/clientv3/yaml"
clientv3yaml.NewConfig

Änderung an --listen-peer-urls und --listen-client-urls

3.2 weist jetzt Domainnamen für --listen-peer-urls und --listen-client-urls zurück (3.1 gibt nur Warnungen aus), da ein Domainname für die Bindung an eine Netzwerkschnittstelle ungültig ist. Stellen Sie sicher, dass diese URLs korrekt als scheme://IP:port formatiert sind.

Weitere Hintergründe finden Sie in Issue #6336 .

Checklisten für das Server-Upgrade

Upgrade-Voraussetzungen

Um eine bestehende etcd-Installation auf 3.2 zu aktualisieren, muss der laufende Cluster Version 3.1 oder höher verwenden. Falls er eine ältere Version als 3.1 verwendet, führen Sie vor dem Upgrade auf 3.2 zunächst ein Upgrade auf 3.1 durch.

Außerdem muss der laufende Cluster fehlerfrei sein, damit das Rolling Upgrade reibungslos verläuft. Prüfen Sie den Zustand des Clusters mit dem Befehl etcdctl endpoint health, bevor Sie fortfahren.

Vorbereitung

Testen Sie vor einem etcd-Upgrade immer die von etcd abhängigen Dienste in einer Staging-Umgebung, bevor Sie das Upgrade in der Produktionsumgebung durchführen.

Erstellen Sie vor Beginn ein Backup der etcd-Daten . Falls beim Upgrade etwas schiefgeht, können Sie mit diesem Backup ein Downgrade auf die bestehende etcd-Version durchführen. Beachten Sie, dass der Befehl snapshot nur die v3-Daten sichert. Informationen zu v2-Daten finden Sie unter Backup des v2-Datenspeichers .

Gemischte Versionen

Während des Upgrades unterstützt ein etcd-Cluster Mitglieder mit gemischten etcd-Versionen und verwendet das Protokoll der niedrigsten gemeinsamen Version. Der Cluster gilt erst als aktualisiert, wenn alle Mitglieder auf Version 3.2 aktualisiert wurden. Intern handeln die etcd-Mitglieder untereinander die Gesamtversion des Clusters aus, die die gemeldete Version und die unterstützten Funktionen bestimmt.

Einschränkungen

Hinweis: Wenn der Cluster nur v3-Daten und keine v2-Daten enthält, gilt diese Einschränkung nicht.

Wenn der Cluster einen v2-Datenbestand von mehr als 50MB bereitstellt, kann es bis zu zwei Minuten dauern, bis jedes neu aktualisierte Mitglied zum bestehenden Cluster aufgeschlossen hat. Prüfen Sie die Größe eines aktuellen Snapshots, um die Gesamtdatenmenge abzuschätzen. Anders ausgedrückt ist es am sichersten, zwischen den Upgrades der einzelnen Mitglieder jeweils 2 Minuten zu warten.

Bei einer deutlich größeren Gesamtdatenmenge von 100MB oder mehr kann dieser einmalige Vorgang noch länger dauern. Administratoren sehr großer etcd-Cluster dieser Größenordnung können vor dem Upgrade das etcd-Team kontaktieren; wir beraten Sie gern zum Vorgehen.

Downgrade

Wenn alle Mitglieder auf v3.2 aktualisiert wurden, wird der Cluster auf v3.2 aktualisiert; ein Downgrade aus diesem abgeschlossenen Zustand ist nicht möglich. Solange jedoch noch ein einziges Mitglied v3.1 verwendet, bleiben der Cluster und sein Betrieb auf „v3.1“. Aus diesem Zustand mit gemischten Versionen ist es möglich, auf allen Mitgliedern wieder eine etcd-v3.1-Binärdatei zu verwenden.

Erstellen Sie ein Backup des Datenverzeichnisses aller etcd-Mitglieder, um ein Downgrade des Clusters auch nach einem vollständig abgeschlossenen Upgrade zu ermöglichen.

Upgrade-Verfahren

Dieses Beispiel zeigt das Upgrade eines etcd-v3.1-Clusters mit 3 Mitgliedern, der auf einem lokalen Rechner läuft.

1. Upgrade-Voraussetzungen prüfen

Ist der Cluster fehlerfrei und läuft er mit v3.1.x?

$ ETCDCTL_API=3 etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
localhost:2379 is healthy: successfully committed proposal: took = 6.600684ms
localhost:22379 is healthy: successfully committed proposal: took = 8.540064ms
localhost:32379 is healthy: successfully committed proposal: took = 8.763432ms

$ curl http://localhost:2379/version
{"etcdserver":"3.1.7","etcdcluster":"3.1.0"}

2. Den bestehenden etcd-Prozess stoppen

Wenn ein etcd-Prozess gestoppt wird, protokollieren die anderen Cluster-Mitglieder erwartete Fehler. Dies ist normal, da die Verbindung zu einem Cluster-Mitglied (vorübergehend) unterbrochen wurde:

2017-04-27 14:13:31.491746 I | raft: c89feb932daef420 [term 3] received MsgTimeoutNow from 6d4f535bae3ab960 and starts an election to get leadership.
2017-04-27 14:13:31.491769 I | raft: c89feb932daef420 became candidate at term 4
2017-04-27 14:13:31.491788 I | raft: c89feb932daef420 received MsgVoteResp from c89feb932daef420 at term 4
2017-04-27 14:13:31.491797 I | raft: c89feb932daef420 [logterm: 3, index: 9] sent MsgVote request to 6d4f535bae3ab960 at term 4
2017-04-27 14:13:31.491805 I | raft: c89feb932daef420 [logterm: 3, index: 9] sent MsgVote request to 9eda174c7df8a033 at term 4
2017-04-27 14:13:31.491815 I | raft: raft.node: c89feb932daef420 lost leader 6d4f535bae3ab960 at term 4
2017-04-27 14:13:31.524084 I | raft: c89feb932daef420 received MsgVoteResp from 6d4f535bae3ab960 at term 4
2017-04-27 14:13:31.524108 I | raft: c89feb932daef420 [quorum:2] has received 2 MsgVoteResp votes and 0 vote rejections
2017-04-27 14:13:31.524123 I | raft: c89feb932daef420 became leader at term 4
2017-04-27 14:13:31.524136 I | raft: raft.node: c89feb932daef420 elected leader c89feb932daef420 at term 4
2017-04-27 14:13:31.592650 W | rafthttp: lost the TCP streaming connection with peer 6d4f535bae3ab960 (stream MsgApp v2 reader)
2017-04-27 14:13:31.592825 W | rafthttp: lost the TCP streaming connection with peer 6d4f535bae3ab960 (stream Message reader)
2017-04-27 14:13:31.693275 E | rafthttp: failed to dial 6d4f535bae3ab960 on stream Message (dial tcp [::1]:2380: getsockopt: connection refused)
2017-04-27 14:13:31.693289 I | rafthttp: peer 6d4f535bae3ab960 became inactive
2017-04-27 14:13:31.936678 W | rafthttp: lost the TCP streaming connection with peer 6d4f535bae3ab960 (stream Message writer)

An dieser Stelle empfiehlt es sich, ein Backup der etcd-Daten zu erstellen , um bei Problemen ein Downgrade durchführen zu können:

$ etcdctl snapshot save backup.db

3. Die etcd-v3.2-Binärdatei einsetzen und den neuen etcd-Prozess starten

Das neue etcd v3.2 veröffentlicht seine Informationen im Cluster:

2017-04-27 14:14:25.363225 I | etcdserver: published {Name:s1 ClientURLs:[http://localhost:2379]} to cluster a9ededbffcb1b1f1

Prüfen Sie, ob jedes Mitglied und anschließend der gesamte Cluster mit der neuen etcd-v3.2-Binärdatei wieder fehlerfrei ist:

$ ETCDCTL_API=3 /etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
localhost:22379 is healthy: successfully committed proposal: took = 5.540129ms
localhost:32379 is healthy: successfully committed proposal: took = 7.321771ms
localhost:2379 is healthy: successfully committed proposal: took = 10.629901ms

Aktualisierte Mitglieder protokollieren Warnungen wie die folgenden, bis der gesamte Cluster aktualisiert ist. Dies ist zu erwarten und endet, sobald alle etcd-Cluster-Mitglieder auf v3.2 aktualisiert wurden:

2017-04-27 14:15:17.071804 W | etcdserver: member c89feb932daef420 has a higher version 3.2.0
2017-04-27 14:15:21.073110 W | etcdserver: the local etcd version 3.1.7 is not up-to-date
2017-04-27 14:15:21.073142 W | etcdserver: member 6d4f535bae3ab960 has a higher version 3.2.0
2017-04-27 14:15:21.073157 W | etcdserver: the local etcd version 3.1.7 is not up-to-date
2017-04-27 14:15:21.073164 W | etcdserver: member c89feb932daef420 has a higher version 3.2.0

4. Schritt 2 bis Schritt 3 für alle anderen Mitglieder wiederholen

5. Abschluss

Sobald alle Mitglieder aktualisiert wurden, meldet der Cluster den erfolgreichen Abschluss des Upgrades auf 3.2:

2017-04-27 14:15:54.536901 N | etcdserver/membership: updated the cluster version from 3.1 to 3.2
2017-04-27 14:15:54.537035 I | etcdserver/api: enabled capabilities for version 3.2
$ ETCDCTL_API=3 /etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
localhost:2379 is healthy: successfully committed proposal: took = 2.312897ms
localhost:22379 is healthy: successfully committed proposal: took = 2.553476ms
localhost:32379 is healthy: successfully committed proposal: took = 2.517902ms

17.8 - Upgrade von etcd 3.0 auf 3.1

Verfahren, Checklisten und Hinweise zum Upgrade von etcd 3.0 auf 3.1

Im Allgemeinen kann das Upgrade von etcd 3.0 auf 3.1 als Rolling Upgrade ohne Ausfallzeit erfolgen:

  • Die etcd-v3.0-Prozesse nacheinander stoppen und durch etcd-v3.1-Prozesse ersetzen.
  • Sobald alle v3.1-Prozesse laufen, stehen dem Cluster die neuen Funktionen von v3.1 zur Verfügung.

Lesen Sie zur Vorbereitung den Rest dieses Leitfadens, bevor Sie mit dem Upgrade beginnen .

Checklisten für das Upgrade

Warnung

Bei der Migration von v2 ohne v3-Daten löst der etcd-Server v3.2+ eine Panic aus, wenn etcd aus vorhandenen Snapshots wiederhergestellt wird, aber keine v3-Datei ETCD_DATA_DIR/member/snap/db vorhanden ist. Dies tritt auf, wenn der Server von v2 migriert wurde, ohne zuvor v3-Daten zu enthalten. Dadurch wird auch ein versehentlicher Verlust von v3-Daten verhindert (z. B. könnte die Datei db verschoben worden sein). etcd verlangt, dass weitere Migrationen nach der Migration auf v3 nur mit v3-Daten erfolgen können. Führen Sie kein Upgrade auf neuere v3-Versionen durch, bevor der v3.0-Server v3-Daten enthält.

Überwachung

Die folgenden Metriken aus v3.0.x sind zugunsten von go-grpc-prometheus veraltet:

  • etcd_grpc_requests_total
  • etcd_grpc_requests_failed_total
  • etcd_grpc_active_streams
  • etcd_grpc_unary_requests_duration_seconds

Upgrade-Voraussetzungen

Um eine bestehende etcd-Installation auf 3.1 zu aktualisieren, muss der laufende Cluster Version 3.0 oder höher verwenden. Falls er eine ältere Version als 3.0 verwendet, führen Sie vor dem Upgrade auf 3.1 zunächst ein Upgrade auf 3.0 durch.

Außerdem muss der laufende Cluster fehlerfrei sein, damit das Rolling Upgrade reibungslos verläuft. Prüfen Sie den Zustand des Clusters mit dem Befehl etcdctl endpoint health, bevor Sie fortfahren.

Vorbereitung

Testen Sie vor einem etcd-Upgrade immer die von etcd abhängigen Dienste in einer Staging-Umgebung, bevor Sie das Upgrade in der Produktionsumgebung durchführen.

Erstellen Sie vor Beginn ein Backup der etcd-Daten . Falls beim Upgrade etwas schiefgeht, können Sie mit diesem Backup ein Downgrade auf die bestehende etcd-Version durchführen. Beachten Sie, dass der Befehl snapshot nur die v3-Daten sichert. Informationen zu v2-Daten finden Sie unter Backup des v2-Datenspeichers .

Gemischte Versionen

Während des Upgrades unterstützt ein etcd-Cluster Mitglieder mit gemischten etcd-Versionen und verwendet das Protokoll der niedrigsten gemeinsamen Version. Der Cluster gilt erst als aktualisiert, wenn alle Mitglieder auf Version 3.1 aktualisiert wurden. Intern handeln die etcd-Mitglieder untereinander die Gesamtversion des Clusters aus, die die gemeldete Version und die unterstützten Funktionen bestimmt.

Einschränkungen

Hinweis: Wenn der Cluster nur v3-Daten und keine v2-Daten enthält, gilt diese Einschränkung nicht.

Wenn der Cluster einen v2-Datenbestand von mehr als 50MB bereitstellt, kann es bis zu zwei Minuten dauern, bis jedes neu aktualisierte Mitglied zum bestehenden Cluster aufgeschlossen hat. Prüfen Sie die Größe eines aktuellen Snapshots, um die Gesamtdatenmenge abzuschätzen. Anders ausgedrückt ist es am sichersten, zwischen den Upgrades der einzelnen Mitglieder jeweils 2 Minuten zu warten.

Bei einer deutlich größeren Gesamtdatenmenge von 100MB oder mehr kann dieser einmalige Vorgang noch länger dauern. Administratoren sehr großer etcd-Cluster dieser Größenordnung können vor dem Upgrade das etcd-Team kontaktieren; wir beraten Sie gern zum Vorgehen.

Downgrade

Wenn alle Mitglieder auf v3.1 aktualisiert wurden, wird der Cluster auf v3.1 aktualisiert; ein Downgrade aus diesem abgeschlossenen Zustand ist nicht möglich. Solange jedoch noch ein einziges Mitglied v3.0 verwendet, bleiben der Cluster und sein Betrieb auf „v3.0“. Aus diesem Zustand mit gemischten Versionen ist es möglich, auf allen Mitgliedern wieder eine etcd-v3.0-Binärdatei zu verwenden.

Erstellen Sie ein Backup des Datenverzeichnisses aller etcd-Mitglieder, um ein Downgrade des Clusters auch nach einem vollständig abgeschlossenen Upgrade zu ermöglichen.

Upgrade-Verfahren

Dieses Beispiel zeigt das Upgrade eines etcd-v3.0-Clusters mit 3 Mitgliedern, der auf einem lokalen Rechner läuft.

1. Upgrade-Voraussetzungen prüfen

Ist der Cluster fehlerfrei und läuft er mit v3.0.x?

$ ETCDCTL_API=3 etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
localhost:2379 is healthy: successfully committed proposal: took = 6.600684ms
localhost:22379 is healthy: successfully committed proposal: took = 8.540064ms
localhost:32379 is healthy: successfully committed proposal: took = 8.763432ms

$ curl http://localhost:2379/version
{"etcdserver":"3.0.16","etcdcluster":"3.0.0"}

2. Den bestehenden etcd-Prozess stoppen

Wenn ein etcd-Prozess gestoppt wird, protokollieren die anderen Cluster-Mitglieder erwartete Fehler. Dies ist normal, da die Verbindung zu einem Cluster-Mitglied (vorübergehend) unterbrochen wurde:

2017-01-17 09:34:18.352662 I | raft: raft.node: 1640829d9eea5cfb elected leader 1640829d9eea5cfb at term 5
2017-01-17 09:34:18.359630 W | etcdserver: failed to reach the peerURL(http://localhost:2380) of member fd32987dcd0511e0 (Get http://localhost:2380/version: dial tcp 127.0.0.1:2380: getsockopt: connection refused)
2017-01-17 09:34:18.359679 W | etcdserver: cannot get the version of member fd32987dcd0511e0 (Get http://localhost:2380/version: dial tcp 127.0.0.1:2380: getsockopt: connection refused)
2017-01-17 09:34:18.548116 W | rafthttp: lost the TCP streaming connection with peer fd32987dcd0511e0 (stream Message writer)
2017-01-17 09:34:19.147816 W | rafthttp: lost the TCP streaming connection with peer fd32987dcd0511e0 (stream MsgApp v2 writer)
2017-01-17 09:34:34.364907 W | etcdserver: failed to reach the peerURL(http://localhost:2380) of member fd32987dcd0511e0 (Get http://localhost:2380/version: dial tcp 127.0.0.1:2380: getsockopt: connection refused)

An dieser Stelle empfiehlt es sich, ein Backup der etcd-Daten zu erstellen , um bei Problemen ein Downgrade durchführen zu können:

$ etcdctl snapshot save backup.db

3. Die etcd-v3.1-Binärdatei einsetzen und den neuen etcd-Prozess starten

Das neue etcd v3.1 veröffentlicht seine Informationen im Cluster:

2017-01-17 09:36:00.996590 I | etcdserver: published {Name:my-etcd-1 ClientURLs:[http://localhost:2379]} to cluster 46bc3ce73049e678

Prüfen Sie, ob jedes Mitglied und anschließend der gesamte Cluster mit der neuen etcd-v3.1-Binärdatei wieder fehlerfrei ist:

$ ETCDCTL_API=3 /etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
localhost:22379 is healthy: successfully committed proposal: took = 5.540129ms
localhost:32379 is healthy: successfully committed proposal: took = 7.321671ms
localhost:2379 is healthy: successfully committed proposal: took = 10.629901ms

Aktualisierte Mitglieder protokollieren Warnungen wie die folgenden, bis der gesamte Cluster aktualisiert ist. Dies ist zu erwarten und endet, sobald alle etcd-Cluster-Mitglieder auf v3.1 aktualisiert wurden:

2017-01-17 09:36:38.406268 W | etcdserver: the local etcd version 3.0.16 is not up-to-date
2017-01-17 09:36:38.406295 W | etcdserver: member fd32987dcd0511e0 has a higher version 3.1.0
2017-01-17 09:36:42.407695 W | etcdserver: the local etcd version 3.0.16 is not up-to-date
2017-01-17 09:36:42.407730 W | etcdserver: member fd32987dcd0511e0 has a higher version 3.1.0

4. Schritt 2 bis Schritt 3 für alle anderen Mitglieder wiederholen

5. Abschluss

Sobald alle Mitglieder aktualisiert wurden, meldet der Cluster den erfolgreichen Abschluss des Upgrades auf 3.1:

2017-01-17 09:37:03.100015 I | etcdserver: updating the cluster version from 3.0 to 3.1
2017-01-17 09:37:03.104263 N | etcdserver/membership: updated the cluster version from 3.0 to 3.1
2017-01-17 09:37:03.104374 I | etcdserver/api: enabled capabilities for version 3.1
$ ETCDCTL_API=3 /etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
localhost:2379 is healthy: successfully committed proposal: took = 2.312897ms
localhost:22379 is healthy: successfully committed proposal: took = 2.553476ms
localhost:32379 is healthy: successfully committed proposal: took = 2.516902ms

17.9 - Upgrade von etcd 2.3 auf 3.0

Verfahren, Checklisten und Hinweise zum Upgrade von etcd 2.3 auf 3.0

Im Allgemeinen kann das Upgrade von etcd 2.3 auf 3.0 als Rolling Upgrade ohne Ausfallzeit erfolgen:

  • Die etcd-v2.3-Prozesse nacheinander stoppen und durch etcd-v3.0-Prozesse ersetzen.
  • Sobald alle v3.0-Prozesse laufen, stehen dem Cluster die neuen Funktionen von v3.0 zur Verfügung.

Lesen Sie zur Vorbereitung den Rest dieses Leitfadens, bevor Sie mit dem Upgrade beginnen .

Checklisten für das Upgrade

Warnung

Bei der Migration von v2 ohne v3-Daten löst der etcd-Server v3.2+ eine Panic aus, wenn etcd aus vorhandenen Snapshots wiederhergestellt wird, aber keine v3-Datei ETCD_DATA_DIR/member/snap/db vorhanden ist. Dies tritt auf, wenn der Server von v2 migriert wurde, ohne zuvor v3-Daten zu enthalten. Dadurch wird auch ein versehentlicher Verlust von v3-Daten verhindert (z. B. könnte die Datei db verschoben worden sein). etcd verlangt, dass weitere Migrationen nach der Migration auf v3 nur mit v3-Daten erfolgen können. Führen Sie kein Upgrade auf neuere v3-Versionen durch, bevor der v3.0-Server v3-Daten enthält.

Upgrade-Voraussetzungen

Um eine bestehende etcd-Installation auf 3.0 zu aktualisieren, muss der laufende Cluster Version 2.3 oder höher verwenden. Falls er eine ältere Version als 2.3 verwendet, aktualisieren Sie vor dem Upgrade auf 3.0 zunächst auf 2.3 .

Außerdem muss der laufende Cluster fehlerfrei sein, damit das Rolling Upgrade reibungslos verläuft. Prüfen Sie den Zustand des Clusters mit dem Befehl etcdctl cluster-health, bevor Sie fortfahren.

Vorbereitung

Testen Sie vor einem etcd-Upgrade immer die von etcd abhängigen Dienste in einer Staging-Umgebung, bevor Sie das Upgrade in der Produktionsumgebung durchführen.

Erstellen Sie vor Beginn ein Backup des etcd-Datenverzeichnisses . Falls beim Upgrade etwas schiefgeht, können Sie mit diesem Backup ein Downgrade auf die bestehende etcd-Version durchführen.

Gemischte Versionen

Während des Upgrades unterstützt ein etcd-Cluster Mitglieder mit gemischten etcd-Versionen und verwendet das Protokoll der niedrigsten gemeinsamen Version. Der Cluster gilt erst als aktualisiert, wenn alle Mitglieder auf Version 3.0 aktualisiert wurden. Intern handeln die etcd-Mitglieder untereinander die Gesamtversion des Clusters aus, die die gemeldete Version und die unterstützten Funktionen bestimmt.

Einschränkungen

Bei einer Gesamtdatenmenge von mehr als 50MB kann es bis zu 2 Minuten dauern, bis das neu aktualisierte Mitglied zum bestehenden Cluster aufgeschlossen hat. Prüfen Sie die Größe eines aktuellen Snapshots, um die Gesamtdatenmenge abzuschätzen. Anders ausgedrückt ist es am sichersten, zwischen den Upgrades der einzelnen Mitglieder jeweils 2 Minuten zu warten.

Bei einer deutlich größeren Gesamtdatenmenge von 100MB oder mehr kann dieser einmalige Vorgang noch länger dauern. Administratoren sehr großer etcd-Cluster dieser Größenordnung können vor dem Upgrade das etcd-Team kontaktieren; wir beraten Sie gern zum Vorgehen.

Downgrade

Wenn alle Mitglieder auf v3.0 aktualisiert wurden, wird der Cluster auf v3.0 aktualisiert; ein Downgrade aus diesem abgeschlossenen Zustand ist nicht möglich. Solange jedoch noch ein einziges Mitglied v2.3 verwendet, bleiben der Cluster und sein Betrieb auf „v2.3“. Aus diesem Zustand mit gemischten Versionen ist es möglich, auf allen Mitgliedern wieder eine etcd-v2.3-Binärdatei zu verwenden.

Erstellen Sie ein Backup des Datenverzeichnisses aller etcd-Mitglieder, um ein Downgrade des Clusters auch nach einem vollständig abgeschlossenen Upgrade zu ermöglichen.

Upgrade-Verfahren

Dieses Beispiel beschreibt das Upgrade eines etcd-v2.3-Clusters mit drei Mitgliedern, der auf einem lokalen Rechner läuft.

1. Upgrade-Voraussetzungen prüfen.

Ist der Cluster fehlerfrei und läuft er mit v.2.3.x?

$ etcdctl cluster-health
member 6e3bd23ae5f1eae0 is healthy: got healthy result from http://localhost:22379
member 924e2e83e93f2560 is healthy: got healthy result from http://localhost:32379
member 8211f1d0f64f3269 is healthy: got healthy result from http://localhost:12379
cluster is healthy

$ curl http://localhost:2379/version
{"etcdserver":"2.3.x","etcdcluster":"2.3.8"}

2. Den bestehenden etcd-Prozess stoppen

Wenn ein etcd-Prozess gestoppt wird, protokollieren die anderen Cluster-Mitglieder erwartete Fehler. Dies ist normal, da die Verbindung zu einem Cluster-Mitglied (vorübergehend) unterbrochen wurde:

2016-06-27 15:21:48.624124 E | rafthttp: failed to dial 8211f1d0f64f3269 on stream Message (dial tcp 127.0.0.1:12380: getsockopt: connection refused)
2016-06-27 15:21:48.624175 I | rafthttp: the connection with 8211f1d0f64f3269 became inactive

An dieser Stelle empfiehlt es sich, ein Backup des etcd-Datenverzeichnisses zu erstellen , um bei Problemen ein Downgrade durchführen zu können:

$ etcdctl backup \
      --data-dir /var/lib/etcd \
      --backup-dir /tmp/etcd_backup

3. Die etcd-v3.0-Binärdatei einsetzen und den neuen etcd-Prozess starten

Das neue etcd v3.0 veröffentlicht seine Informationen im Cluster:

09:58:25.938673 I | etcdserver: published {Name:infra1 ClientURLs:[http://localhost:12379]} to cluster 524400597fb1d5f6

Prüfen Sie, ob jedes Mitglied und anschließend der gesamte Cluster mit der neuen etcd-v3.0-Binärdatei wieder fehlerfrei ist:

$ etcdctl cluster-health
member 6e3bd23ae5f1eae0 is healthy: got healthy result from http://localhost:22379
member 924e2e83e93f2560 is healthy: got healthy result from http://localhost:32379
member 8211f1d0f64f3269 is healthy: got healthy result from http://localhost:12379
cluster is healthy

Aktualisierte Mitglieder protokollieren Warnungen wie die folgenden, bis der gesamte Cluster aktualisiert ist. Dies ist zu erwarten und endet, sobald alle etcd-Cluster-Mitglieder auf v3.0 aktualisiert wurden:

2016-06-27 15:22:05.679644 W | etcdserver: the local etcd version 2.3.7 is not up-to-date
2016-06-27 15:22:05.679660 W | etcdserver: member 8211f1d0f64f3269 has a higher version 3.0.0

4. Schritt 2 bis Schritt 3 für alle anderen Mitglieder wiederholen

5. Abschluss

Sobald alle Mitglieder aktualisiert wurden, meldet der Cluster den erfolgreichen Abschluss des Upgrades auf 3.0:

2016-06-27 15:22:19.873751 N | membership: updated the cluster version from 2.3 to 3.0
2016-06-27 15:22:19.914574 I | api: enabled capabilities for version 3.0.0
$ ETCDCTL_API=3 etcdctl endpoint health
127.0.0.1:12379 is healthy: successfully committed proposal: took = 18.440155ms
127.0.0.1:32379 is healthy: successfully committed proposal: took = 13.651368ms
127.0.0.1:22379 is healthy: successfully committed proposal: took = 18.513301ms

Weitere Hinweise

  • Die Umgebungsvariablen von etcdctl wurden aktualisiert. Wenn ETCDCTL_API=2 etcdctl cluster-health ordnungsgemäß funktioniert, aber ETCDCTL_API=3 etcdctl endpoints health mit Error: grpc: timed out when dialing antwortet, verwenden Sie unbedingt die neuen Variablennamen .

Bekannte Probleme

  • etcd < v3.1 funktioniert nicht ordnungsgemäß, wenn es mit Go > v1.7 gebaut wurde. Weitere Informationen finden Sie in Issue 6951 .
  • Wenn in den etcd-Serverprotokollen ein Fehler wie transport: http2Client.notifyError got notified that the client transport was broken unexpected EOF. erscheint, stellen Sie sicher, dass etcd als vorgefertigtes Release vorliegt oder mit (etcd v3.1+ & go v1.7+) oder (etcd <v3.1 & go v1.6.x) gebaut wurde.
  • Das Hinzufügen eines v3-Knotens zu einem v2.3-Cluster während des Upgrades wird nicht unterstützt und könnte Panics auslösen. Weitere Informationen finden Sie in Issue 7249 . Gemischte Versionen von etcd-Mitgliedern sind nur während der v3-Migration zulässig. Schließen Sie die Upgrades ab, bevor Sie die Mitgliedschaft ändern.

18 - Triage

Änderungen an etcd verwalten

18.1 - Richtlinien zur Issue-Triage

Richtlinien zur Sichtung und Einordnung von etcd-Issues

Zweck

Die Verwaltung von Issues beschleunigen.

Die Issues für etcd sind unter https://github.com/etcd-io/etcd/issues aufgeführt und werden mit Labels gekennzeichnet. Ein als Fehler erkanntes Issue erhält beispielsweise das Label area/bug . Neue Issues haben zunächst keine Labels; üblicherweise ergänzen die Maintainer und aktiven Mitwirkenden von etcd sie anhand ihrer Erkenntnisse. Die vollständige Liste der Labels steht unter https://github.com/kubernetes/kubernetes/labels

Hier einige praktische vordefinierte Suchen nach Issues:

Geltungsbereich

Diese Richtlinien dienen als grundlegendes Dokument zur Sichtung und Einordnung neuer Issues in etcd. Alle sind eingeladen, bei der Verwaltung von Issues und PRs mitzuhelfen. Die hier beschriebenen Arbeiten und Verantwortlichkeiten richten sich jedoch an die Maintainer und aktiven Mitwirkenden von etcd.

Prüfen, ob ein Issue einen Fehler beschreibt

Prüfen, ob tatsächlich ein Fehler vorliegt. Falls nicht, die Erkenntnisse in einem Kommentar festhalten und triviale Issues schließen. Bei nicht trivialen Issues die Rückmeldung der meldenden Person abwarten, um mögliche Einwände zu berücksichtigen. Antwortet sie innerhalb von 30 Tagen nicht, das Issue schließen. Lässt sich das Problem nicht reproduzieren oder werden weitere Informationen benötigt, einen Kommentar für die meldende Person hinterlassen.

Inaktive Issues

Issues mit unzureichenden Angaben sollten geschlossen werden, wenn die meldende Person innerhalb von 60 Tagen keine Informationen nachliefert.

Doppelte Issues

Bei einem doppelten Issue einen entsprechenden Kommentar mit einem Verweis auf das ursprüngliche Issue hinterlassen und das Duplikat schließen.

Issues außerhalb von etcd

Manche gemeldeten Issues betreffen tatsächlich andere Projekte, die etcd verwendet, etwa grpc oder golang. In solchen Fällen sollte die meldende Person gebeten werden, ein Issue im zuständigen Projekt zu eröffnen. Das Issue schließen, sofern nicht ein Maintainer und die meldende Person es zur Nachverfolgung offen halten möchten.

Wichtige Labels prüfen

Sicherstellen, dass das Issue Labels für die betroffenen Bereiche hat, geeignete Verantwortliche zugewiesen sind und ein Meilenstein festgelegt ist. Fehlende Labels ergänzen. Lassen sich Labels wegen fehlender Berechtigungen nicht zuweisen oder lässt sich das richtige Label nicht bestimmen, ist das in Ordnung; bei Bedarf die Maintainer kontaktieren.

Bei Bedarf die verantwortliche Person erinnern

Wenn für ein von einem Entwickler übernommenes Issue innerhalb von 30 Tagen kein PR erstellt wurde, die verantwortliche Person kontaktieren und sie bei Bedarf bitten, einen PR zu erstellen oder die Zuständigkeit freizugeben.

18.2 - PR-Verwaltung

Richtlinien zur Verwaltung von etcd-Pull-Requests

Zweck

Die PR-Verwaltung beschleunigen.

Die PRs für etcd sind unter https://github.com/etcd-io/etcd/pulls aufgeführt. Ein PR kann verschiedene Labels, einen Meilenstein, Reviewer usw. haben. Die vollständige Liste der Labels steht unter https://github.com/kubernetes/kubernetes/labels

Hier einige praktische Suchbeispiele für PRs:

Geltungsbereich

Diese Richtlinien dienen als grundlegendes Dokument zur Verwaltung von PRs in etcd. Alle sind eingeladen, bei der PR-Verwaltung mitzuhelfen. Die hier beschriebenen Arbeiten und Verantwortlichkeiten richten sich jedoch an die Maintainer und aktiven Mitwirkenden von etcd.

Inaktive PRs bearbeiten

Die verantwortliche Person für den PR erinnern, wenn Review-Kommentare innerhalb von 15 Tagen nicht bearbeitet wurden. Antwortet sie innerhalb von 90 Tagen nicht, den PR nach Möglichkeit mit einem neuen Commit aktualisieren. Ist das nicht möglich, sollte der inaktive PR nach 180 Tagen geschlossen werden.

Bei Bedarf Reviewer erinnern

Reviewer reagieren zeitnah. Da alle viel zu tun haben, nach einer Review-Anfrage jedoch etwas Zeit lassen, falls keine schnelle Antwort kommt. Bleibt die Antwort 10 Tage lang aus, können sie durch einen Kommentar im PR, eine E-Mail oder eine Slack-Nachricht kontaktiert werden.

Wichtige Labels prüfen

Sicherstellen, dass dem PR geeignete Reviewer zugewiesen sind und ein Meilenstein festgelegt ist. Fehlende Zuweisungen oder andere wichtige Labels ergänzen. Lässt sich das richtige Label nicht bestimmen, einen Kommentar hinterlassen, damit die Maintainer es bei Bedarf festlegen können.