Systematischer Ansatz fĂŒr Variablen in Ansible

Ansible DevOps Codestil

Hallo! Mein Name ist Denis Kalujny Ich arbeite als Ingenieur in der Abteilung fĂŒr Automatisierung von Entwicklungsprozessen. Jeden Tag werden neue Anwendungsbuilds auf Hunderten von Servern des Unternehmens implementiert. In diesem Artikel teile ich meine Erfahrungen mit Ansible zu diesem Zweck.

Dieser Leitfaden bietet einen Ansatz zur Organisation von Variablen im Deployment. Er richtet sich an diejenigen, die bereits Rollen in ihren Playbooks verwenden und die BestPracticesgelesen haben, aber auf folgende Probleme stoßen:

  • Wenn man eine Variable im Code findet, ist es oft schwierig, sofort zu verstehen, wofĂŒr sie verantwortlich ist;
  • Es gibt mehrere Rollen, und die Variablen mĂŒssen mit einem Wert verknĂŒpft werden, aber das funktioniert nicht;
  • Es fĂ€llt schwer, anderen zu erklĂ€ren, wie die Logik der Variablen in euren Playbooks funktioniert.

Mit diesen Problemen sind wir in unseren Projekten in der Firma konfrontiert worden, was uns zu Regeln fĂŒr die Handhabung von Variablen in unseren Playbooks gefĂŒhrt hat, die diese Probleme teilweise gelöst haben.

Systematischer Ansatz fĂŒr Variablen in Ansible

Variablen in Rollen

Eine Rolle ist ein separates Objekt im Deployment-System. Wie jedes andere Objekt im System sollte es eine Schnittstelle zur Interaktion mit dem Rest des Systems haben. Diese Schnittstelle besteht aus den Variablen der Rolle.

Nehmen wir als Beispiel die Rolle api, die eine Java-Anwendung auf dem Server installiert. Welche Variablen könnte sie haben?

Systematischer Ansatz fĂŒr Variablen in Ansible

Die Rollenvariablen lassen sich in zwei Typen unterteilen:

1. Eigenschaften
    a) umgebungsunabhÀngig
    b) umgebungsabhÀngig
2. Beziehungen
    a) Listener
    b) interne Systemanfragen
    c) Anfragen an die Umgebung

Eigenschaften-Variablen — das sind Variablen, die das Verhalten der Rolle definieren.

Anfrage-Variablen — das sind Variablen, deren Werte verwendet werden, um externe, die Rolle betreffende, Ressourcen zu kennzeichnen.

Listener-Variablen — das sind Variablen, deren Werte zur Bildung der Anfrage-Variablen verwendet werden.

Andererseits sind 1a, 2a, 2b Variablen, die nicht von der Umgebung (Hardware, externe Ressourcen etc.) abhĂ€ngen und mit Standardwerten in den Defaults der Rolle gefĂŒllt werden können. Allerdings können Variablen des Typs 1b und 2c nur mit Werten wie 'example' gefĂŒllt werden, da sie von Stand zu Stand je nach Umgebung variieren.

Code-Stil

  • Der Name einer Variablen muss unbedingt mit dem Namen der Rolle beginnen. Dies erleichtert spĂ€ter das VerstĂ€ndnis, aus welcher Rolle die Variable stammt und wofĂŒr sie zustĂ€ndig ist.
  • Bei der Verwendung von Variablen in Rollen sollten Sie unbedingt das Prinzip der Kapselung beachten und Variablen verwenden, die entweder in der Rolle selbst oder in den Rollen definiert sind, von denen die aktuelle abhĂ€ngt.
  • Vermeiden Sie es, WörterbĂŒcher fĂŒr Variablen zu verwenden. Ansible lĂ€sst keine einfache Überschreibung einzelner Werte in einem Wörterbuch zu.

    Beispiel einer schlechten Variable:

    myrole_user:
        login: admin
        password: admin

    Hier ist login eine umgebungsunabhÀngige Variable, wÀhrend password abhÀngig ist. Aber
    da sie in einem Wörterbuch zusammengefasst sind, mĂŒssen Sie diese immer vollstĂ€ndig angeben.
    Was sehr unpraktisch ist. Besser so:

    myrole_user_login: admin
    myrole_user_password: admin

Variablen in Deployment-Playbooks

Bei der Erstellung eines Deployment-Playbooks (im Folgenden Playbook genannt) halten wir uns an die Regel, dass es in einem separaten Repository abgelegt werden sollte. So wie die Rollen: jede in ihrem eigenen Git-Repository. Das ermöglicht es, zu erkennen, dass Rollen und das Playbook verschiedene, unabhĂ€ngige Objekte des Deploymentsystems sind und Änderungen an einem Objekt die FunktionalitĂ€t des anderen nicht beeintrĂ€chtigen sollten. Dies wird durch die Anpassung der Standardwerte von Variablen erreicht.

Beim Erstellen eines Playbooks haben Sie die Möglichkeit, die Standardwerte von Rollenvariablen an zwei Stellen zu ĂŒberschreiben: in den Playbook-Variablen und in den Inventarvariablen.

mydeploy                        # Deployment-Verzeichnis
├── deploy.yml                  # Deployment-Playbook
├── group_vars                  # Verzeichnis fĂŒr Playbook-Variablen
│   ├── all.yml                 # Datei fĂŒr systemweite Variablen
│   └── myapi.yml               # Datei fĂŒr Gruppenvariablen von myapi
└── inventories                 #
    └── prod                    # Verzeichnis fĂŒr die Prod-Umgebung
        ├── prod.ini            # Inventar-Datei
        └── group_vars          # Verzeichnis fĂŒr Inventarvariablen
            └── myapi           #
                ├── vars.yml    # UmgebungsabhĂ€ngige Variablen der Gruppe myapi
                └── vault.yml   # Geheimnisse (immer umgebungsabhĂ€ngig) *

* — Variablen und Tresore

Der Unterschied besteht darin, dass Variablen eines Playbooks immer beim Aufruf von Playbooks verwendet werden, die sich auf derselben Ebene befinden. Das bedeutet, dass diese Variablen ideal geeignet sind, um Standardwerte von variablen Umgebungen zu Ă€ndern. Im Gegensatz dazu werden Inventarvariablen nur fĂŒr eine bestimmte Umgebung verwendet, was ideal fĂŒr umgebungsabhĂ€ngige Variablen ist.

Es ist wichtig zu beachten, dass die PrioritĂ€t der Variablen nicht zulĂ€sst, dass Sie Variablen zuerst in Playbook-Variablen und dann zusĂ€tzlich in einem Inventar ĂŒberschreiben.

Das bedeutet, dass Sie bereits in dieser Phase entscheiden mĂŒssen, ob die Variable umgebungsabhĂ€ngig oder nicht ist, und sie am richtigen Platz zuordnen sollten.

Zum Beispiel war in einem Projekt die Variable, die fĂŒr die Aktivierung von SSL zustĂ€ndig war, lange zeit umgebungsabhĂ€ngig, da wir aus uns nicht zuzurechnenden GrĂŒnden SSL in einer unserer Umgebungen nicht aktivieren konnten. Nachdem wir dieses Problem behoben hatten, wurde sie umgebungsunabhĂ€ngig und wurde in die Playbook-Variablen verschoben.

Eigenschaftsvariablen fĂŒr Gruppen

Wir erweitern unser Modell in Abbildung 1, indem wir 2 Gruppen von Servern mit einer anderen Java-Anwendung, aber mit unterschiedlichen Einstellungen hinzufĂŒgen.

Systematischer Ansatz fĂŒr Variablen in Ansible

Lassen Sie uns vorstellen, wie das Playbook in diesem Fall aussehen könnte:

- hosts: myapi
  roles:
    - api

- hosts: bbauth
  roles:
    - auth

- hosts: ghauth
  roles:
    - auth

Wir haben drei Gruppen im Playbook, daher wird empfohlen, ebenso viele Dateien fĂŒr Gruppen in den group_vars der Inventarvariablen und des Playbooks zu erstellen. Eine Gruppendatei beschreibt in diesem Fall eine Komponente Ihrer Anwendung im Playbook. Wenn Sie die Gruppendatei in den Variablen des Playbooks öffnen, sehen Sie sofort alle Unterschiede zum Standardverhalten der auf die Gruppe angewendeten Rollen. In den Inventarvariablen: Unterschiede im Verhalten der Gruppe von Stand zu Stand.

Code-Stil

  • Versuchen Sie, host_vars-Variablen so gut wie möglich zu vermeiden, da sie das System nicht beschreiben, sondern nur einen Einzelfall darstellen, was langfristig zu Fragen fĂŒhrt: "Warum unterscheidet sich dieser Host von den anderen?", auf die nicht immer leicht eine Antwort zu finden ist.

Verbindungsvariablen

Das betrifft jedoch die Eigenschaftenvariablen. Wie gehen wir mit den Verbindungsvariablen um?
Ihr Unterschied besteht darin, dass sie in verschiedenen Gruppen den gleichen Wert haben mĂŒssen.

UrsprĂŒnglich gab es die Idee eine monströse Konstruktion zu verwenden:
hostvars[groups['bbauth'][0]]['auth_bind_port'], aber davon wurde sofort Abstand genommen
da sie Nachteile hat. Erstens ist sie unhandlich. Zweitens besteht eine AbhĂ€ngigkeit von einem bestimmten Host in der Gruppe. Drittens mĂŒssen vor dem Deployment alle Fakten von allen Hosts gesammelt werden, wenn wir keinen Fehler ĂŒber eine nicht definierte Variable erhalten möchten.

Es wurde beschlossen, Bindungsvariablen zu verwenden.

Verbindungsvariablen Das sind Variablen, die zum Playbook gehören und zur Verbindung der Systemobjekte benötigt werden.

Die Bindungsvariablen werden in den allgemeinen Systemvariablen ausgefĂŒllt. group_vars/all/vars und entstehen durch das Herausziehen aller Listener-Variablen aus jeder Gruppe und das HinzufĂŒgen des Gruppennamens an den Anfang der Variablen, von wo der Listener herausgezogen wurde.

So wird eine Einheitlichkeit und Nicht-Überlappung von Namen sichergestellt.

Versuchen wir, die Variablen aus dem obigen Beispiel zu verbinden:

Systematischer Ansatz fĂŒr Variablen in Ansible

Angenommen, wir haben Variablen, die voneinander abhÀngig sind:

# roles/api/defaults:
# ĐŸĐ”Ń€Đ”ĐŒĐ”ĐœĐœĐ°Ń Đ·Đ°ĐżŃ€ĐŸŃĐ°
api_auth1_address: "http://example.com:80"
api_auth2_address: "http://example2.com:80"

# roles/auth/defaults:
# ĐŸĐ”Ń€Đ”ĐŒĐ”ĐœĐœĐ°Ń ŃĐ»ŃƒŃˆĐ°Ń‚Đ”Đ»ŃŒ
auth_bind_port: "20000"

Wir ziehen alle Listener in die allgemeinen Variablen group_vars/all/vars und fĂŒgen den Gruppennamen in den Titel ein:

# 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 }}"

Jetzt sind wir sicher, dass die Abfrage dort hinfĂŒhrt, wo sich der Port befindet, wenn wir den Wert des Connectors Ă€ndern.

Code-Stil

  • Da Rollen und Gruppen unterschiedliche Objekte im System sind, mĂŒssen sie unterschiedliche Namen haben, damit die Verbindungsvariablen klar anzeigen, zu welcher spezifischen Gruppe von Servern sie gehören und nicht zu einer Rolle im System.

UmgebungsabhÀngige Dateien

In Rollen können Dateien verwendet werden, die von Umgebung zu Umgebung unterschiedlich sind.

Ein Beispiel fĂŒr solche Dateien sind SSL-Zertifikate. Es ist nicht sehr praktisch, sie im Textformat
in einer Variablen zu speichern. Es ist jedoch bequem, den Pfad zu ihnen innerhalb der Variablen zu speichern.

Verwenden wir zum Beispiel die Variable api_ssl_key_file: "/path/to/file".

Da offensichtlich ist, dass das SchlĂŒsselzertifikat von Umgebung zu Umgebung variieren wird, handelt es sich um eine umgebungsabhĂ€ngige Variable, die daher in der Datei
group_vars/myapi/vars der Variableninventarisierung angeordnet sein sollte und den Wert 'zum Beispiel' enthalten sollte.

In diesem Fall ist es am praktischsten, die SchlĂŒsseldatei im Playbook-Repository unter dem Pfad
files/prod/certs/myapi.keyzu speichern, 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, 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 bereitzustellen. In diesem Fall unterteilen wir die umgebungsabhÀngigen Variablen in solche, die innerhalb dieser Umgebung unverÀndert bleiben, und in solche, die verÀndert werden. Letztere werden direkt in die Inventardateien ausgegliedert. Nach dieser Manipulation ist es möglich, eine weitere Inventardatei direkt im Verzeichnis der Umgebung zu erstellen.

Diese wird die Inventar group_vars wiederverwenden und gleichzeitig die Möglichkeit bieten, einige Variablen direkt fĂŒr sich selbst zu ĂŒberschreiben.

Die endgĂŒltige Verzeichnisstruktur fĂŒr das Deployment-Projekt:

mydeploy                        # Bereitstellungskatalog
├── deploy.yml                  # Bereitstellungs-Playbook
├── files                       # Katalog fĂŒr Bereitstellungsdateien
│   ├── prod                    # Katalog fĂŒr umgebungsabhĂ€ngige Dateien des prod-Standes
│   │   └── certs               # 
│   │       └── myapi.key       #
│   └── test1                   # Katalog fĂŒr umgebungsabhĂ€ngige Dateien des test1-Standes
├── group_vars                  # Katalog fĂŒr Playbook-Variablen
│   ├── all.yml                 # Datei fĂŒr systemweite Verbindungsvariablen
│   ├── myapi.yml               # Datei der Variablen fĂŒr die Gruppe myapi
│   ├── bbauth.yml              # 
│   └── ghauth.yml              #
└── inventories                 #
    ├── prod                    # Katalog fĂŒr die prod-Umgebung
    │   ├── group_vars          # Katalog 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-Standes
    └── test                    # Katalog fĂŒr die test-Umgebung
        ├── group_vars          #
        │   ├── myapi           #
        │   │   ├── vars.yml    #
        │   │   └── vault.yml   #
        │   ├── bbauth          #
        │   │   ├── vars.yml    #
        │   │   └── vault.yml   #
        │   └── ghauth          #
        │       ├── vars.yml    #
        │       └── vault.yml   #
        ├── test1.ini           # Inventar des test1-Standes in der test-Umgebung
        └── test2.ini           # Inventar des test2-Standes in der test-Umgebung

Zusammenfassung

Nach der Organisation der Variablen gemĂ€ĂŸ dem Artikel: Jede Datei mit Variablen ist fĂŒr eine bestimmte Aufgabe verantwortlich. Da eine Datei bestimmte Aufgaben hat, ist es möglich geworden, einen Verantwortlichen fĂŒr die Korrektheit jeder Datei zu benennen. Beispielsweise wird der Entwickler des Systemdeployments fĂŒr die korrekte AusfĂŒllung der Variablen des Playbooks verantwortlich, wĂ€hrend der Administrator, dessen Stand im Inventory beschrieben ist, fĂŒr die AusfĂŒllung der Inventory-Variablen zustĂ€ndig ist.

Rollen sind zu einer eigenstĂ€ndigen Einheit in der Entwicklung mit einer eigenen Schnittstelle geworden, was es dem Rollendesigner ermöglicht, Funktionen zu entwickeln, anstatt die Rolle an das System anzupassen. Besonders dieses Problem betraf die gemeinsamen Rollen fĂŒr alle Systeme im Unternehmen.

Systemadministratoren mĂŒssen sich nicht mehr im Deployment-Code auskennen. Alles, was fĂŒr ein erfolgreiches Deployment von ihnen verlangt wird, ist das AusfĂŒllen der umgebungsabhĂ€ngigen Variablen-Dateien.

Literatur

  1. Dokumentation

Autor

Kaljuzhny Denis Alexandrowitsch

Quelle: habr.com

ZuverlĂ€ssiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen đŸ”„ ZuverlĂ€ssiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen | ProHoster