Hallo!
Mein Name ist Sergej und ich arbeite als Infrastruktur-Ingenieur im API-Team von tinkoff.ru.
In diesem Artikel berichte ich über die Herausforderungen, mit denen unser Team bei der Vorbereitung von Load-Balancern auf Basis von für verschiedene Projekte konfrontiert war. Außerdem stelle ich ein Werkzeug vor, das uns geholfen hat, einen Großteil davon zu überwinden.
Nginx ist ein vielseitiger und aktiv entwickelter Proxy-Server. Er zeichnet sich durch eine große Anzahl von Modulen aus, . Jedes Projekt hat spezifische Anforderungen an die Funktionalität des Load-Balancers und die Nginx-Version (zum Beispiel die Verfügbarkeit von http/2 und die Unterstützung von gRPC-Proxying) sowie an die Module.
Wir möchten die neueste Version mit dem erforderlichen Modulset, die auf einer bestimmten Linux-Distribution läuft. In unserem Fall handelt es sich um deb- und rpm-basierte Systeme. Ein Containeransatz wird in diesem Artikel nicht behandelt.
Wir möchten die Funktionen unserer Load Balancer schnell anpassen. Dabei stellt sich sofort die Frage, wie wir das mit möglichst minimalem Ressourceneinsatz erreichen können. Noch besser wäre es, einen Prozess zu etablieren, der es uns ermöglicht, eine feste Anzahl von Eingabeparametern zu definieren und als Ergebnis ein Artefakt in Form eines deb/rpm-Pakets für das gewünschte Betriebssystem zu erhalten.
Folglich lassen sich eine Reihe von Problemen formulieren:
- Es sind nicht immer Pakete mit der neuesten Version von Nginx verfügbar.
- Es fehlen Pakete mit den erforderlichen Modulen.
- Die manuelle Kompilierung und Erstellung eines Pakets dauert viel Zeit und ist einfach ermüdend.
- Es gibt keine Dokumentation dazu, wie eine bestimmte Nginx-Instanz zusammengestellt wird.
Um diese Probleme zu lösen, benötigt man ein Werkzeug, das eine Spezifikation in einem menschenlesbaren Format als Eingabe akzeptiert und ein Nginx-Paket mit den erforderlichen Funktionen daraus erstellt.
Da wir auf GitHub keine geeignete Lösung für uns finden konnten, haben wir uns entschieden, unser eigenes Werkzeug zu entwickeln — .
Spezifikationen
In unserem Werkzeug wollten wir eine Spezifikation in Form von Code erstellen, die anschließend in ein Git-Repository gelegt werden kann. Wir haben dafür das gängige Format yaml gewählt. Beispiel für eine Spezifikation:
nginx_version: 1.14.1
output_package: deb
modules:
- module:
name: nginx-auth-ldap
git_url: https://github.com/kvspb/nginx-auth-ldap.git
git_branch: master
dependencies:
- libldap2-dev
- module:
name: ngx_http_substitutions_filter_module
git_url: https://github.com/yaoweibin/ngx_http_substitutions_filter_module.git
- module:
name: headers-more-nginx-module
web_url: https://github.com/openresty/headers-more-nginx-module/archive/v0.261.zip
- module:
name: nginx-module-vts
git_url: https://github.com/vozlt/nginx-module-vts.git
git_tag: v0.1.18
- module:
name: ngx_devel_kit
git_url: https://github.com/simplresty/ngx_devel_kit.git
git_tag: v0.3.0
- module:
name: ngx_cache_purge
git_url: https://github.com/FRiCKLE/ngx_cache_purge.git
- module:
name: ngx_http_dyups_module
git_url: https://github.com/yzprofile/ngx_http_dyups_module.git
- module:
name: nginx-brotli
git_url: https://github.com/eustas/ngx_brotli.git
git_tag: v0.1.2
- module:
name: nginx_upstream_check_module
git_url: https://github.com/yaoweibin/nginx_upstream_check_module.git
- module:
name: njs
git_url: https://github.com/nginx/njs.git
git_tag: 0.2.5
config_folder_path: nginx
Hier geben wir an, dass wir das deb-Paket mit der Nginx-Version 1.14.2 und dem gewünschten Modul-Set sehen möchten. Der Abschnitt mit den Modulen ist optional. Für jedes Modul können folgende Angaben gemacht werden:
- Name.
- Die Adresse, wo es verfügbar ist:
- Git-Repository. Es kann auch ein Branch oder Tag angegeben werden.
- Weblink zu einem Archiv.
- Lokaler Link zu einem Archiv.
Einige Module erfordern die Installation zusätzlicher Abhängigkeiten, wie zum Beispiel benötigt nginx-auth-ldap das installierte libldap2-dev. Notwendige Abhängigkeiten können auch in der Moduldokumentation angegeben werden.
Umgebung
Mit unserem Tool können Sie schnell eine Umgebung mit installierten Utilities für die Kompilierung, Paketgestaltung und weitere unterstützende Software erhalten. Hierfür eignet sich am besten ein Docker-Container mit allem Notwendigen (im Repository gibt es bereits ein paar Beispiele für Docker-Dateien für Ubuntu und CentOS).
Nachdem die Spezifikation erstellt und die Umgebung vorbereitet ist, starten wir unseren Builder, nachdem wir seine Abhängigkeiten installiert haben:
pip3 install -r requirements.txt
./main.py build -f [конфиг_файл].yaml -r [номер_ревизии]
Die Versionsnummer ist hier optional und dient der Versionierung der Builds. Sie wird in die Metainformationen des Pakets eingetragen, was eine einfache Aktualisierung auf den Servern ermöglicht.
Anhand der Logs kann man das Geschehen verfolgen. Hier ein Beispiel für die wichtigsten Punkte:
builder - INFO - YAML-Datei analysieren: example.config.yaml
builder - INFO - Skripte zum Erstellen des Deb-Pakets herunterladen
builder - INFO - Herunterladen von nginx-src...
builder - INFO - --> http://nginx.org/download/nginx-1.14.1.tar.gz
builder - INFO - Herunterladen von 3rd-Party-Modulen...
builder - INFO - Modul nginx-auth-ldap wird nach Branch heruntergeladen
builder - INFO - -- Fertig: nginx-auth-ldap
builder - INFO - -- Fertig: ngx_http_substitutions_filter_module
builder - INFO - Modul headers-more-nginx-module wird heruntergeladen
builder - INFO - Modul nginx-module-vts wird nach Tag heruntergeladen
builder - INFO - -- Fertig: nginx-module-vts
builder - INFO - Modul ngx_devel_kit wird nach Tag heruntergeladen
builder - INFO - -- Fertig: ngx_devel_kit
builder - INFO - -- Fertig: ngx_cache_purge
builder - INFO - -- Fertig: ngx_http_dyups_module
builder - INFO - Abhängigkeiten herunterladen
builder - INFO - .deb-Paket erstellen
builder - INFO - 'dh_make' ausführen...
builder - INFO - 'dpkg-buildpackage' ausführen...
dpkg-deb: Paket 'nginx' wird in '../nginx_1.14.1-1_amd64.deb' erstellt.
So erstellen wir mit nur ein paar Befehlen die Umgebung und die benötigte Nginx-Build, und das Paket erscheint im Verzeichnis, von dem das Skript gestartet wurde.
Integration
Darüber hinaus können wir unser Tool in CI/CD-Prozesse einbinden. Dabei kann jede der vielen bestehenden CI-Systeme hilfreich sein, zum Beispiel oder .
Das bedeutet, dass bei jeder Änderung der Spezifikation im Git-Repository automatisch der Build des Artefakts gestartet wird. Die Revisionsnummer wird an die Anzahl der Build-Starts gebunden.
Mit etwas zusätzlicher Zeit kann die Übermittlung des Artefakts an ein lokales Paket-Repository, Nexus, Artifactory usw. eingerichtet werden.
Ein zusätzlicher Vorteil ist, dass die Konfigurations-YAML-Datei in Ansible oder ein anderes Automatisierungssystem integriert werden kann, um die Versionsnummer und den Pakettyp abzurufen, die wir bereitstellen möchten.
Was kommt als Nächstes
Das Projekt ist noch nicht abgeschlossen. Hier arbeiten wir momentan dran:
- Wir erweitern die Konfigurationsmöglichkeiten, halten sie dabei jedoch so einfach wie möglich. Es ist nicht sinnvoll, tausend Parameter zu definieren, wenn nur zwei benötigt werden und die anderen Standardwerte haben. Dazu gehören die Compiler-Flags (aktuell können diese in der internen Konfigurationsdatei src/config.py geändert werden), Installationspfade und der Benutzer zum Ausführen.
- Wir fügen Optionen für eine automatische Übermittlung des Pakets an verschiedene Artefakt-Speicher hinzu.
- Ausführen eines benutzerdefinierten Befehls beim Laden des Moduls (zum Beispiel zur Verwendung muß zuerst ein Patch für eine bestimmte Version angewendet werden)
- Wir fügen das Testen hinzu:
- Das Paket wird korrekt installiert.
- Nginx hat die erforderliche Version und ist mit den benötigten Flags und Modulen kompiliert.
- Die notwendigen Pfade, Konten usw. werden erstellt.
Sie können dieses Tool jedoch bereits jetzt nutzen und auch Verbesserungen vorschlagen — Willkommen!
Quelle: habr.com
