Beim Aufräumen meiner Tabs bin ich über eine Meldung aus dem November des letzten Jahres gestolpert: DNS Service Discovery ist jetzt auch in der Open Source Variante von Nginx verfügbar (bis dahin nur in NginxPlus).
Natürlich konnte man auch früher schon FQDNs (statt IP-Adressen) in der Nginx-Konfiguration verwenden - aber der dazu erforderliche DNS-Lookup fand genau einmal beim Start von Nginx statt - danach nicht mehr.
Mit DNS service discovery, löst Nginx bei jedem Request den FQDN auf und ermittelt so die aktiven IP-Adressen der Backends, an die die Requests weitergeleitet werden sollen.
Zusätzlich können auch DNS SRV Records ausgewertet werden, um so z. B. Priorität, Gewicht und Port des Backends zuzuweisen:
root@nginx-revp:~# dig +short nginx-revp1.service.consul srv
1 1 80 c0a800f6.addr.prod1patroni.consul.
Es ist also "nur noch" eine dynamische DNS Komponente erforderlich, um den Loadbalancer/Reverse-Proxy dynamisch mit Informationen über verfügbare Backends zu versorgen.
Eine solche DNS Komponente wäre z. B. ein Consul-Cluster, bei welchem sich Nginx-Backends automatisch registrieren. Eine andere Variante wäre z. B. Triton-CNS.
Für Consul reicht es, auf dem jeweiligen Backend einen Consul-Client zu konfigurieren, der z. B. durch Ansible oder Terraform beim erzeugen der Backend-Instanz mit der jeweiligen IP-Adresse des Backends versehen werden könnte:
service {
id="nginx-revp1"
name="nginx-revp1"
tags=["nginx"]
meta=[
{ configured="by terraform" }
]
address="192.168.0.246"
port=80
checks = {
id = "nginx-revp1"
name = "nginx-revp1"
http = "http://127.0.0.1/"
interval = "15s"
}
}
Im Consul Catalog wird der Dienst dann gelistet:
root@nginx-revp:~# consul catalog services -tags
consul
nginx-revp1 nginx
patroni42 master,primary,replica
Durch diese Registrierung und den zugehörigen Health-Check, wird Consul alle 15 Sekunden die Verfügbarkeit des Dienstes prüfen und ihn bei einem Fehler sofort aus dem Consul DNS austragen:
root@nginx-revp:~# dig +short nginx-revp1.service.consul
192.168.0.246
root@nginx-revp:~# dig +short nginx.nginx-revp1.service.consul
192.168.0.246
root@nginx-revp:~# dig +short nginx.nginx-revp1.service.prod1patroni.consul
192.168.0.246
Ich empfehle dafür lokal statt systemd-resolved ein dnsmasq zu konfigurieren. In der Consul-Dokumentation gibt es dafür einen Abschnitt. Der Vorteil von dnsmasq gegenüber systemd-resolved ist, dass damit nur DNS-Anfragen, die für die consul-Domain bestimmt sind, an den Consul-Cluster weitergeleitet werden.
# Enable forward lookup of the 'consul' domain:
server=/consul/127.0.0.1#8600
# User Google DNS for all other domains:
server=8.8.8.8
Auf diese Weise wird die Instanz nicht unbedienbar, wenn z. B. die Consul-Konfiguration angepasst und Consul neugestartet wird.
Das schöne an Nginx DNS Service Discovery ist, dass damit auch mehrere Reverse-Proxies nebeneinander (z. B. aus Gründen der Ausfallsicherheit) laufen können, ohne dass deren Konfiguration ständig synchronisiert werden müsste - sie aktualisiert sich ja dann selbstständig per DNS.
Bei meinen Tests war die Funktion in der aktuellen Stable-Version von Nginx (1.26.x) noch nicht eingebaut. Ich mußte den "Mainline"-Kernel (1.27.3) verwenden, um die Konfiguration durchführen zu können.