Best Practices für Continuous Delivery mit Docker (Überblick und Video)

Wir beginnen unseren Blog mit Veröffentlichungen, die auf den kürzlichen Vorträgen unseres technischen Direktors basieren. distol (Dmitrij Stolyarov). Alle fanden im Jahr 2016 bei verschiedenen Fachveranstaltungen statt und handelten von DevOps und Docker. Ein Video von einem Treffen in Docker Moscow in den Büros von Badoo haben wir bereits veröffentlicht auf der Website. Weitere werden mit Artikeln begleitet, die den Kern der Vorträge wiedergeben. Also…

Am 31. Mai fand auf der Konferenz RootConf 2016im Rahmen des Festivals „Russische Internet-Technologien“ (RIT++ 2016) die Sektion „Continuous Deployment und Deployment“ mit dem Vortrag „Beste Praktiken für Continuous Delivery mit Docker“ statt. In diesem wurden die besten Praktiken für den Aufbau eines Continuous Delivery (CD) Prozesses unter Verwendung von Docker und anderen Open Source-Produkten zusammengefasst und systematisiert. Mit diesen Lösungen arbeiten wir in der Produktion, was es uns ermöglicht, auf praktischen Erfahrungen zu basieren.

Best Practices für Continuous Delivery mit Docker (Überblick und Video)

Wenn Sie die Möglichkeit haben, eine Stunde für das Video mit dem Vortrageinzuräumen, empfehlen wir, es vollständig anzusehen. Andernfalls finden Sie unten die wichtigsten Inhalte in Textform.

Continuous Delivery mit Docker

Unter Continuous Delivery Wir verstehen den Ablauf, in dem der Anwendungscode aus dem Git-Repository zunächst in die Produktion gelangt und anschließend archiviert wird. Dieser Prozess sieht wie folgt aus: Git → Build → Test → Release → Operate.

Best Practices für Continuous Delivery mit Docker (Überblick und Video)
Der Großteil des Berichts widmet sich der Phase des Builds, während die Themen Release und Operate nur allgemein behandelt werden. Es geht um Probleme und Muster, die helfen, diese zu lösen, wobei die konkreten Implementierungen dieser Muster unterschiedlich sein können.

Warum ist Docker hier überhaupt notwendig? Wir haben nicht ohne Grund über die Praktiken des Continuous Delivery im Kontext dieses Open-Source-Tools gesprochen. Obwohl der gesamte Bericht diesem Thema gewidmet ist, werden viele Gründe bereits bei der Betrachtung des Hauptmusters des Rollouts des Anwendungscodes deutlich.

Das Hauptmuster des Rollouts

So stehen wir bei der Einführung neuer Versionen der Anwendung unweigerlich vor dem Problem der Ausfallzeiten, das während des Wechsels des Produktionsservers entsteht. Der Traffic von der alten Version der Anwendung zur neuen kann nicht sofort umgeschaltet werden: Zuerst müssen wir sicherstellen, dass die neue Version nicht nur erfolgreich bereitgestellt, sondern auch „aufgewärmt“ (d. h. vollständig bereit zur Bearbeitung von Anfragen) ist.

Best Practices für Continuous Delivery mit Docker (Überblick und Video)
In der Folge werden beide Versionen der Anwendung (alte und neue) eine Zeit lang gleichzeitig laufen. Dies führt automatisch zu Konflikten um gemeinsame Ressourcen: Netzwerk, Dateisystem, IPC usw. Mit Docker lässt sich dieses Problem leicht lösen, indem unterschiedliche Versionen der Anwendung in separaten Containern ausgeführt werden, für die eine Isolation der Ressourcen auf einem einzigen Host (Server/virtuelle Maschine) garantiert ist. Natürlich kann man auch ohne vollständige Isolation etwas tricksen, aber wenn es ein praktisches und nützliches Werkzeug gibt, sollte man es auch nutzen.

Containerisierung bietet viele weitere Vorteile beim Deploy. Jede Anwendung ist abhängig von einer bestimmten Version (oder Versionsbereich) des Interpreters., vorhandene Module/Erweiterungen usw. sowie deren Versionen. Dies betrifft nicht nur die unmittelbare Ausführungsumgebung, sondern auch die gesamte Umgebung einschließlich Betriebssoftware und deren Versionen (bis hin zur verwendeten Linux-Distribution). Da Container nicht nur den Anwendungscode, sondern auch die benötigte system- und anwendungsseitige Software in den entsprechenden Versionen enthalten, können Probleme mit Abhängigkeiten vergessen werden.

Lassen Sie uns zusammenfassen das Hauptmuster der Bereitstellung neuer Versionen unter Berücksichtigung der genannten Faktoren:

  1. Zunächst läuft die alte Version der Anwendung im ersten Container.
  2. Dann wird die neue Version bereitgestellt und im zweiten Container «aufgewärmt». Interessanterweise kann diese neue Version nicht nur den aktualisierten Anwendungscode, sondern auch alle seine Abhängigkeiten sowie systemische Komponenten (z.B. eine neue Version von OpenSSL oder des gesamten Distributionspakets) beinhalten.
  3. Sobald die neue Version vollständig bereit ist, um Anfragen zu bedienen, wird der Datenverkehr vom ersten Container auf den zweiten umgeschaltet.
  4. Jetzt kann die alte Version gestoppt werden.

Dieser Ansatz zur Bereitstellung verschiedener Versionen der Anwendung in separaten Containern bietet einen weiteren Vorteil — eine schnelle Rückkehr zur alten Version (es genügt, den Datenverkehr auf den entsprechenden Container umzuleiten).

Best Practices für Continuous Delivery mit Docker (Überblick und Video)
Die endgültige erste Empfehlung lautet so, dass selbst der Kapitän nichts daran auszusetzen hat: «[bei der Organisation von Continuous Delivery mit Docker] Verwenden Sie Docker [und verstehen Sie, was das bedeutet]». Denken Sie daran, dass dies keine „silberne Kugel“ ist, die alle Probleme löst, sondern ein Werkzeug, das eine hervorragende Grundlage bietet.

Reproduzierbarkeit

Unter „Reproduzierbarkeit“ verstehen wir eine generelle Reihe von Problemen, mit denen man bei der Nutzung von Anwendungen konfrontiert wird. Es geht um solche Fälle:

  • Szenarien, die vom Qualitätssicherungsteam auf der Staging-Umgebung getestet wurden, sollten sich genau im Produktionsumfeld reproduzieren lassen.
  • Anwendungen werden auf Servern veröffentlicht, die Pakete von verschiedenen Spiegeln der Repositories beziehen können (über die Zeit hinweg werden sie aktualisiert, und damit auch die Versionen der installierten Anwendungen).
  • „Bei mir lokal funktioniert alles!“ (... und Entwickler dürfen nicht in die Produktion.)
  • Es muss etwas in der alten (archivierten) Version überprüft werden.

Die Grundidee besteht darin, dass die verwendeten Umgebungen vollständig übereinstimmen müssen (und der menschliche Faktor ausgeschlossen ist). Wie kann man also Reproduzierbarkeit gewährleisten? Docker-Images erstellen basierend auf dem Code aus Git und diese dann für verschiedene Aufgaben verwenden: auf Testumgebungen, in der Produktion, auf den lokalen Rechnern der Entwickler... Dabei ist es wichtig, die Aktionen zu minimieren, die nach dem Erstellen des Images ausgeführt werden: je einfacher, desto geringer die Wahrscheinlichkeit von Fehlern.

Infrastruktur ist Code

Wenn die Anforderungen an die Infrastruktur (Vorhandensein von Server-Software, deren Versionen usw.) nicht formalisiert und nicht "programmiert" werden, kann die Bereitstellung eines jeden Updates der Anwendung ernste Folgen haben. Wenn Sie beispielsweise in der Staging-Umgebung bereits auf PHP 7.0 umgestiegen sind und den Code entsprechend angepasst haben, wird das Auftauchen in der Produktion mit einer veralteten PHP-Version (5.5) mit Sicherheit jemanden überraschen. Auch wenn Sie große Versionsänderungen des Interpreters nicht übersehen, "liegt der Teufel im Detail": Überraschungen können in minoren Updates jeder Abhängigkeit verborgen sein.

Der Ansatz zur Lösung dieses Problems ist bekannt als IaC (Infrastructure as Code, "Infrastruktur als Code") und beinhaltet die Speicherung der Infrastrukturanforderungen zusammen mit dem Anwendungscode. Bei dessen Verwendung können Entwickler und DevOps-Experten mit einem einzigen Git-Repository der Anwendung arbeiten, jedoch an verschiedenen Teilen davon. Aus diesem Code wird in Git ein Docker-Image erstellt, in dem die Anwendung unter Berücksichtigung aller spezifischen Infrastrukturmerkmale bereitgestellt wird. Mit anderen Worten, die Skripte (Regeln) zum Erstellen von Images sollten in demselben Repository wie die Quellcodes liegen und gemeinsam zusammengeführt werden.

Best Practices für Continuous Delivery mit Docker (Überblick und Video)

Im Falle einer mehrschichtigen Anwendungsarchitektur – zum Beispiel, wenn nginx vor einer bereits innerhalb eines Docker-Containers laufenden Anwendung steht – sollten Docker-Images aus dem Code in Git für jede Schicht erstellt werden. Dann enthält das erste Image die Anwendung mit dem Interpreter und anderen "naheliegenden" Abhängigkeiten, während das zweite das darüber liegende nginx enthält.

Docker-Images, Verbindung zu Git

Alle Docker-Images, die aus Git erstellt werden, unterteilen wir in zwei Kategorien: temporäre und Release-Images. Temporäre Images Tags werden nach dem Branch-Namen in Git vergeben, können durch einen neuen Commit überschrieben werden und sind nur für die Vorschau gedacht (nicht für die Produktion). Das ist ihr entscheidender Unterschied zu Releases: Man weiß nie, welcher spezifische Commit enthalten ist.

Es ist sinnvoll, temporäre Images zu erstellen: den Master-Branch (der automatisch auf eine separate Umgebung ausgerollt werden kann, um die aktuelle Version des Masters ständig zu sehen), Release-Branches und Branches für spezifische Neuerungen.

Best Practices für Continuous Delivery mit Docker (Überblick und Video)
Nachdem der Vorschau-Status der temporären Images den Bedarf an einer Überführung in die Produktion erreicht, setzen die Entwickler ein bestimmtes Tag. Basierend auf diesem Tag wird automatisch ein Release-Image (diesem Tag entspricht ein Tag in Git) erstellt und auf die Staging-Umgebung ausgerollt. Nach einer erfolgreichen Überprüfung durch die Qualitätssicherung gelangt es in die Produktion.

dapp

Alle genannten Schritte (Rollout, Image-Erstellung, anschließende Wartung) können selbst mit Bash-Skripten und anderen "einfachen" Mitteln durchgeführt werden. Doch wenn man es so angeht, führt das irgendwann zu großer Komplexität und schlechter Handhabbarkeit. Vor diesem Hintergrund haben wir unsere spezialisierte Workflow-Utility zur Erstellung von CI/CD entwickelt — dapp.

Der Quellcode ist in Ruby geschrieben, Open Source und veröffentlicht auf GitHub. Leider ist die Dokumentation im Moment das schwächste Glied des Tools, aber wir arbeiten daran. Außerdem werden wir in Zukunft noch öfter über dapp berichten, da wir wirklich begeistert sind, seine Möglichkeiten mit der interessierten Community zu teilen. Bis dahin senden Sie uns bitte Ihre Issues und Pull Requests und/oder verfolgen Sie die Entwicklung des Projekts auf GitHub.

Aktualisiert am 13. August 2019: Derzeit wurde das Projekt dapp in werf, umbenannt, der Code wurde vollständig in Go neu geschrieben und die Dokumentation erheblich verbessert.

Kubernetes

Ein weiteres fertiges Open Source-Tool, das bereits in Fachkreisen erhebliche Anerkennung gefunden hat, ist Kubernetes, ein Cluster zur Verwaltung von Docker. Die Verwendung in der Umsetzung von Projekten, die auf Docker basieren, geht über den Rahmen dieser Präsentation hinaus, daher beschränkt sich der Vortrag auf eine Übersicht einiger interessanter Möglichkeiten.

Für die Bereitstellung bietet Kubernetes:

  • readiness probe – eine Überprüfung der Einsatzbereitschaft der neuen Version der Anwendung (um den Verkehr auf diese umzuleiten);
  • rolling update – schrittweises Aktualisieren des Images im Cluster von Containern (deaktivieren, aktualisieren, für den Start vorbereiten, Verkehr umschalten);
  • synchronous update – Aktualisierung des Images im Cluster mit einem anderen Ansatz: zuerst auf der Hälfte der Container, dann auf den restlichen;
  • canary releases – Einführung eines neuen Images auf einer begrenzten (geringen) Anzahl von Containern zur Überwachung von Anomalien.

Da Continuous Delivery nicht nur die Veröffentlichung einer neuen Version umfasst, bietet Kubernetes eine Reihe von Möglichkeiten für die nachfolgende Pflege der Infrastruktur: integrierte Überwachung und Protokollierung für alle Container, automatische Skalierung und vieles mehr. All dies funktioniert bereits und wartet nur auf eine sinnvolle Integration in Ihre Prozesse.

Abschließende Empfehlungen

  1. Nutzen Sie Docker.
  2. Erstellen Sie Docker-Images der Anwendung für alle Anforderungen.
  3. Befolgen Sie das Prinzip „Infrastruktur ist Code“.
  4. Verbinden Sie Git mit Docker.
  5. Regeln Sie den Rollout-Prozess.
  6. Nutzen Sie eine vorgefertigte Plattform (Kubernetes oder eine andere).

Videos und Folien

Video des Vortrags (ca. eine Stunde) veröffentlicht auf YouTube (der Vortrag beginnt direkt ab der 5. Minute — die Wiedergabe beginnt an diesem Punkt über den Link).

Präsentation des Vortrags:

P.S.

Weitere Vorträge zu diesem Thema in unserem Blog:

Quelle: habr.com

Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster