Zum Inhalt springen

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.