Bei einem der Treffen der .Net-Community von St. Petersburg mit Entwicklern der SpbDotNet-Community haben wir ein Experiment durchgeführt und beschlossen, darüber zu sprechen, wie Sie Ansätze anwenden können, die in der Linux-Welt seit langem Standard sind, um Windows-Infrastrukturen zu automatisieren. Um jedoch nicht alles so weit zu bringen, dass das Ansible-Flag markiert wird, wurde beschlossen, dies am Beispiel der Bereitstellung einer ASP.Net-Anwendung zu zeigen.
Aleksey Chernov, Senior Developer des Teams, das die Bibliothek der UI-Komponenten für unsere Projekte entwickelt, meldete sich freiwillig als Redner. Und ja, es schien Ihnen nicht so: Ein JavaScript-Entwickler trat vor ein .Net-Publikum.
Jeder, der sich für das Ergebnis eines solchen Experiments interessiert, ist im Rahmen der Dekodierung willkommen.
Hi) Sie haben sich schon ein wenig verwöhnt und gesagt, dass ich ein Frontend bin, also kannst du schon auseinander gehen =) Mein Name ist Alexey, ich mache seit einiger Zeit alles Mögliche in Bezug auf Webentwicklung. Ich habe mit Perl angefangen, dann gab es PHP, ein bisschen RoR, ein bisschen, ein bisschen davon. Und dann brach JavaScript in mein Leben ein und seitdem mache ich fast alles.
Zusätzlich zu JS habe ich in letzter Zeit ziemlich viele Autotests geschrieben (außerdem auf demselben JS), und deshalb muss ich mich mit der Automatisierung der Bereitstellung von Testbänken und der Infrastruktur für diese befassen.
Hintergrund
Vor zwei Jahren bin ich bei Veeam gelandet, wo sie Produkte für Windows entwickeln. In diesem Moment war ich sehr überrascht, aber es stellte sich heraus, dass es passiert =). Vor allem aber war ich überrascht über den ungewöhnlich geringen Automatisierungsgrad von allem, was mit der Bereitstellung, der Bereitstellung von Anwendungen, Tests usw. zu tun hat.
Wir, die wir für Linux entwickeln, sind seit langem daran gewöhnt, dass alles in Docker sein sollte, es gibt Kubernetes und alles entfaltet sich mit einem einzigen Klick. Und als ich in einer Umgebung landete, in der das alles nicht da ist, war es schockiert. Und als ich anfing, Autotests durchzuführen, stellte ich fest, dass dies nur ein Erfolg von 20% war und alles andere die Infrastruktur für sie vorbereitete.

Meine Gefühle am Anfang
Aktuelle Bedingungen
Ich erzähle Ihnen ein wenig darüber, wie alles bei uns arrangiert ist, was wir automatisieren müssen und was wir tun.
Wir haben eine Reihe verschiedener Produkte, die meisten davon unter Windows, einige unter Linux und sogar etwas unter Solaris. Für alle Produkte werden täglich sehr viele Builds gesammelt. Dementsprechend ist es notwendig, alles in Testlabors sowohl für die Qualitätssicherung als auch für die Entwickler selbst einzuführen, damit sie die Anwendungsintegration überprüfen können. All dies erfordert eine riesige Infrastruktur mit vielen Eisenservern und virtuellen Maschinen. Und manchmal führen wir Leistungstests durch, wenn wir sofort tausend virtuelle Maschinen hochfahren und sehen müssen, wie schnell unsere Anwendungen funktionieren.
Die Probleme
Natürlich wurde in den ersten Phasen (vor langer Zeit gelesen) PowerShell verwendet, um alles direkt zu automatisieren. Das Tool ist leistungsstark, aber Bereitstellungsskripte sind äußerst kompliziert. Ein weiteres Problem war das Fehlen einer zentralen Verwaltung dieses Prozesses. Einige Skripte wurden lokal von Entwicklern ausgeführt, andere auf virtuellen Maschinen, die im Zeitalter der Mammuts usw. erstellt wurden. Infolgedessen war es schwierig, ein einziges Ergebnis zu erhalten und zu verstehen, was funktioniert und was nicht. Wenn Sie zur Arbeit kommen, öffnen Sie den Browser - der Server ist nicht verfügbar. Warum es nicht verfügbar ist, was passiert ist, wo es kaputt gegangen ist - es war völlig unklar. Es gab keinen einzigen Einstiegspunkt und ich musste in funktionierenden Chatrooms nach der Wahrheit suchen. Es ist gut, wenn jemand antwortete.
Ein weiteres Problem, das nicht so offensichtlich ist, sind Neulinge. Es war schwierig für sie. In der ersten Arbeitswoche haben sie sich nur mit dem befasst, was geschah. Wir haben gewöhnlich damit gelebt und uns versichert, dass das Leben eine schwierige Sache ist und wir uns damit abfinden müssen. Sozusagen verstehen und vergeben.
Aber irgendwann fanden sie die innere Kraft, es zu überwinden und sich umzusehen. Wahrscheinlich kannst du irgendwie damit umgehen.

Der erste Schritt zur Lösung des Problems besteht darin, es zu akzeptieren.
Lösungsauswahl
Wenn Sie nicht wissen, was Sie tun sollen, sehen Sie, was andere tun.
Und für den Anfang haben wir unsere Liste der Anforderungen für das erstellt, was wir am Ende bekommen wollen.
- Einheitliche Codebasis. Alle Bereitstellungsskripte sollten sich an derselben Stelle befinden. Möchten Sie etwas bereitstellen oder sehen, wie es sich entwickelt: Hier ist ein Repository für Sie. Gehen Sie dorthin.
- Jeder weiß, wie es funktioniert. Fragen sollten verschwinden a la "Ich verstehe nicht, wie ich es bereitstellen soll, daher kann ich den Fehler am zweiten Tag nicht schließen."
- Möglichkeit, per Knopfdruck zu starten. Wir müssen in der Lage sein, Bereitstellungen zu steuern. Zum Beispiel eine Art Weboberfläche, auf der Sie eine Taste drücken und das gewünschte Produkt auf dem gewünschten Host bereitgestellt wird.
Nachdem wir sichergestellt hatten, dass diese Liste das Minimum an notwendigen und ausreichenden Anforderungen für unser Glück abdeckt, begannen wir es zu versuchen. Traditionell war das erste, was sie versuchten, Probleme zu lösen, die Frontalangriffsmethode. Haben wir viele PowerShell-Skripte? Kombinieren wir sie also zu einem Repository. Das Problem ist jedoch nicht, dass es zu viele Skripte gab, sondern dass verschiedene Teams dasselbe mit verschiedenen Skripten machten. Ich ging durch verschiedene Teams, hörte ihren Anforderungen zu, sammelte dieselben Skripte, versuchte sie irgendwie zu kämmen und zu parametrisieren und legte sie dann in ein einziges Repository.
Fehlgeschlagen: Der Versuch ist fehlgeschlagen. Erstens haben wir viel darüber gestritten, warum wir das tun und nicht so. Warum wurde diese Methode verwendet und nicht irgendeine andere usw. Infolgedessen gab es viele, die alles "wie es sollte" nach dem Prinzip "Ich werde alles für Sie aufteilen und umschreiben" wiederholen wollten. Und natürlich wird es nicht möglich sein, Branchen mit diesem Ansatz zu kombinieren.
Versuch Nummer zwei: Es sollte unseren CI-Server (TeamCity) nehmen, einige Vorlagen darauf erstellen und mithilfe der Vererbung das Hauptproblem vom ersten Versuch an schließen. Wie Sie vielleicht gleich vermutet haben, hat Fail auch auf uns gewartet : Sie können die Vorlage nur für die neueste Version verwenden, was bedeutet, dass wir nicht die erforderliche Versionierung erreichen. Und die Folge einer großen Anzahl von Teams - Vorlagen wurden sehr zahlreich, es wurde schwieriger, sie zu verwalten, und am Horizont war ein neuer Sumpf deutlich sichtbar.

Es war müde, bei jedem Startversuch mit dem Gesicht nach unten zu fallen, und es wurde beschlossen, sich wieder hinzusetzen und nachzudenken. Wir haben also einerseits eine große Anzahl von ps-Skripten und andererseits eine große Anzahl von virtuellen Skripten. Aber wir haben uns geirrt, weil das war nicht die Wurzel des Problems. Das Problem war, dass sich zwischen diesen Dingen immer eine Person befand. Es spielt keine Rolle, ob es sich um einen Entwickler, einen Tester oder eine andere Person handelt. Die folgende logische Kette ist immer im Kopf aufgetreten:
- Ich brauche also eine virtuelle Maschine für Tests
- Ja, hier haben wir einen Host-Pool
- Und hier ist das Skript, das ich brauche. Jetzt werde ich es ausführen und alles wird passieren
Mit der Realisierung einer so scheinbar einfachen Sache begann das allgemeine Problem mit neuen Farben zu spielen. Es stellte sich heraus, dass alle unsere Schmerzen auf das Fehlen einer einzigen Beschreibung unserer Infrastruktur zurückzuführen sind. Es war in den Köpfen der Menschen, die es geschaffen haben, sie saßen in verschiedenen Abteilungen, versuchten nicht, es irgendwie zu dokumentieren, und im Allgemeinen lebten alle in ihrem eigenen Zustand.
In diesem Moment kamen wir zu dem Schluss, dass die Antwort auf alle unsere Probleme lautet:
Infrastruktur als Code
Genau hier sollte unsere gesamte Infrastruktur im Code beschrieben und im Repository abgelegt werden. Alle virtuellen Maschinen, alle ihre Parameter, alles, was dort installiert ist - alles muss im Code beschrieben werden.
Es stellt sich eine berechtigte Frage - warum?
Wir antworten: Dieser Ansatz gibt uns die Möglichkeit, die Best Practices aus der Entwicklungswelt anzuwenden, an die wir alle so gewöhnt sind:
- Versionskontrolle. Wir können immer verstehen, was und wann sich geändert hat. Keine Gastgeber mehr, die aus dem Nichts kommen oder nirgendwo hingehen. Es wird immer klar sein, wer die Änderungen vorgenommen hat.
- Codeüberprüfung. Wir werden in der Lage sein, die Bereitstellungsprozesse so zu steuern, dass einige andere nicht verletzen.
- Kontinuierliche Integration.
Werkzeugauswahl
Wie wir alle wissen, gibt es viele Konfigurationsmanagement-Tools. Wir haben uns für Ansible entschieden, weil es eine Reihe von Funktionen enthält, die wir benötigen.
Zunächst möchten wir, dass das Automatisierungssystem keine Installationsprogramme ausführt, etwas, das irgendwo migriert werden kann usw. Zunächst möchten wir von einem solchen System, dass wir nach dem Drücken einer Taste die Benutzeroberfläche der benötigten Anwendung sehen.
Daher ist das Hauptmerkmal für uns die Idempotenz. Ansible spielt keine Rolle, was vorher passiert ist. Nach dem Start des gewünschten Spielbuchs erhalten wir immer das gleiche Ergebnis. Dies ist sehr wichtig, wenn Sie nicht "IIS installieren" sagen, sondern "Es sollte IIS geben", und Sie müssen nicht darüber nachdenken, ob er zuvor dort war oder nicht. Es ist sehr schwierig, dies mit Skripten zu erreichen, und Ansible-Playbooks bieten eine solche Möglichkeit.
Erwähnenswert ist auch die Agentenlosigkeit von Ansible. Die meisten Automatisierungssysteme arbeiten über Agenten. Dies hat viele Vorteile - zum Beispiel die beste Leistung -, aber es war uns wichtig, dass es keinen Agenten gab, damit das System nicht irgendwie zusätzlich vorbereitet werden musste.
PowerShell:
$url = "http://buildserver/build.msi" $output = "$PSSscriptRoot\build.msi" Invoke-WebRequest -Uri $url -OutFile $output
Ansible:
name: Download build hosts: all tasks: name: Download installer win_get_url: url: "http://buildserver/build.msi" dest: "build.msi" force: no
Hier sehen wir, dass im Basisbeispiel das ps-Skript noch prägnanter ist als das Ansible-Playbook. 3 Zeilen Skript versus 7 Zeilen Playbook, um eine Datei herunterzuladen.
Aber, Petka, es gibt eine Nuance (n). Sobald wir uns an das Prinzip der Idempotenz halten und beispielsweise sicherstellen möchten, dass sich die Datei auf dem Server nicht geändert hat und nicht heruntergeladen werden muss, müssen Sie eine HEAD-Anforderung im Skript implementieren, die etwa 200 Zeilen hinzufügt. Und im Spielbuch - eins. Das Ansible win_get_url-Modul, das alle Überprüfungen für Sie durchführt, enthält 257 Codezeilen, die Sie nicht in jedes Skript einfügen müssen.
Und dies ist nur ein Beispiel für eine sehr einfache Aufgabe.

Und wenn Sie darüber nachdenken, brauchen wir überall Idempotenz:
- Überprüfen Sie das Vorhandensein einer virtuellen Maschine. Bei Skripten besteht die Gefahr, dass entweder unendlich viele davon erstellt werden, oder das Skript stürzt ganz am Anfang ab.
- Welche MSI-Pakete befinden sich auf dem Computer? Im besten Fall fällt hier nichts, im schlimmsten Fall funktioniert die Maschine nicht mehr richtig.
- Muss ich Build-Artefakte erneut herunterladen? Es ist gut, wenn Ihre Builds ein Dutzend Megabyte wiegen. Und was ist mit denen, die ein paar Gigabyte haben?
Und andere Beispiele, bei denen der Ausweg darin besteht, Skripte mit endloser Verzweigung von Ifs aufzublasen, die nicht angemessen debuggt und nicht verwaltet werden können.
Ansible verwendet unter anderem keine Agenten, um Ihre Hosts und Computer zu verwalten. Unter Linux läuft es natürlich unter ssh, während unter Windows WinRM verwendet wird. Daher die offensichtliche Konsequenz: Ansible ist plattformübergreifend. Es unterstützt eine fantastische Anzahl von Plattformen bis hin zu Netzwerkgeräten.
Und das letzte, aber nicht weniger wichtige ist das YAML-Konfigurationsaufzeichnungsformat. Jeder ist daran gewöhnt, es ist leicht zu lesen und es ist leicht herauszufinden, was dort passiert.
Aber nicht alles ist so süß, es gibt Probleme:
- Das Problem ist zweifelhaft: Zum Ausführen von Playbooks benötigen Sie immer noch einen Linux-Computer, auch wenn Ihre gesamte Infrastruktur ausschließlich aus Windows besteht. Obwohl dies in der modernen Welt kein so großes Problem ist, weil Unter Windows 10 gibt es jetzt WSL, wo Sie Ubuntu ausführen können, unter dem Sie Playbooks fahren können.
- Manchmal sind Playbooks wirklich schwer zu debuggen. Ansible ist in Python geschrieben, und das Letzte, was ich sehen möchte, ist ein Python-Stack-Stack-Sheet mit fünf Bildschirmen. Und ein Tippfehler im Modulnamen
Wie funktioniert es
Zuerst brauchen wir eine Linux-Maschine. In der Ansible-Terminologie wird dies als Control Machine bezeichnet.
Playbooks beginnen damit und die ganze Magie passiert darauf.
Auf dieser Maschine benötigen wir:
- Python und der Python-Paketmanager pip. Viele Distributionen sind sofort einsatzbereit, daher gibt es hier keine Überraschungen.
- Installieren Sie Ansible über pip als universellste Methode: pip install ansible
- Fügen Sie ein winrm-Modul hinzu, um zu Windows-Computern zu gelangen: pip install pywinrm [credssp]
- Und auf den Maschinen, die wir steuern möchten, müssen wir winrm aktivieren, weil es ist standardmäßig deaktiviert. Es gibt viele Möglichkeiten, dies zu tun, und alle sind in der Ansible-Dokumentation beschrieben. Am einfachsten ist es jedoch, das fertige Skript aus dem Ansible-Repository zu entnehmen und es mit der erforderlichen Autorisierungsoption auszuführen: ConfigureRemotingForAnsible.ps1 -EnableCredSSP
Der wichtigste Teil, den wir brauchten, um nicht mehr mit ps-Skripten zu leiden, war Inventar. Eine YAML-Datei (in unserem Fall), die unsere Infrastruktur beschreibt und in der Sie immer nachsehen können, wo diese bereitgestellt wird. Und natürlich die Spielbücher selbst. In Zukunft sieht die Arbeit so aus, als würde ein Playbook mit der erforderlichen Inventardatei und zusätzlichen Parametern gestartet.
all: children: webservers: hosts: spbdotnet-test-host.dev.local: dbservers: hosts: spbdotnet-test-host.dev.local: vars: ansible_connection: winrm ansible_winrm_transport: credssp ansible_winrm_server_cert_validation: ignore ansible_user: administrator ansible_password: 123qweASD
Hier ist alles einfach: Die Stammgruppe besteht aus allen und zwei Untergruppen, Webserves und DBServer. Alles andere ist intuitiv, aber ich möchte Ihre Aufmerksamkeit auf die Tatsache lenken, dass Ansible standardmäßig glaubt, dass Linux überall ist. Für Windows müssen Sie daher unbedingt winrm und die Art der Autorisierung angeben.
Natürlich müssen Sie das Passwort nicht in klarer Form im Playbook speichern, hier nur ein Beispiel. Passwörter können beispielsweise in Ansible-Vault gespeichert werden. Wir verwenden hierfür TeamCity, das Geheimnisse durch Umgebungsvariablen weitergibt und nichts auslöst.
Module
Alles, was Ansible macht, macht es mit Hilfe von Modulen. Module für Linux sind in Python geschrieben, für Windows in PowerShell. Und Ehrfurcht vor der Idempotenz: Das Ergebnis des Moduls liegt immer in Form einer JSON-Datei vor, die angibt, ob auf dem Host Änderungen vorgenommen wurden oder nicht.
Im allgemeinen Fall führen wir ein Konstrukt des Formulars ansible host group inventory file list of modules aus:

Spielbücher
Ein Playbook beschreibt, wie und wo wir Ansible-Module ausführen.
- name: Install AWS CLI hosts: all vars: aws_cli_download_dir: c:\downloads aws_cli_msi_url: https://s3.amazonaws.com/aws-cli/AWSCLI32PY3.msi tasks: - name: Ensure target directory exists win_file: path: "{{ aws_cli_download_dir }}" state: directory - name: Download installer win_get_url: url: "{{ aws_cli_msi_url }}" dest: "{{ aws_cli_download_dir }}\\awscli.msi" force: no - name: Install AWS CLI win_package: path: "{{ aws_cli_download_dir }}\\awscli.msi" state: present
In diesem Beispiel haben wir drei Aufgaben. Jede Aufgabe ist ein Modulaufruf. In diesem Playbook erstellen wir zuerst ein Verzeichnis (stellen Sie sicher, dass es vorhanden ist), laden dann die AWS-CLI dort herunter und installieren sie mit dem win_packge-Modul.
Wenn Sie dieses Playbook ausführen, erhalten Sie dieses Ergebnis.

Der Bericht zeigt, dass vier Aufgaben erfolgreich abgeschlossen wurden und drei der vier einige Änderungen am Host vorgenommen haben.
Aber was passiert, wenn Sie dieses Playbook erneut ausführen? Wir haben nirgendwo geschrieben, dass wir das Verzeichnis erstellen, die Installationsdatei herunterladen und ausführen sollen. Wir prüfen einfach die Verfügbarkeit jedes Artikels und überspringen, falls verfügbar.

Dies ist die Idempotenz, die wir mit PowerShell nicht erreichen konnten.
Übe
Dies ist ein leicht vereinfachtes Beispiel, aber im Prinzip ist es genau das, was wir jeden Tag tun.
Wir werden eine Anwendung bereitstellen, die aus einem Windows-Dienst und einer Webanwendung unter IIS besteht.
- name: Setup App hosts: webservers tasks: - name: Install IIS win_feature: name: - Web-Server - Web-Common-Http include_sub_features: True include_management_tools: True state: present register: win_feature - name: reboot if installing Web-Server feature requires it win_reboot: when: win_feature.reboot_required
Zuerst müssen wir prüfen, ob sich auf dem Host IIS befindet, und es installieren, wenn nicht. Und es wäre schön, sofort Management-Tools und alle abhängigen Funktionen hinzuzufügen. Und es ist sehr gut, wenn der Host bei Bedarf neu gestartet wird.
Die erste Aufgabe, die wir lösen, ist das win_feature-Modul, das sich mit der Verwaltung von Windows-Funktionen befasst. Und hier haben wir zum ersten Mal die Umgebungsvariablen Ansible im Registerelement. Denken Sie daran, ich sagte, dass Aufgaben immer ein JSON-Objekt zurückgeben? Nach Abschluss der Aufgabe "IIS installieren" liegt die Ausgabe des Moduls "win_feature" in der Variablen "win_feature" (entschuldigen Sie die Tautologie).
In der nächsten Aufgabe rufen wir das Modul win_reboot auf. Wir müssen unseren Server jedoch nicht jedes Mal neu starten. Wir werden es nur neu laden, wenn das win_feature-Modul diese Anforderung in Form einer Variablen an uns zurückgibt.
Der nächste Schritt ist die Installation von SQL. Hierfür wurden bereits eine Million Wege erfunden. Ich verwende hier das win_chocolatey-Modul. Dies ist ein Paketmanager für Windows. Ja, genau das sind wir unter Linux gewohnt. Die Module werden von der Community unterstützt und es gibt bereits mehr als sechstausend davon. Ich rate Ihnen dringend, es zu versuchen.
- name: SQL Server hosts: dbservers tasks: - name: Install MS SQL Server 2014 win_chocolatey: name: mssqlserver2014express state: present
Also haben wir den Host für den Start der Anwendung vorbereitet. Lassen Sie uns sie bereitstellen!
- name: Deploy binaries hosts: webservers vars: myapp_artifacts: files/MyAppService.zip myapp_workdir: C:\myapp tasks: - name: Remove Service if exists win_service: name: MyAppService state: absent path: "{{ myapp_workdir }}\\MyAppService.exe"
Nur für den Fall, das erste, was wir tun, ist den vorhandenen Dienst zu löschen.
- name: Delete old files win_file: path: "{{ myapp_workdir }}\\" state: absent - name: Copy artifacts to remote machine win_copy: src: "{{ myapp_artifacts }}" dest: "{{ myapp_workdir }}\\" - name: Unzip build artifacts win_unzip: src: "{{ myapp_workdir }}\\MyAppService.zip" dest: "{{ myapp_workdir }}"
Der nächste Schritt ist das Hochladen neuer Artefakte auf den Host. Dieses Playbook impliziert, dass es auf einem Build-Server ausgeführt wird, alle Archive sich in einem bekannten Ordner befinden und wir den Pfad zu ihnen mit Variablen angeben. Nach dem Kopieren (win_copy) werden die Archive entpackt (win_unzip). Dann registrieren wir einfach den Dienst, sagen den Pfad zu exe und dass er gestartet werden soll.
- name: Register and start the service win_service: name: ReporterService start_mode: auto state: started path: "{{ myapp_workdir }}\\MyAppService.exe"
Fertig !?
Es scheint, dass unser Dienst für Arbeit und Verteidigung bereit ist, aber es gibt ein „aber“ - wir haben das Prinzip der Idempotenz nicht beachtet. Wir löschen immer den vorhandenen Code und stellen dann den neuen bereit.
Und das ist das Problem. Wenn wir den alten außer Betrieb befindlichen Dienst gelöscht haben und nachdem ein Fehler aufgetreten ist und das Playbook seine Arbeit nicht abgeschlossen hat, erhalten wir einen defekten Host. Oder wir stellen beispielsweise mehrere Anwendungen gleichzeitig bereit, von denen sich eine nicht geändert hat. Dann müssen wir sie auch nicht bereitstellen.
Was kann getan werden? Alternativ können Sie die Prüfsumme unserer Artefakte überprüfen und mit denen auf dem Server vergleichen.
- name: Get arifacts checksum stat: path: "{{ myapp_artifacts }}" delegate_to: localhost register: myapp_artifacts_stat - name: Get remote artifacts checksum win_stat: path: "{{ myapp_workdir }}\\MyAppService.zip" register: myapp_remote_artifacts_stat
Wir verwenden das stat-Modul, das alle Arten von Informationen zu Dateien bereitstellt, einschließlich der Prüfsumme. Als nächstes schreiben wir das Ergebnis unter Verwendung des bekannten Direktivenregisters in eine Variable. Von interessant: delegate_to gibt an, dass dies auf dem lokalen Computer erfolgen muss, auf dem das Playbook gestartet wird.
- name: Stop play if checksums match meta: end_play when: - myapp_artifacts_stat.stat.checksum is defined - myapp_remote_artifacts_stat.stat.checksum is defined - myapp_artifacts_stat.stat.checksum == myapp_remote_artifacts_stat.stat.checksum
Und mit Hilfe des Metamoduls sagen wir, dass wir das Playbook beenden müssen, wenn die Prüfsummen der Artefakte auf den lokalen und Remote-Computern übereinstimmen. So haben wir das Prinzip der Idempotenz beobachtet.
- name: Ensure that the WebApp application exists win_iis_webapplication: name: WebApp physical_path: c:\webapp site: Default Web Site state: present
Schauen wir uns nun unsere Webanwendung an. Wir lassen den Teil über das Kopieren von Dateien weg und gehen direkt zum Punkt. Unser Build-Server hat den Herausgeber erstellt, alle losen Dateien auf den Host hochgeladen und das integrierte Modul für die Arbeit mit IIS-Anwendungen verwendet. Er wird die Anwendung erstellen und ausführen.
Wiederverwendung von Code
Eine der Aufgaben, die wir uns gestellt haben, war: jedem Ingenieur im Unternehmen zu ermöglichen, eine Bereitstellung einfach zu starten. Er schreibt sein Spielbuch aus vorgefertigten Modulen und sagt, dass er so und so ein Produkt auf so und so einem Host ausführen muss.
Dafür hat Ansible Rollen. Dies ist im Wesentlichen eine Konvention. Wir erstellen einen Ordner / Rollen / auf dem Server und legen unsere Rollen darin ab. Jede Rolle besteht aus einer Reihe von Konfigurationsdateien: einer Beschreibung unserer Geräte, Variablen, Servicedateien usw. Normalerweise spielt eine isolierte Einheit eine Rolle. Die Installation von IIS ist ein gutes Beispiel, wenn wir es nicht nur installieren, sondern auch irgendwie konfigurieren oder mit zusätzlichen Aufgaben überprüfen müssen. Wir erstellen eine separate Rolle und isolieren daher alle IIS-bezogenen Playbooks im Rollenordner. In Zukunft rufen wir diese Rolle einfach mit der Anweisung include_role% role_name% auf.
Natürlich haben wir Rollen für alle Anwendungen festgelegt, sodass die Ingenieure den Prozess mithilfe von Konfigurationsparametern irgendwie anpassen können.
- name: Run App hosts: webservers tasks: - name: "Install IIS" include_role: name: IIS - name: Run My App include_role: name: MyAppService vars: myapp_artifacts: ./buld.zip
In diesem Beispiel kann die Rolle "Meine App ausführen" einen Pfad zu Artefakten übertragen.
Hier müssen Sie ein Wort zu Ansible Galaxy einbringen - einem Repository allgemein verfügbarer Standardlösungen. Wie in einer anständigen Gesellschaft üblich, wurden viele Probleme bereits vor uns gelöst. Und wenn Sie das Gefühl haben, dass wir das Rad jetzt neu erfinden werden, müssen Sie sich zuerst die Liste der integrierten Module ansehen und sich dann mit Ansible Galaxy befassen. Es ist wahrscheinlich, dass das von Ihnen benötigte Spielbuch bereits von einer anderen Person erstellt wurde. Es gibt dort eine große Anzahl von Modulen für alle Gelegenheiten.
Mehr Flexibilität
Aber was ist, wenn es in Galaxy kein eingebautes Modul oder eine geeignete Rolle gibt? Es gibt zwei Möglichkeiten: Entweder machen wir etwas falsch oder wir haben wirklich eine einzigartige Aufgabe.
Bei der zweiten Option können wir unser Modul immer schreiben. Wie ich Ihnen am Anfang gezeigt habe, ermöglicht Ansible das Schreiben des einfachsten Moduls in buchstäblich 10 Minuten. Wenn Sie tiefer gehen, hilft Ihnen eine recht detaillierte Dokumentation, die viele Fragen abdeckt.
Ci
In unserer Abteilung lieben wir TeamCity wirklich, aber es kann jeden anderen CI-Server Ihrer Wahl geben. Warum müssen wir sie teilen?
Erstens können wir immer die Syntax unserer Playbooks überprüfen. Während YAML Tabs als Syntaxfehler betrachtet, ist dies eine sehr nützliche Funktion.
Auch auf dem CI-Server führen wir ansible-lint aus. Dies ist ein statischer Analysator für ansible-Konfigurationen, der eine Liste von Empfehlungen enthält.

Zum Beispiel sagt er hier, dass wir am Ende der Zeile ein zusätzliches Leerzeichen haben und für eine Aufgabe kein Name angegeben wird. Das ist wichtig, weil Der Modulname kann mehrmals im selben Playbook vorkommen, und alle Aufgaben müssen benannt werden.
Natürlich können Sie immer noch Tests für Spielbücher schreiben. Wir können es uns leisten, dies nicht zu tun, weil Wir werden in der Testumgebung bereitstellen und nichts Kritisches wird passieren. Wenn Sie jedoch auf dem Produkt bereitstellen, ist es besser, alles zu überprüfen. Mit dem Vorteil von ansible können Sie nicht nur Playbooks, sondern auch einzelne Module testen. Achten Sie also unbedingt darauf.
Der zweite Hauptgrund für die Verwendung des CI-Servers ist das Starten von Playbooks. Dies ist der gleiche magische Knopf "Gut machen", der uns TeamCity gibt. Wir erstellen nur einige einfache Konfigurationen für verschiedene Produkte, in denen wir sagen: ansible-playbook reporter_vm.yml -i inventar.yml -vvvv und rufen die Schaltfläche Bereitstellen auf.
Bonuskomfort: Sie können Builds je nach Build erstellen. Sobald sich etwas konsolidiert hat, startet TeamCity den Prozess der erneuten Bereitstellung. Danach können wir die Protokolle nur dann anzeigen, wenn plötzlich etwas kaputt geht.
Insgesamt
- Verwirrte und unterschiedliche PowerShell-Skripte, die wir durch YAML-Konfigurationen ersetzt haben.
- Wir haben verschiedene Implementierungen derselben Probleme durch gemeinsame Rollen ersetzt, die wiederverwendet werden können. Es wurde ein Repository erstellt, in dem die Rollen liegen. Wenn die Rolle zu Ihnen passt, verwenden Sie sie einfach. Wenn es nicht zu Ihnen passt, senden Sie einfach die Poolanfrage und es passt zu Ihnen =)
- Sie können jetzt den Erfolg der Bereitstellung an einem einzigen Ort überprüfen.
- Jeder weiß, wo er nach Protokollen suchen muss.
- Kommunikationsprobleme wurden auch über ein gemeinsames Repository und TeamCity gelöst. Alle Interessierten wissen, wo sich Spielbücher befinden und wie sie funktionieren.
PS Alle Beispiele aus dem Artikel können auf Github genommen werden .