Hallo!
Mein Name ist Sergej, ich arbeite als Infrastrukturingenieur im API-Team der Plattform tinkoff.ru.
In diesem Artikel werde ich über die Probleme sprechen, mit denen unser Team bei der Vorbereitung von Lastenausgleichsmechanismen auf Basis für verschiedene Projekte konfrontiert war. Außerdem werde ich von einem Werkzeug berichten, das es uns ermöglicht hat, den Großteil davon zu überwinden.
Nginx ist ein leistungsfähiger und sich aktiv weiterentwickelnder Proxy-Server. Er zeichnet sich durch eine große Anzahl von Modulen aus, . Jedes Projekt stellt bestimmte Anforderungen an die Funktionalität des Lastenausgleichs und die Version von Nginx (z. B. die Verfügbarkeit von http/2 und das Proxien von grpc) sowie an die Zusammensetzung seiner Module.
Wir möchten die neueste Version mit dem erforderlichen Satz an Modulen sehen, die unter einer bestimmten Linux-Distribution funktioniert. In unserem Fall handelt es sich um deb- und rpm-basierte Systeme. Die Option mit Containern wird in diesem Artikel nicht betrachtet.
Wir möchten die Funktionalität unserer Lastenausgleichsmechanismen schnell anpassen. Und hier stellt sich sofort die Frage – wie können wir das erreichen, ohne zu viele Ressourcen zu verschwenden? Noch besser wäre es, einen Prozess einzurichten, bei dem wir eine endliche Anzahl von Eingabeparametern angeben und als Ergebnis ein Artefakt in Form eines deb/rpm-Pakets für das benötigte Betriebssystem erhalten.
Insgesamt lässt sich eine Reihe von Problemen formulieren:
- Es gibt nicht immer Pakete mit der neuesten Version von Nginx.
- Es fehlen Pakete mit den erforderlichen Modulen.
- Die manuelle Kompilierung und Erstellung eines Pakets nimmt viel Zeit in Anspruch und ist einfach nur ermüdend.
- Es gibt keine Beschreibung, wie der jeweilige Nginx-Instanz erstellt wurde.
Um diese Probleme zu lösen, drängt sich ein Werkzeug auf, das eine Spezifikation im menschenlesbaren Format entgegennimmt und damit ein Nginx-Paket mit den gewünschten Funktionen erstellt.
Nachdem wir auf GitHub keine passende Lösung gefunden hatten, entschieden wir uns, unser eigenes Werkzeug zu erstellen – .
Spezifikationen
In unserem Werkzeug wollten wir die Beschreibung der Spezifikation in Form von Code erstellen, den man dann in ein Git-Repository ablegen kann. Dafür wählten wir das für solche Dinge gewohnte Format – yaml. Ein Beispiel für die 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 ein deb-Paket mit der Version Nginx 1.14.2 und dem gewünschten Modulsatz sehen möchten. Der Abschnitt mit Modulen ist optional. Für jedes Modul können wir folgende Angaben machen:
- Name.
- Adresse, wo es erhältlich ist:
- Git-Repository. Es kann auch ein Branch oder ein Tag angegeben werden.
- Web-Link auf das Archiv.
- Lokaler Link auf das Archiv.
Einige Module erfordern die Installation zusätzlicher Abhängigkeiten, beispielsweise benötigt nginx-auth-ldap die installierte libldap2-dev. Notwendige Abhängigkeiten können ebenfalls bei der Modulbeschreibung angegeben werden.
Umgebung
In unserem Tool können wir schnell eine Umgebung mit installierten Tools für die Kompilierung, den Paketbau und andere Hilfssoftware erhalten. Hierfür eignet sich ein Docker-Container mit allem Notwendigen (im Repository gibt es bereits einige Beispiele für Docker-Dateien für Ubuntu und CentOS).
Nachdem die Spezifikation erstellt und die Umgebung vorbereitet wurde, starten wir unseren Builder, nachdem wir dessen Abhängigkeiten installiert haben:
pip3 install -r requirements.txt
./main.py build -f [config_file].yaml -r [revision_number]
Die Revisionsnummer ist hier optional und dient der Versionierung der Builds. Sie wird in die Metainformationen des Pakets geschrieben, was es ermöglicht, es auf Servern einfach zu aktualisieren.
Anhand der Protokolle kann man die Vorgänge beobachten. Hier ein Beispiel für die wichtigsten Punkte:
builder - INFO - yaml-Datei analysieren: example.config.yaml
builder - INFO - Skripte für den Build des deb-Pakets herunterladen
builder - INFO - Lade nginx-Quellcode herunter...
builder - INFO - --> http://nginx.org/download/nginx-1.14.1.tar.gz
builder - INFO - Lade 3d-Party-Module herunter...
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 - Lade Abhängigkeiten herunter
builder - INFO - Erstelle .deb-Paket
builder - INFO - Führe 'dh_make' aus...
builder - INFO - Führe 'dpkg-buildpackage' aus...
dpkg-deb: Baue Paket 'nginx' in '../nginx_1.14.1-1_amd64.deb'.
So erstellen wir mit nur wenigen Befehlen die Umgebung und den benötigten Nginx-Build, und das Paket erscheint im Verzeichnis, von dem das Skript gestartet wurde.
Integration
Wir können unser Tool auch in CI/CD-Prozesse integrieren. Dabei kann uns jedes der heute existierenden CI-Systeme helfen, zum Beispiel oder .
Somit wird bei jeder Änderung der Spezifikation im Git-Repository automatisch der Build des Artefakts gestartet. Die Revisionnummer wird an den Zähler der Build-Ausführungen gebunden.
Wenn wir noch etwas Zeit investieren, können wir die Übertragung des Artefakts in lokale Paket-Repositories, Nexus, Artifactory usw. einrichten.
Ein zusätzlicher Vorteil besteht darin, dass die Konfigurations-yaml-Datei in Ansible oder ein anderes System zur automatischen Konfiguration eingebunden werden kann, sodass wir die Versionsnummer und den Typ des Pakets, das wir bereitstellen möchten, dort entnehmen können.
Was kommt als nächstes
Das Projekt ist noch nicht abgeschlossen. An diesen Punkten arbeiten wir derzeit:
- Wir erweitern die Konfigurationsmöglichkeiten, wobei wir sie gleichzeitig so einfach wie möglich halten. Wir möchten keine tausend Parameter definieren, wenn nur zwei notwendig sind und der Rest die Standardwerte verwendet. Dazu gehören die Compiler-Flags (derzeit können sie in der internen Konfigurationsdatei src/config.py geändert werden), Installationspfade, Benutzer für die Ausführung.
- Wir fügen Optionen zum automatischen Hochladen des Pakets in verschiedene Artefakt-Storage-Lösungen hinzu.
- Ausführung benutzerdefinierter Befehle beim Laden des Moduls (zum Beispiel zur Verwendung muss zunächst ein Patch einer bestimmten Version angewendet werden)
- Wir fügen die Durchführung von Tests hinzu:
- Das Paket wird korrekt installiert.
- Nginx hat die benötigte Version und wurde mit den erforderlichen Flags und Modulen erstellt.
- Die notwendigen Pfade, Benutzerkonten usw. werden erstellt.
Sie können dieses Tool jedoch bereits jetzt nutzen und Vorschläge zur Verbesserung machen — Willkommen!
Quelle: habr.com
