Systemansatz für Variablen in Ansible

Ansible entwickelt Codestil

Hey! Ich heiße Denis Kaljuschny Ich arbeite als Ingenieur in der Abteilung Entwicklungsprozessautomatisierung. Jeden Tag werden neue Anwendungs-Builds auf Hunderten von Kampagnenservern bereitgestellt. Und in diesem Artikel teile ich meine Erfahrungen mit der Verwendung von Ansible für diese Zwecke.

Dieses Handbuch bietet eine Möglichkeit, Variablen in einer Bereitstellung zu organisieren. Dieser Leitfaden richtet sich an diejenigen, die bereits Rollen in ihren Playbooks verwenden und lesen Empfohlene Vorgehensweiseaber ich stoße auf ähnliche Probleme:

  • Wenn man eine Variable im Code gefunden hat, ist es unmöglich, sofort zu verstehen, wofür sie verantwortlich ist;
  • Es gibt mehrere Rollen und die Variablen müssen einem Wert zugeordnet werden, aber das funktioniert nicht;
  • Es fällt Ihnen schwer, anderen zu erklären, wie die Logik der Variablen in Ihren Playbooks funktioniert

Wir sind bei Projekten in unserem Unternehmen auf diese Probleme gestoßen, wodurch wir zu den Regeln für die Formatierung von Variablen in unseren Playbooks kamen, die diese Probleme teilweise lösten.

Systemansatz für Variablen in Ansible

Variablen in Rollen

Eine Rolle ist ein separates Bereitstellungssystemobjekt. Wie jedes Objekt des Systems muss es über eine Schnittstelle zur Interaktion mit dem Rest des Systems verfügen. Rollenvariablen sind eine solche Schnittstelle.

Nehmen Sie zum Beispiel die Rolle api, wodurch eine Java-Anwendung auf dem Server installiert wird. Welche Variablen hat es?

Systemansatz für Variablen in Ansible

Rollenvariablen können je nach Typ in zwei Typen unterteilt werden:

1. Свойства
    a) независимые от среды
    б) зависимые от среды
2. Связи
    a) слушатели 
    б) запросы внутри системы
    в) запросы в среду

Variable Eigenschaften sind Variablen, die das Verhalten einer Rolle definieren.

Abfragevariablen sind Variablen, deren Wert zur Bezeichnung von Ressourcen außerhalb der Rolle verwendet wird.

Variable Zuhörer sind Variablen, deren Wert zur Bildung von Abfragevariablen verwendet wird.

Andererseits sind 1a, 2a, 2b Variablen, die nicht von der Umgebung (Eisen, externe Ressourcen usw.) abhängen und in der Standardrolle mit Standardwerten gefüllt werden können. Variablen wie 1.b und 2.c können jedoch nicht mit anderen Werten als „Beispiel“ gefüllt werden, da sie sich je nach Umgebung von Stand zu Stand ändern.

Codestil

  • Der Name der Variable muss mit dem Namen der Rolle beginnen. Dadurch lässt sich in Zukunft leicht herausfinden, welche Rolle die Variable spielt und wofür sie verantwortlich ist.
  • Bei der Verwendung von Variablen in Rollen müssen Sie unbedingt das Prinzip der Kapselung befolgen und Variablen verwenden, die entweder in der Rolle selbst oder in den Rollen, von denen die aktuelle Rolle abhängt, definiert sind.
  • Vermeiden Sie die Verwendung von Wörterbüchern für Variablen. Ansible ermöglicht es Ihnen nicht, einzelne Werte in einem Wörterbuch bequem zu überschreiben.

    Ein Beispiel für eine fehlerhafte Variable:

    myrole_user:
        login: admin
        password: admin

    Hier ist „Login“ die mittlere Variable und „Passwort“ die abhängige Variable. Aber
    Da sie in einem Wörterbuch zusammengefasst sind, müssen Sie es vollständig angeben
    Stets. Was sehr unpraktisch ist. Besser so:

    myrole_user_login: admin
    myrole_user_password: admin

Variablen in Bereitstellungs-Playbooks

Beim Kompilieren eines Bereitstellungs-Playbooks (im Folgenden als Playbook bezeichnet) halten wir uns an die Regel, dass es in einem separaten Repository abgelegt werden sollte. Genau wie Rollen: jede in ihrem eigenen Git-Repository. Dadurch können Sie erkennen, dass es sich bei den Rollen und dem Playbook um unterschiedliche unabhängige Objekte des Bereitstellungssystems handelt und dass Änderungen an einem Objekt keinen Einfluss auf den Betrieb des anderen haben sollten. Dies wird durch die Änderung der Standardwerte der Variablen erreicht.

Zusammenfassend ist es beim Kompilieren eines Playbooks möglich, die Standardwerte von Rollenvariablen an zwei Stellen zu überschreiben: in Playbook-Variablen und in Inventarvariablen.

mydeploy                        # Каталог деплоя
├── deploy.yml                  # Плейбук деплоя
├── group_vars                  # Каталог переменных плейбука
│   ├── all.yml                 # Файл для переменных связи всей системы
│   └── myapi.yml               # Файл переменных свойств группы myapi
└── inventories                 #
    └── prod                    # Каталог окружения prod
        ├── prod.ini            # Инвентори файл
        └── group_vars          # Каталог для переменных инвентори
            └── myapi           #
                ├── vars.yml    # Средозависимые переменные группы myapi
                └── vault.yml   # Секреты (всегда средозависимы) *

* - Variablen und Tresore

Der Unterschied besteht darin, dass Playbook-Variablen immer verwendet werden, wenn Playbooks aufgerufen werden, die sich auf derselben Ebene befinden. Dies bedeutet, dass sich diese Variablen hervorragend zum Ändern der Standardwerte von Variablen eignen, die nicht von der Umgebung abhängen. Umgekehrt werden Inventarvariablen nur für eine bestimmte Umgebung verwendet, was ideal für umgebungsspezifische Variablen ist.

Es ist wichtig zu beachten, dass die Variablenpriorität es Ihnen nicht ermöglicht, Variablen zunächst in Playbook-Variablen und dann separat im selben Inventar neu zu definieren.

Das bedeutet, dass Sie bereits zu diesem Zeitpunkt entscheiden müssen, ob die Variable umgebungsabhängig ist oder nicht, und sie an der richtigen Stelle platzieren.

Beispielsweise war in einem Projekt die für die Aktivierung von SSL verantwortliche Variable lange Zeit umgebungsabhängig, da wir SSL aus Gründen, die außerhalb unserer Kontrolle lagen, an einem der Stände nicht aktivieren konnten. Nachdem wir dieses Problem behoben hatten, wurde es medienunabhängig und auf Playbook-Variablen verschoben.

Eigenschaftsvariablen für Gruppen

Erweitern wir unser Modell in Abbildung 1, indem wir zwei Servergruppen mit einer anderen Java-Anwendung, aber mit unterschiedlichen Einstellungen hinzufügen.

Systemansatz für Variablen in Ansible

Stellen Sie sich vor, wie das Playbook in diesem Fall aussehen wird:

- hosts: myapi
  roles:
    - api

- hosts: bbauth
  roles:
    - auth

- hosts: ghauth
  roles:
    - auth

Wir haben drei Gruppen im Playbook, daher wird empfohlen, möglichst viele Gruppendateien in den Inventarvariablen „group_vars“ und den Playbook-Variablen gleichzeitig zu erstellen. Eine Gruppendatei ist in diesem Fall die Beschreibung einer Komponente Ihrer Anwendung im Playbook. Wenn Sie die Gruppendatei in den Playbook-Variablen öffnen, sehen Sie sofort alle Unterschiede zum Standardverhalten der der Gruppe zugewiesenen Rollen. In Inventarvariablen: Unterschiede im Gruppenverhalten von Stand zu Stand.

Codestil

  • Versuchen Sie, überhaupt keine host_vars-Variablen zu verwenden, da diese nicht das System beschreiben, sondern nur einen Sonderfall, der auf lange Sicht zu Fragen führen wird: „Warum unterscheidet sich dieser Host von den anderen?“ Die Antwort darauf lautet nicht immer leicht zu finden.

Variablen verknüpfen

Dabei geht es allerdings um Eigenschaftsvariablen, aber was ist mit Linkvariablen?
Ihr Unterschied besteht darin, dass sie in verschiedenen Gruppen den gleichen Wert haben müssen.

Am Anfang gab es идея Verwenden Sie eine monströse Konstruktion der Form:
hostvars[groups['bbauth'][0]]['auth_bind_port'], aber es wurde sofort aufgegeben
weil es Mängel hat. Erstens die Sperrigkeit. Zweitens die Abhängigkeit von einem bestimmten Wirt in der Gruppe. Drittens ist es notwendig, Fakten von allen Hosts zu sammeln, bevor mit der Bereitstellung begonnen wird, wenn wir keinen Fehler aufgrund einer undefinierten Variable erhalten möchten.

Aus diesem Grund wurde beschlossen, Linkvariablen zu verwenden.

Variablen verknüpfen sind Variablen, die zum Playbook gehören und zur Verknüpfung von Systemobjekten benötigt werden.

Linkvariablen werden in allgemeine Systemvariablen gefüllt group_vars/all/vars Sie werden gebildet, indem alle Listener-Variablen aus jeder Gruppe entfernt und der Name der Gruppe, aus der der Listener entfernt wurde, am Anfang der Variablen hinzugefügt werden.

Dadurch wird die Einheitlichkeit und Nichtüberschneidung der Namen gewährleistet.

Versuchen wir, Variablen aus dem obigen Beispiel zu binden:

Systemansatz für Variablen in Ansible

Stellen Sie sich vor, wir haben Variablen, 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"

Setzen wir es in gemeinsame Variablen ein group_vars/all/vars Alle Zuhörer, und fügen Sie den Namen der Gruppe zum Namen hinzu:

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

Indem wir nun den Wert des Connectors ändern, stellen wir sicher, dass die Anfrage an denselben Ort gesendet wird, an dem sich der Port befindet.

Codestil

  • Da Rollen und Gruppen unterschiedliche Objekte im System sind, müssen Sie unterschiedliche Namen für sie haben, damit die Linkvariablen genau zeigen, dass sie zu einer bestimmten Gruppe von Servern und nicht zu einer Rolle im System gehören.

Umgebungsdateien

Rollen können Dateien verwenden, die von Umgebung zu Umgebung unterschiedlich sind.

Ein Beispiel für solche Dateien sind SSL-Zertifikate. Speichern Sie sie als Text
in einer Variablen ist nicht sehr praktisch. Es ist jedoch praktisch, den Pfad zu ihnen in einer Variablen zu speichern.

Wir verwenden zum Beispiel die Variable api_ssl_key_file: "/path/to/file".

Da es offensichtlich ist, dass sich das Schlüsselzertifikat von Umgebung zu Umgebung ändert, handelt es sich um eine umgebungsabhängige Variable, das heißt, sie sollte in der Datei liegen
group_vars/myapi/vars Inventar von Variablen und enthalten den Wert „zum Beispiel“.

In diesem Fall ist es am bequemsten, die Schlüsseldatei entlang des Pfads im Playbook-Repository abzulegen
files/prod/certs/myapi.key, dann ist 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 an einem bestimmten Stand verantwortlich sind, auch über einen eigenen Platz im Repository verfügen, an dem sie ihre Dateien speichern können. Gleichzeitig besteht weiterhin 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

Oft besteht die Notwendigkeit, mehrere nahezu identische Stände mit minimalen Unterschieden in derselben Umgebung bereitzustellen. In diesem Fall unterteilen wir umgebungsabhängige Variablen in solche, die sich innerhalb dieser Umgebung nicht ändern, und solche, die sich ändern. Und letztere nehmen wir direkt in die Inventardateien selbst auf. Nach dieser Manipulation ist es möglich, direkt im Umgebungsverzeichnis ein weiteres Inventar zu erstellen.

Es wird den Bestand von „group_vars“ wiederverwenden und kann außerdem einige Variablen direkt für sich selbst neu definieren.

Die endgültige Verzeichnisstruktur für das Bereitstellungsprojekt:

mydeploy                        # Каталог деплоя
├── deploy.yml                  # Плейбук деплоя
├── files                       # Каталог для файлов деплоя
│   ├── prod                    # Католог для средозависимых файлов стенда prod
│   │   └── certs               # 
│   │       └── myapi.key       #
│   └── test1                   # Каталог для средозависимых файлов стенда test1
├── group_vars                  # Каталог переменных плейбука
│   ├── all.yml                 # Файл для переменных связи всей системы
│   ├── myapi.yml               # Файл переменных свойств группы myapi
│   ├── bbauth.yml              # 
│   └── ghauth.yml              #
└── inventories                 #
    ├── prod                    # Каталог окружения prod
    │   ├── group_vars          # Каталог для переменных инвентори
    │   │   ├── myapi           #
    │   │   │   ├── vars.yml    # Средозависимые переменные группы myapi
    │   │   │   └── vault.yml   # Секреты (всегда средозависимы)
    │   │   ├── bbauth          # 
    │   │   │   ├── vars.yml    #
    │   │   │   └── vault.yml   #
    │   │   └── ghauth          #
    │   │       ├── vars.yml    #
    │   │       └── vault.yml   #
    │   └── prod.ini            # Инвентори стенда prod
    └── test                    # Каталог окружения test
        ├── group_vars          #
        │   ├── myapi           #
        │   │   ├── vars.yml    #
        │   │   └── vault.yml   #
        │   ├── bbauth          #
        │   │   ├── vars.yml    #
        │   │   └── vault.yml   #
        │   └── ghauth          #
        │       ├── vars.yml    #
        │       └── vault.yml   #
        ├── test1.ini           # Инвентори стенда test1 в среде test
        └── test2.ini           # Инвентори стенда test2 в среде test

Zusammenfassen

Nach der Organisation der Variablen gemäß dem Artikel: Jede Datei mit Variablen ist für eine bestimmte Aufgabe verantwortlich. Und da die Datei bestimmte Aufgaben hat, wurde es möglich, für jede Datei eine Person zu benennen, die für die Richtigkeit verantwortlich ist. Beispielsweise ist der Entwickler der Systembereitstellung für das korrekte Ausfüllen der Playbook-Variablen verantwortlich, während der Administrator, dessen Stand im Inventar beschrieben ist, direkt für das Ausfüllen des Variableninventars verantwortlich ist.

Rollen wurden zu einer eigenständigen Entwicklungseinheit mit eigener Schnittstelle, die es dem Rollenentwickler ermöglichte, Funktionen zu entwickeln, anstatt die Rolle an das System anzupassen. Dieses Problem traf insbesondere auf gemeinsame Rollen für alle Systeme in einer Kampagne zu.

Systemadministratoren müssen den Bereitstellungscode nicht mehr verstehen. Für eine erfolgreiche Bereitstellung müssen sie lediglich die Dateien der Umgebungsvariablen ausfüllen.

Literatur

  1. Dokumentation

Autor

Kaljuschny Denis Alexandrowitsch

Source: habr.com

Kommentar hinzufügen