ansible devops codestyle
Hey! Ich heiĂe Ich arbeite als Ingenieur in der Abteilung fĂŒr die Automatisierung von Entwicklungsprozessen. Jeden Tag werden neue Anwendungsbuilds auf Hunderten von Servern des Unternehmens bereitgestellt. In diesem Artikel teile ich meine Erfahrungen mit Ansible fĂŒr diese Zwecke.
Dieser Leitfaden bietet einen Ansatz zur Organisation von Variablen im Deployment. Er richtet sich an diejenigen, die bereits Rollen in ihren Playbooks verwenden und , aber auf Ă€hnliche Probleme stoĂen:
- Beim Finden einer Variablen im Code ist es oft nicht sofort klar, wofĂŒr sie verantwortlich ist;
- Es gibt mehrere Rollen, und die Variablen mĂŒssen mit einem Wert verknĂŒpft werden, aber es funktioniert nicht;
- Es gibt Schwierigkeiten, anderen zu erklÀren, wie die Logik der Variablen in Ihren Playbooks aufgebaut ist.
Mit diesen Problemen sind wir in Projekten in unserem Unternehmen konfrontiert worden, was uns zu den Regeln fĂŒr die Gestaltung der Variablen in unseren Playbooks gefĂŒhrt hat, die diese Probleme teilweise gelöst haben.

Variablen in Rollen
Eine Rolle ist ein separates Objekt des Deployment-Systems. Wie jedes Objekt des Systems muss es eine Schnittstelle zur Interaktion mit dem Rest des Systems haben. Diese Schnittstelle sind die Variablen der Rolle.
Nehmen wir zum Beispiel die Rolle API, die eine Java-Anwendung auf dem Server installiert. Welche Variablen könnte sie haben?

Variablen einer Rolle können in 2 Typen unterteilt werden:
1. Eigenschaften
a) umgebungsunabhÀngig
b) umgebungsabhÀngig
2. Verbindungen
a) Listener
b) Anfragen innerhalb des Systems
c) Anfragen an die Umgebung
Eigenschaftsvariablen sind Variablen, die das Verhalten der Rolle bestimmen.
Anfragevariablen sind Variablen, deren Werte verwendet werden, um externe Ressourcen, die sich nicht innerhalb der Rolle befinden, zu kennzeichnen.
Listener-Variablen sind Variablen, deren Werte verwendet werden, um Anfragevariablen zu bilden.
Andererseits sind 1a, 2a, 2b - Variablen, die nicht von der Umgebung abhĂ€ngen (Hardware, externe Ressourcen usw.) und mit Standardwerten in den Defaults der Rolle gefĂŒllt werden können. Variablen vom Typ 1b und 2c hingegen können nicht mit Werten auĂer 'example' gefĂŒllt werden, da sie je nach Umgebung von Stand zu Stand variieren.
Code-Stil
- Der Name der Variable sollte unbedingt mit dem Namen der Rolle beginnen. Dies ermöglicht es, spĂ€ter leicht zu erkennen, aus welcher Rolle die Variable stammt und wofĂŒr sie verantwortlich ist.
- Bei der Verwendung von Variablen in Rollen mĂŒssen Sie unbedingt dem Prinzip der Kapselung folgen und Variablen verwenden, die entweder innerhalb der Rolle oder in den Rollen definiert sind, von denen die aktuelle abhĂ€ngt.
Versuchen Sie, keine WörterbĂŒcher fĂŒr Variablen zu verwenden. Ansible erlaubt es nicht, einzelne Werte in einem Wörterbuch bequem zu ĂŒberschreiben.
Beispiel fĂŒr eine schlechte Variable:
myrole_user: login: admin password: adminHier ist login eine umgebungsunabhÀngige Variable, und password ist abhÀngig. Aber
da sie in einem Wörterbuch zusammengefasst sind, mĂŒssen Sie sie immer vollstĂ€ndig angeben.
Was sehr unpraktisch ist. Besser so:myrole_user_login: admin myrole_user_password: admin
Variablen in Bereitstellungsplaybooks
Bei der Erstellung eines Bereitstellungsplaybooks (nachfolgend Playbook genannt) halten wir uns an die Regel, dass es in einem separaten Repository abgelegt werden muss. Genau wie bei Rollen: Jede in ihrem eigenen Git-Repository. Dies ermöglicht es zu erkennen, dass Rollen und Playbook unterschiedliche unabhĂ€ngige Objekte des Bereitstellungssystems sind und Ănderungen in einem Objekt die FunktionalitĂ€t des anderen nicht beeintrĂ€chtigen sollten. Dies wird durch die Ănderung der Standardwerte der Variablen erreicht.
Bei der Erstellung eines Playbooks gibt es, um es zusammenzufassen, die Möglichkeit, die Standardwerte der Rollenvariablen an zwei Stellen zu ĂŒberschreiben: in den Playbook-Variablen und in den Inventarvariablen.
mydeploy # Bereitstellungsverzeichnis
âââ deploy.yml # Bereitstellungs-Playbook
âââ group_vars # Verzeichnis fĂŒr Playbook-Variablen
â âââ all.yml # Datei fĂŒr die Variablen aller Systeme
â âââ myapi.yml # Datei fĂŒr die Variablen der Gruppe myapi
âââ inventories #
âââ prod # Verzeichnis der Umgebung prod
âââ prod.ini # Inventardatei
âââ group_vars # Verzeichnis fĂŒr die Inventarvariablen
âââ myapi #
âââ vars.yml # UmgebungsabhĂ€ngige Variablen der Gruppe myapi
âââ vault.yml # Geheimnisse (immer umgebungsabhĂ€ngig) ** â
Der Unterschied besteht darin, dass die Playbook-Variablen immer beim Aufruf der Playbooks verwendet werden, die sich auf derselben Ebene befinden. Das bedeutet, dass diese Variablen hervorragend geeignet sind, um die Standardwerte von umgebungsunabhĂ€ngigen Variablen zu Ă€ndern. Umgekehrt werden die Inventarvariablen nur fĂŒr die jeweilige Umgebung verwendet, was ideal fĂŒr umgebungsabhĂ€ngige Variablen ist.
Es ist wichtig zu beachten, dass die PrioritĂ€t der Variablen es Ihnen nicht ermöglicht, Variablen zuerst in den Playbook-Variablen und dann separat in einer Inventarliste zu ĂŒberschreiben.
Das bedeutet, dass Sie bereits in diesem Schritt entscheiden mĂŒssen, ob die Variable umgebungsabhĂ€ngig ist oder nicht, und sie am richtigen Ort platzieren mĂŒssen.
Zum Beispiel war in einem Projekt die Variable, die fĂŒr die Aktivierung von SSL verantwortlich war, lange umgebungsabhĂ€ngig, da wir aus uns nicht bekannten GrĂŒnden SSL auf einem der StĂ€nde nicht aktivieren konnten. Nachdem wir dieses Problem behoben hatten, wurde sie umgebungsunabhĂ€ngig und wurde in die Playbook-Variablen verschoben.
Eigenschaftsvariablen fĂŒr Gruppen
Erweitern wir unser Modell in Abbildung 1, indem wir 2 Gruppen von Servern mit einer anderen Java-Anwendung, jedoch mit unterschiedlichen Einstellungen hinzufĂŒgen.

Lassen Sie uns ansehen, wie das Playbook in diesem Fall aussehen wĂŒrde:
- hosts: myapi
roles:
- api
- hosts: bbauth
roles:
- auth
- hosts: ghauth
roles:
- authWir haben drei Gruppen im Playbook, daher wird empfohlen, ebenso viele Gruppendateien in group_vars der Inventarvariablen und den Playbook-Variablen zu erstellen. Eine Gruppendatei beschreibt in diesem Fall eine Komponente Ihrer Anwendung im Playbook. Wenn Sie die Gruppendatei in den Playbook-Variablen öffnen, sehen Sie sofort alle Abweichungen vom Standardverhalten der auf die Gruppe angewendeten Rollen. In den Inventarvariablen: Verhaltensunterschiede zwischen den StÀnden.
Code-Stil
- Versuchen Sie, host_vars-Variablen ĂŒberhaupt nicht zu verwenden, da sie das System nicht beschreiben, sondern nur einen Einzelfall, was langfristig zu Fragen fĂŒhren könnte: "Warum unterscheidet sich dieser Host von den anderen?", auf die nicht immer leicht zu antworten ist.
Beziehungsvariablen
Das betrifft die Eigenschaftenvariablen, aber wie steht es um die Beziehungsvariablen?
Ihr Unterschied besteht darin, dass sie in verschiedenen Gruppen den gleichen Wert haben mĂŒssen.
ZunÀchst war da eine monströse Konstruktion wie:
hostvars[groups['bbauth'][0]]['auth_bind_port'], aber diese wurde sofort verworfen
da sie Nachteile hat. Erstens, die Unhandlichkeit. Zweitens, die AbhÀngigkeit von einem bestimmten Host in der Gruppe. Drittens, es ist notwendig, vor dem Deployment Fakten von allen Hosts zu sammeln, wenn wir nicht mit einem Fehler bei einer undefinierten Variable konfrontiert werden wollen.
Letztendlich wurde beschlossen, Beziehungsvariablen zu verwenden.
Beziehungsvariablen â das sind Variablen, die zum Playbook gehören und fĂŒr die Verbindung von Systemobjekten benötigt werden.
Die Verbindungsvariablen werden in den allgemeinen Variablen des Systems ausgefĂŒllt group_vars/all/vars und entstehen durch das Herausnehmen aller Listener-Variablen aus jeder Gruppe und das HinzufĂŒgen des Gruppennamens, aus der der Listener entnommen wurde, zu Beginn der Variablen.
Auf diese Weise wird Eindeutigkeit und NichtĂŒberschneidbarkeit der Namen gewĂ€hrleistet.
Wir versuchen, die Variablen aus dem obigen Beispiel zu verknĂŒpfen:

Stellen wir uns vor, dass wir Variablen haben, die voneinander abhÀngen:
# roles/api/defaults:
# ĐĐ”ŃĐ”ĐŒĐ”ĐœĐœĐ°Ń Đ·Đ°ĐżŃĐŸŃа
api_auth1_address: "http://example.com:80"
api_auth2_address: "http://example2.com:80"
# roles/auth/defaults:
# ĐĐ”ŃĐ”ĐŒĐ”ĐœĐœĐ°Ń ŃĐ»ŃŃаŃДлŃ
auth_bind_port: "20000"Lassen Sie uns alle Listener in die allgemeinen Variablen ĂŒberfĂŒhren group_vars/all/vars und den Gruppennamen hinzufĂŒgen:
# group_vars/all/vars
bbauth_auth_bind_port: "20000"
ghauth_auth_bind_port: "30000"
# group_vars/bbauth/vars
auth_bind_port: "{{ bbauth_auth_bind_port }}"
# group_vars/ghauth/vars
auth_bind_port: "{{ ghauth_auth_bind_port }}"
# group_vars/myapi/vars
api_auth1_address: "http://{{ bbauth_auth_service_name }}:{{ bbauth_auth_bind_port }}"
api_auth2_address: "http://{{ ghauth_auth_service_name }}:{{ ghauth_auth_bind_port }}"Wenn wir also den Wert des Connectors Àndern, sind wir sicher, dass die Anfrage an den Ort geht, an dem sich der Port befindet.
Code-Stil
- Da Rollen und Gruppen unterschiedliche Objekte im System sind, mĂŒssen sie unterschiedliche Namen haben, damit die Verbindungsvariablen genau anzeigen, dass sie zu einer bestimmten Gruppe von Servern und nicht zu einer Rolle im System gehören.
UmgebungsabhÀngige Dateien
In Rollen können Dateien verwendet werden, die sich von Umgebung zu Umgebung unterscheiden.
Ein Beispiel fĂŒr solche Dateien sind SSL-Zertifikate. Es ist nicht sehr praktisch, sie im Textformat
als Variable zu speichern. Es ist jedoch praktisch, den Pfad zu ihnen innerhalb der Variablen zu speichern.
Zum Beispiel verwenden wir die Variable api_ssl_key_file: "/path/to/file".
Da offensichtlich ist, dass sich das Zertifikat je nach Umgebung Àndert, ist dies eine umgebungsabhÀngige Variable, und sie sollte sich in der Datei
group_vars/myapi/vars der Variableninventar befinden und den Wert 'zum Beispiel' enthalten.
Am praktischsten ist es in diesem Fall, die SchlĂŒsseldatei im Playbook-Repository unter dem Pfad
files/prod/certs/myapi.key, dann wÀre der Wert der Variablen:
api_ssl_key_file: "prod/certs/myapi.key". Der Vorteil liegt darin, dass die Personen, die fĂŒr die Bereitstellung des Systems auf einem bestimmten Stand verantwortlich sind, ebenfalls ihren eigenen Platz im Repository zur Speicherung ihrer Dateien haben. Gleichzeitig bleibt die Möglichkeit bestehen, den absoluten Pfad zum Zertifikat auf dem Server anzugeben, falls die Zertifikate von einem anderen System bereitgestellt werden.
Mehrere StÀnde in einer Umgebung
Es besteht hÀufig die Notwendigkeit, mehrere praktisch identische StÀnde in einer Umgebung mit minimalen Unterschieden zu erweitern. In diesem Fall teilen wir umgebungsabhÀngige Variablen in solche ein, die sich innerhalb dieser Umgebung nicht Àndern, und solche, die variieren. Letztere bringen wir direkt in die Inventardateien ein. Nach dieser Manipulation wird es möglich, ein weiteres Inventar direkt im Umgebungsverzeichnis zu erstellen.
Es wird die Möglichkeit geben, die Inventar group_vars wiederzuverwenden und einige Variablen direkt nach Bedarf zu ĂŒberschreiben.
Die endgĂŒltige Verzeichnisstruktur fĂŒr das Deployment-Projekt:
mydeploy # Deployment-Verzeichnis
âââ deploy.yml # Deployment-Playbook
âââ files # Verzeichnis fĂŒr Deployment-Dateien
â âââ prod # Verzeichnis fĂŒr umgebungsabhĂ€ngige Dateien des prod-Stands
â â âââ certs #
â â âââ myapi.key #
â âââ test1 # Verzeichnis fĂŒr umgebungsabhĂ€ngige Dateien des test1-Stands
âââ group_vars # Verzeichnis fĂŒr Playbook-Variablen
â âââ all.yml # Datei fĂŒr systemweite Variablen
â âââ myapi.yml # Datei fĂŒr Gruppenvariablen der Gruppe myapi
â âââ bbauth.yml #
â âââ ghauth.yml #
âââ inventories #
âââ prod # Verzeichnis der prod-Umgebung
â âââ group_vars # Verzeichnis fĂŒr Inventarvariablen
â â âââ myapi #
â â â âââ vars.yml # UmgebungsabhĂ€ngige Variablen der Gruppe myapi
â â â âââ vault.yml # Geheimnisse (immer umgebungsabhĂ€ngig)
â â âââ bbauth #
â â â âââ vars.yml #
â â â âââ vault.yml #
â â âââ ghauth #
â â âââ vars.yml #
â â âââ vault.yml #
â âââ prod.ini # Inventar des prod-Stands
âââ test # Verzeichnis der test-Umgebung
âââ group_vars #
â âââ myapi #
â â âââ vars.yml #
â â âââ vault.yml #
â âââ bbauth #
â â âââ vars.yml #
â â âââ vault.yml #
â âââ ghauth #
â âââ vars.yml #
â âââ vault.yml #
âââ test1.ini # Inventar des test1-Stands in der test-Umgebung
âââ test2.ini # Inventar des test2-Stands in der test-UmgebungZusammenfassung
Nachdem die Variablen gemÀà dem Artikel organisiert wurden: Jede Datei mit Variablen ist fĂŒr eine bestimmte Aufgabe verantwortlich. Da eine Datei spezifische Aufgaben hat, ist es möglich geworden, jemanden fĂŒr die Korrektheit jeder Datei verantwortlich zu machen. Zum Beispiel wird der Entwickler des Systemdeployments fĂŒr die Korrektheit der Variablen im Playbook verantwortlich, wĂ€hrend der Administrator, dessen Stand im Inventar beschrieben ist, fĂŒr das AusfĂŒllen der Inventarvariablen zustĂ€ndig ist.
Rollen sind zu einer eigenstĂ€ndigen Einheit in der Entwicklung mit einer eigenen BenutzeroberflĂ€che geworden, was es dem Rollenersteller ermöglicht hat, Funktionen zu entwickeln, anstatt die Rolle an das System anzupassen. Besonders dieses Problem betraf allgemeine Rollen fĂŒr alle Systeme in der Kampagne.
Systemadministratoren mĂŒssen sich nicht mehr mit dem Deployment-Code auseinandersetzen. Alles, was sie fĂŒr ein erfolgreiches Deployment benötigen, ist das AusfĂŒllen der dateibezogenen Variablen.
Literatur
Autor
Kaljuzhny Denis Alexandrowitsch
Quelle: habr.com
