Transferify
Zurück zum Blog

Schreib den Teil deiner Envoy-Konfiguration, der dir gehört, und generiere den Rest

Die Dienste von Transferify stehen hinter einem einzigen Gateway, einem Envoy-Proxy. Es prüft Anfragen mit unserem Auth-Dienst, lässt Browser nach Origin zu und leitet Pfade und RPC-Methoden an die Dienste dahinter weiter. Seine Konfiguration war früher eine lange Envoy-Datei. Heute bearbeiten Menschen eine kurze Datei, und ein Programm schreibt daraus die Datei für Envoy.

Das Programm heißt proxyfile. Wir haben es bei Transferify für unser eigenes Gateway gebaut. Es ist Open Source unter Apache-2.0, in Go geschrieben und liegt unter github.com/kitecorp/proxyfile. Dieser Beitrag erklärt, warum wir es geschrieben haben, was du schreibst und was es für dich schreibt, und wie wir unser eigenes Gateway darauf umgestellt haben, ohne zu ändern, was Envoy tut. Zu einem Teil, den es schreibt, der Brücke von Connect zu gRPC, siehe Wie Envoy die Connect-Aufrufe des Browsers in gRPC umwandelt.

Warum die Envoy-Datei eines Gateways immer weiter wächst

Die Konfiguration von Envoy ist absichtlich explizit. Jeder Listener, jeder Cluster, jede Route, jeder Filter und jede Header-Regel wird vollständig ausgeschrieben. Das passt zu Envoy, das sie liest. Für die Menschen, die sie ändern, ist es mühsam, denn ein echtes Gateway wiederholt sich: jede Route in jeder Umgebung, jeder Cluster, jede Header-Regel.

Unsere war auf 552.000 Bytes in 799 Zeilen gewachsen. Sie bediente drei Umgebungen, und der virtuelle Host jeder Umgebung enthielt dieselben 205 RPC-Routen. Eine Kopie war YAML. Die anderen beiden waren je eine einzige Zeile JSON, etwa 167.000 und 169.000 Zeichen lang. Ein Renderer schrieb diese Teile zwischen Markierungskommentare, mitten in dieselbe Datei, die Menschen von Hand bearbeiteten.

Die Fakten, die uns gehörten, waren wenige: die Dienste und ihre Ports, die Timeouts, die Auth-Prüfung, die Browser-Origins pro Umgebung, die Routen nach Pfad oder RPC-Methode, Log-Sampling und Tracing. Sie waren zwischen den Typnamen von Envoy verstreut, und wer einen davon ändern wollte, musste ihn erst finden. Niemand konnte die Datei lesen oder reviewen.

Wir wollten nur schreiben, was uns gehört, mit dem Grund neben jedem Wert, und den Rest ein Werkzeug schreiben lassen, jedes Mal gleich.

Vorher: eine einzige envoy.yaml mit 552.000 Bytes in 799 Zeilen, teils von Hand und teils von einem Renderer geschrieben, mit zwei Zeilen von etwa 167.000 und 169.000 Zeichen. Nachher: ein Proxyfile mit 169 Zeilen und eine Methodendatei, die der Build schreibt, aus denen proxyfile eine envoy.yaml rendert, die niemand bearbeitet.Vorher: eine einzige envoy.yaml mit 552.000 Bytes in 799 Zeilen, teils von Hand und teils von einem Renderer geschrieben, mit zwei Zeilen von etwa 167.000 und 169.000 Zeichen. Nachher: ein Proxyfile mit 169 Zeilen und eine Methodendatei, die der Build schreibt, aus denen proxyfile eine envoy.yaml rendert, die niemand bearbeitet.
Vor und nach unserer Umstellung. Menschen bearbeiten nur die kurze Datei. Die lange wird generiert, und der Build weist eine Änderung von Hand zurück.

Das kleinste Proxyfile

Ein Proxyfile beschreibt ein Gateway. Nur vier Schlüssel sind Pflicht: listen, services, origins und routes. Das hier ist das kleinste, aus den Beispielen des Repositorys:

# yaml-language-server: $schema=https://raw.githubusercontent.com/kitecorp/proxyfile/v1.2.0/schema/proxyfile.schema.json
# The smallest proxyfile: one service, one route, and the browser origins it admits.
listen: 8000
services:
  app: {http: 3000}
origins:
  all: {hosts: [localhost], origins: ["http://localhost:3000"]}
routes:
  - {name: app, prefix: /, to: app}

Dasselbe Gateway in HOCON:

# The smallest proxyfile, in HOCON: one service, one route, and the browser origins it admits.
listen = 8000
services {
  app { http = 3000 }
}
origins {
  all { hosts = [localhost], origins = ["http://localhost:3000"] }
}
routes = [
  { name = app, prefix = /, to = app }
]

Es liest sich, wie es klingt: ein öffentlicher Listener auf Port 8000, ein Dienst mit einem HTTP-Port, eine Umgebung, die für localhost antwortet und den Browser-Origin http://localhost:3000 zulässt, und eine Route, die jeden Pfad an den Dienst schickt. Beide Dateien ergeben dieselbe envoy.yaml, Byte für Byte: 119 Zeilen und 5.592 Bytes. Alles darin, was das Proxyfile nicht sagt, ist ein Standardwert, in jedem Gateway, das proxyfile schreibt, derselbe.

render und check

render schreibt die Envoy-Datei. check rendert im Speicher und vergleicht das Ergebnis mit der Datei auf der Platte. Es schreibt nichts.

proxyfile render gateway.yaml -o envoy.yaml
proxyfile check gateway.yaml -o envoy.yaml

Beide geben nichts aus und enden mit 0. Nach einer Änderung von Hand an envoy.yaml oder einer Änderung an gateway.yaml ohne neues Rendern endet check mit 1 und meldet:

envoy.yaml differs from what proxyfile render writes

Dieselbe Eingabe ergibt immer dieselben Bytes, und deshalb funktioniert dieses Paar. Du committest die generierte Datei neben ihrer Quelle, reviewst beide in einem Pull Request und lässt check in deinem Build scheitern, wenn jemand die Ausgabe von Hand ändert oder das Rendern vergisst. Die generierte Datei sagt das in ihrer ersten Zeile:

# Generated by proxyfile. Do not edit: change the proxyfile beside it and run proxyfile render; proxyfile check fails on a hand edit.

render schreibt seine Ausgaben nur, wenn die ganze Eingabe frei von Problemen ist, sodass ein Fehler nie eine halb geschriebene Datei hinterlässt. Exit-Code 2 bedeutet einen Bedienungsfehler. Ohne Dateinamen liest proxyfile Proxyfile, proxyfile.conf, proxyfile.yaml oder proxyfile.yml aus dem Arbeitsverzeichnis, und genau eine davon muss existieren.

Wie ein Fehler aussieht

Jeder Schlüssel wird geprüft. Vertippst du dich bei listen in der kleinsten Datei, weigert sich render, schreibt nichts und nennt Datei, Zeile und Spalte:

gateway.yaml:3:1: "listen" is required here
gateway.yaml:3:1: unknown key "liste"; known here: admin, auth, cors, limits, listen, log, namespace, origins, remove_from_clients, routes, rpc, services, timeouts, tracing

Ein unbekannter Schlüssel ist überall ein Problem, und die Meldung listet die Schlüssel auf, die an dieser Stelle bekannt sind. Eine Route zu einem Dienst, der nicht deklariert ist, ergibt:

gateway.yaml:9:32: route "app": the service "shop" is not declared

Die Prüfungen laufen in Stufen: Lesen und Syntax, dann das Format jedes Schlüssels, dann die Regeln, die Schlüssel miteinander vergleichen. Ein Lauf meldet jedes Problem der ersten Stufe, die überhaupt eines findet, sodass du einen ganzen Schwung auf einmal behebst, nicht eines pro Lauf.

In HOCON hat auch ein Syntaxfehler eine Zeile und eine Spalte. Andere Probleme nennen stattdessen den Schlüsselpfad, weil der HOCON-Leser für einen Wert keine Zeile behält. Schreibst du den Port als http = "3000", kommt:

gateway.conf: services.app.http: "http" must be a whole number from 1 to 65535, not quoted or block text

In HOCON ist ein Wert in Anführungszeichen Text, und ein Port muss eine Zahl sein.

Standardwerte, einmal entschieden

Wofür das Format keinen Schlüssel hat, ist in jedem Gateway, das proxyfile schreibt, gleich. Das Envoy-Setup steckt in YAML-Fragmenten im Programm, und jedes Fragment trägt Kommentare, die sagen, warum es so geschrieben ist. Ein paar Standardwerte, die uns wichtig sind:

  • Kein Pfad in irgendeiner Logzeile. Das Gateway schreibt drei Arten von JSON-Logzeilen auf die Standardausgabe, und keine enthält einen Pfad, einen Query-String, eine Adresse, einen User-Agent oder einen Referrer, weil Pfade Links und Tokens tragen können. Mit log wird jede Antwort ab status_from geloggt, ebenso jede Antwort mit einem Envoy-Response-Flag und ein Anteil der übrigen, ausgewählt nach den ersten acht Hexziffern von x-request-id.
  • Wiederholungen nur, wenn die Anfrage den Dienst nie erreicht hat. Die retries einer Route gelten nur für die Bedingungen connect-failure und reset-before-request von Envoy, sodass eine Anfrage, die der Dienst gesehen hat, nie zweimal gesendet wird.
  • Eine leere 502, wenn ein Dienst nicht erreichbar ist. Die eigene Antwort von Envoy ist eine 503 oder eine 502 mit einem Body, der den Fehler beschreibt. Mit proxyfile bekommt der Client eine 502 mit leerem Body, und die Details landen in der Logzeile gateway_upstream_failure.
  • x-request-id an jeder Antwort, die des Clients, wenn er eine geschickt hat, sodass ein Aufrufer die ID eines fehlgeschlagenen Aufrufs nennen kann. Sie ist die request_id des Anfrage-Logs.
  • Kein Umschreiben von Pfaden. Envoy normalisiert keinen Pfad und fasst keine Schrägstriche zusammen, sodass die eigenen Pfadregeln des Dienstes entscheiden, was ein Pfad bedeutet.
  • Fremde Origins enden am Gateway. Ein Browser-Origin, der nicht zugelassen ist, bekommt 403, bevor CORS, die Auth-Prüfung oder irgendein Dienst ihn sieht: Preflights, Anfragen und WebSocket-Upgrades gleichermaßen. Für einen zugelassenen Origin beantwortet das Gateway jeden Preflight selbst.
  • Die Statuskorrektur der Connect-Brücke. Jede RPC-Route wandelt einen Connect-Aufruf in gRPC um. Die Brücke von Envoy schreibt für vier Codes noch den HTTP-Status einer älteren Tabelle der Connect-Fehlercodes, also setzt ein kleiner Lua-Filter den aktuellen: canceled 499, deadline_exceeded 504, failed_precondition 400 und unimplemented 501. Der Beitrag über die Brücke erklärt, warum das für Logs und Alarme zählt.

Es gibt keinen Weg, rohe Envoy-Konfiguration durch ein Proxyfile zu reichen. Braucht ein Gateway für einen dieser Standardwerte einen anderen Wert, braucht es dafür einen neuen Schlüssel.

Die Auth-Prüfung

Mit auth fragt das Gateway einen deiner Dienste zu jeder Anfrage, bevor die Anfrage einen Dienst erreicht. Es fragt im HTTP-Modus, also ist der Auth-Dienst ein gewöhnlicher HTTP-Endpunkt und braucht keinen Envoy-spezifischen Typ. Hier ist ein Gateway mit Prüfung, mit den erfundenen Namen des Repositorys:

# yaml-language-server: $schema=https://raw.githubusercontent.com/kitecorp/proxyfile/v1.2.0/schema/proxyfile.schema.json
listen: 8000
timeouts:
  upstream_idle: 45s                 # under the accounts service's own idle timeout, so the gateway closes first
services:
  shop: {http: 8080}
  accounts: {http: 7070}
auth:
  ask: accounts /auth/check
  timeout: 1500ms
  enabled: true
  when_unavailable: allow            # if accounts cannot answer, let the request through and log it
  only_with_header: authorization    # a request without a token goes through unchecked
  send: [authorization]
  accept: [x-user-*]                 # the answer headers that reach the service
origins:
  live:
    hosts: [api.example.com]
    origins: ["https://example.com"]
routes:
  - {name: accounts-webhooks, path: /api/webhooks, method: POST, to: accounts, rewrite: /hooks/payments, auth: off}
  - {name: shop, prefix: /, to: shop, retries: 1}
log: {status_from: 400, sample: 1%}

Der Kommentar neben upstream_idle ist die Art von Grund, die wir neben jedem Wert haben wollten. Eine Prüfung, die über eine Verbindung geht, die der Auth-Dienst gerade schließt, scheitert, also sollte das Gateway eine ruhende Verbindung schließen, bevor der Dienst es tut.

Was die Prüfung bekommt und was ihre Antwort bewirkt:

  • Sie bekommt eine Anfrage an den Pfad aus ask, nie den Pfad oder Query-String des Clients, weil Pfade Links und Tokens tragen können. Sie bekommt die Header, die send nennt, und der HTTP-Modus fügt den Host des Clients, die Methode, Authorization und Content-Length: 0 hinzu.
  • x-gateway-timeout-ms enthält die Frist, hier 1500, damit der Auth-Dienst seine eigenen Aufrufe darin halten kann.
  • Eine 200 lässt die Anfrage durch. Die Header der Antwort, die accept nennt, werden an der Anfrage an den Dienst gesetzt und ersetzen jeden Wert, der dort steht. Eine 5xx zählt als fehlgeschlagener Aufruf, über den when_unavailable entscheidet. Jeder andere Status geht als Ablehnung an den Client zurück.
  • Ein Client kann nicht fälschen, was die Prüfung sagt. Das Gateway entfernt jeden accept-Header und die Header, mit denen es die Prüfung fragt, aus Anfragen von Clients, vor dem Routing und vor jedem Filter.
  • Mit when_unavailable: allow geht eine Anfrage, die nicht geprüft werden konnte, mit gesetztem x-envoy-auth-failure-mode-allowed durch, und das Gateway schreibt dafür eine Logzeile gateway_auth_unavailable.
  • auth: off an einer Route, wie an der Webhook-Route oben, schickt ihre Anfragen ohne Prüfung weiter.

RPC-Routen aus einer Liste von Methoden

Für gRPC- und Connect-Dienste schreibst du nicht eine Route pro Methode. Du setzt einen rpc-Eintrag in routes und gibst die Liste der Methoden an. In HOCON kann die Liste in einer eigenen Datei stehen:

include required("rpc-methods.conf")   # written by the build; required: a missing file is an error
listen = 8000
services {
  web { http = 3000 }
  backend { grpc = 5000 }
}
origins {
  only { hosts = [gateway.example.net], origins = ["https://app.example.net"] }
}
routes = [
  { rpc { to { "*" = backend } } }
  { name = web, prefix = /, to = web }
]

Und rpc-methods.conf daneben:

rpc {
  methods = [
    { service = "example.backend.v1.ReportService", method = ListReports, action = read, reports = [export, share] }
  ]
}

proxyfile schreibt eine Route pro Methode, die auf den exakten Pfad eines Aufrufs passt, hier /example.backend.v1.ReportService/ListReports, mit eingeschalteter Connect-Brücke. Die RPC-Routen werden nach Pfad sortiert und dort geschrieben, wo der rpc-Eintrag steht, sodass eine einfache Route über dem Eintrag zuerst probiert wird und eine darunter danach. In to gewinnt ein exakter Dienstname, dann das längste passende Paketmuster, und * kommt zuletzt. Mit einer Auth-Prüfung sagt jede RPC-Route der Prüfung auch action und reports ihrer Methode, in x-gateway-action und x-gateway-reports.

Das Wort required zählt. Ein einfaches HOCON-include überspringt eine fehlende Datei. include required(...) weist sie mit Namen zurück:

rpc-methods.conf: cannot read include file: open rpc-methods.conf: no such file or directory

--rpc-table schreibt außerdem die aufgelösten Routen als JSON, ein Objekt pro Zeile mit Dienst, Methode, Action, Reports und Cluster, damit ein anderes Programm sie lesen kann. In unserem eigenen Repository schreibt ein Build-Schritt rpc-methods.conf aus unseren Protobuf-Verträgen, und das Proxyfile bindet sie ein.

YAML oder HOCON

Beide Formen haben dieselben Schlüssel, Bedeutungen und Regeln und ergeben dieselben Bytes. Nimm die, die dein Team bequemer bearbeitet.

YAML kommt mit einem JSON Schema, sodass ein Editor die Schlüssel beim Tippen vervollständigt und prüft. Setz die oben gezeigte Zeile yaml-language-server an den Anfang der Datei, für Editoren, die den YAML Language Server nutzen, etwa VS Code mit der YAML-Erweiterung. In einer JetBrains-IDE fügst du eine JSON-Schema-Zuordnung für dieselbe URL hinzu. proxyfile schema gibt das Schema aus, und jedes Release enthält es als proxyfile.schema.json. Das Schema beschreibt nur die YAML-Form.

HOCON gibt dir Includes und Substitutionen. Ein Include wird relativ zu der Datei gelesen, die es enthält. Eine Substitution wie accept = ${auth.send} kopiert einen Wert des Proxyfiles in einen anderen. Sie liest die Dateien, nie die Umgebung, sodass dieselben Dateien auf jeder Maschine dieselben Bytes ergeben. Drei Regeln, die du kennen solltest: routes ist ein Array, weil die erste passende Route gewinnt und HOCON von einem Objekt nicht verlangt, die Reihenfolge seiner Schlüssel zu behalten; ein Schlüssel mit . oder * steht in Anführungszeichen, wie in "*" = backend; und eine Zahl in Anführungszeichen ist Text.

Die Datei unseres eigenen Gateways ist HOCON.

Wie wir umgestellt haben, ohne zu ändern, was Envoy tut

Die von Hand geschriebene Quelle unseres Gateways ist jetzt ein Proxyfile mit 169 Zeilen HOCON. Davon sind 49 Kommentare, und 10 weitere tragen einen Kommentar neben ihrem Wert. Daneben liegt rpc-methods.conf mit unseren 205 Methoden, die der Build schreibt.

Die Umstellung durfte keine einzige Route und keinen einzigen Header ändern. Deshalb kam sie mit einem Beweis: einem Test, der das veröffentlichte proxyfile v1.2.0 auf das Proxyfile anwendet, die generierte Datei und die Datei, die sie ersetzt, zu Bäumen parst und verlangt, dass beide Bäume gleich sind, samt Reihenfolge der Listen. Er verlangt auch, dass die generierte RPC-Tabelle Byte für Byte die alte ist. Der Beweis ist vorübergehend. Die alte Datei blieb als Test-Fixture bis zum ersten Produktions-Deploy der neuen, und jetzt, da die Produktion die generierte Datei ausführt, entfernt eine Folgeänderung die Fixture und den Test.

Was bleibt, ist der Check im Build. Der Build lädt das festgelegte proxyfile-Release herunter, prüft es gegen die Prüfsummendatei dieses Releases, schreibt die Methodendatei und führt proxyfile render aus. Ein Schritt der check-Task des Builds führt proxyfile check aus, und er scheitert bei einer Änderung von Hand an envoy.yaml, bei einer Änderung am Proxyfile ohne Rendern und bei einer bearbeiteten Methodendatei. Der Image-Build führt dann envoy --mode validate auf der Datei aus, die er ausliefert.

Die generierte Datei ist immer noch groß: 522.056 Bytes in 1.112 Zeilen, weil Envoy weiterhin jede Route in jeder Umgebung braucht. Aber niemand bearbeitet sie. Jede RPC-Route ist jetzt eine Zeile pro Umgebung, und die längste Zeile hat 959 Zeichen, also zeigt ein Diff der generierten Datei die Routen, die sich geändert haben. Git-Attribute markieren sie als generiert, also klappt GitHub sie in einem Pull Request zu.

Der Weg von einem Proxyfile zu einem laufenden Envoy. Du bearbeitest das Proxyfile. proxyfile render schreibt envoy.yaml, und beide Dateien werden in Git committet. Im Build rendert proxyfile check erneut im Speicher und scheitert, wenn die committete envoy.yaml abweicht. In unserem Build wird dann das Image mit der committeten Datei gebaut, Envoy validiert sie, und das Gateway führt sie aus.Der Weg von einem Proxyfile zu einem laufenden Envoy. Du bearbeitest das Proxyfile. proxyfile render schreibt envoy.yaml, und beide Dateien werden in Git committet. Im Build rendert proxyfile check erneut im Speicher und scheitert, wenn die committete envoy.yaml abweicht. In unserem Build wird dann das Image mit der committeten Datei gebaut, Envoy validiert sie, und das Gateway führt sie aus.
proxyfile schreibt Dateien in Git, und der Build prüft sie. Die Datei auszuliefern ist Sache des Builds, nicht von proxyfile.

Envoy 1.40 lädt jedes Beispiel

proxyfile schreibt für Envoy 1.40. Der Pflicht-Check des Repositorys führt die Go-Tests aus. Sie vergleichen den Baum, der für jedes Beispiel geschrieben wird, mit einem von Hand geschriebenen, samt Reihenfolge der Listen, halten die committeten Ausgaben gleich dem, was render schreibt, und verlangen, dass YAML- und HOCON-Form jedes Beispiels dieselben Dateien ergeben. Dann führt der Check envoy --mode validate aus dem Image von Envoy 1.40.2 auf jedem generierten Beispiel aus. Die Tests beweisen, dass jede Datei die beabsichtigte ist. Nur Envoy beweist, dass sie lädt.

Die Beispiele decken das Format gemeinsam ab: examples/full schreibt jeden Schlüssel außer der address eines Dienstes und tracing, examples/partial nimmt bei jedem optionalen Schlüssel die andere Seite, und examples/tracing schreibt tracing.

Installation

Jedes Release hat eine Programmdatei für Linux und macOS auf amd64 und arm64, daneben checksums.txt und proxyfile.schema.json. Lade die für dein System herunter, prüfe sie und leg sie in ein Verzeichnis in deinem PATH:

curl -fsSLO https://github.com/kitecorp/proxyfile/releases/download/v1.2.0/proxyfile-linux-amd64
curl -fsSLO https://github.com/kitecorp/proxyfile/releases/download/v1.2.0/checksums.txt
shasum -a 256 -c --ignore-missing checksums.txt
install -m 0755 proxyfile-linux-amd64 /usr/local/bin/proxyfile

Auf einem Mac mit Apple Silicon heißt die Datei proxyfile-darwin-arm64. In einem Dockerfile kopierst du das Programm aus dem Image, das /proxyfile enthält und sonst nichts:

COPY --from=ghcr.io/kitecorp/proxyfile:1.2.0 /proxyfile /usr/local/bin/proxyfile

Mit installiertem Go:

go install github.com/kitecorp/proxyfile/cmd/proxyfile@v1.2.0

proxyfile version gibt dann proxyfile v1.2.0 aus.

Was proxyfile nicht tut

  • Es schreibt Konfiguration für Envoy und für keinen anderen Proxy.
  • Es schreibt Dateien. Es hat keinen Deploy-Schritt und ist keine Control Plane, also ändert sich in einem laufenden Envoy nichts, bis dein Build die neue Datei ausliefert.
  • Es nimmt keine rohe Envoy-Konfiguration an, wie oben beschrieben.
  • Es setzt voraus, dass ein Proxy oder ein Load Balancer vor dem Gateway steht. Ein Gateway, das direkt aus dem Internet erreichbar ist, braucht einen Schlüssel, den es noch nicht gibt.
  • Ein Dienst ist eine IP-Adresse, 127.0.0.1, solange du keine andere schreibst, kein Hostname, weil Envoy für einen statischen Cluster keinen Namen nachschlägt.

Das README im Repository enthält das ganze Format: jeden Schlüssel, jede Regel, jeden Standardwert und den Grund für jeden.

Häufige Fragen

Rollt proxyfile die Konfiguration aus oder lädt es Envoy neu?

Nein. Es schreibt Dateien. Du committest die generierte envoy.yaml neben dem Proxyfile, und dein Build liefert sie aus wie jede andere Datei. proxyfile hat keinen Deploy-Schritt und ist keine Control Plane.

Kann ich rohe Envoy-Konfiguration in ein Proxyfile schreiben?

Nein. Ein unbekannter Schlüssel ist überall ein Problem, und die Meldung listet die Schlüssel auf, die an dieser Stelle bekannt sind. Alles, wofür das Format keinen Schlüssel hat, ist ein Standardwert, in jedem Gateway, das proxyfile schreibt, derselbe, und ein anderer Wert braucht einen neuen Schlüssel.

Ergeben die YAML- und die HOCON-Form dieselbe Ausgabe?

Ja. Jeder Schlüssel hat in beiden denselben Namen, dieselbe Bedeutung und dieselben Regeln, und die generierte Datei ist Byte für Byte dieselbe. Der Dateiname entscheidet über die Form, nie der Inhalt. Eine Datei namens Proxyfile oder mit der Endung .conf ist HOCON, eine mit der Endung .yaml oder .yml ist YAML.

Hängt die Ausgabe von der Maschine ab, auf der proxyfile läuft?

Nein. Dieselbe Eingabe ergibt immer dieselben Bytes. HOCON-Substitutionen lesen nur das Proxyfile und seine Includes, nie eine Umgebungsvariable. Ein Tracing-Tag, das eine Umgebungsvariable nennt, liest Envoy beim Start, nicht proxyfile.

Für welche Envoy-Version schreibt proxyfile?

Envoy 1.40. Der Pflicht-Check des Repositorys führt envoy --mode validate aus dem Image von Envoy 1.40.2 auf jedem Beispiel aus, das es generiert.

Ähnliche Seiten

Nach oben