Blog

Kontinuierliche Bereitstellung von Docker Images

Cristiana

Aktualisiert Oktober 22, 2025
6 Minuten
Unser Kunde wollte die Markteinführungszeit für die neue Version seiner Anwendung drastisch verkürzen. Große vierteljährliche Releases sollten durch kleine Änderungen ersetzt werden, die mehrmals am Tag in die Produktion eingespielt werden können. Im Folgenden erklären wir Ihnen, wie Sie Docker und Ansible zur Unterstützung dieser Strategie einsetzen können, oder, um es mit den Worten unseres Kunden zu sagen, wie Sie "Software in Gedankengeschwindigkeit entwickeln". Um die Entwicklung in der Geschwindigkeit des Denkens zu ermöglichen, benötigten wir Folgendes:
  1. Eine Plattform zur Bereitstellung von Docker-Images auf
  2. Protokollierung, Überwachung und Alarmierung einrichten
  3. Versionierung von Anwendungen
  4. Einsatz ohne Ausfallzeiten
  5. Sicherheit
Im Folgenden werden wir jede einzelne Eigenschaft erläutern. Plattform Unsere Docker-Images laufen auf einem Ubuntu-Host, weil wir eine unterstützte Linux-Version benötigten, die gut bekannt ist. In unserem Fall installieren wir das Betriebssystem über ein Image und führen alle andere Software in einem Container aus. Jeder Docker-Container beherbergt genau einen Prozess, so dass es leicht zu erkennen ist, was ein Container tun soll. Beispiele für Container sind:
  • Java VMs zur Ausführung unserer Scala-Dienste
  • HA Proxy
  • Syslog-ng
  • Ein Dienstprogramm zum Rotieren von Protokolldateien
  • Und sogar eine Oracle-Datenbank (nicht für die Abnahme und die Produktion, da wir bei dieser Einrichtung Probleme mit dem Support erwarteten, aber für die Entwicklung funktioniert sie gut)
Die meiste Software, die in Containern läuft, wird mit einem Bash-Skript gestartet, aber seit kurzem experimentieren wir auch mit Go, so dass ein Container möglicherweise nicht mehr als eine einzige ausführbare Datei benötigt. Protokollierung, Überwachung und Alarmierung Um Zeit zu sparen, haben wir beschlossen, den Entwicklungsaufwand für die Überwachung und Alarmierung so weit wie möglich auf gehostete Dienste zu verlagern. Dies führte zu Verträgen mit Loggly zur Speicherung von Anwendungsprotokolldateien, Librato zur Erfassung von Systemmetriken und OpsGenie zur Alarmierung von Ops auf der Grundlage von in Loggly definierten Regeln. Die Protokolldateien werden über das Syslog-NG-Plugin an Loggly übermittelt. Da unsere Anwendung bereits auf statsd basierte, haben wir uns entschlossen, einen statsd-Emulator zu erstellen, um Metriken an Librato zu übermitteln, damit wir den Code nicht umschreiben müssen. Das kann sich in Zukunft ändern, wenn wir die Zeit dafür finden, aber im Moment funktioniert es gut. Wir verwenden die Docker stats API, um Informationen auf Containerebene zu sammeln. Versionierung von Anwendungen In der Java-Welt wäre die zu liefernde Datei eine jar-Datei, die in einem Repository wie Artifactory oder Nexus veröffentlicht wird. Dies ist auch bei der Arbeit mit Docker möglich, aber es ist sinnvoller, Docker-Images als Deliverables zu verwenden. Die Images enthalten alles, was zum Ausführen des Dienstes benötigt wird, einschließlich der jar-Datei. Wie die jar-Dateien werden auch die Docker-Images veröffentlicht, in diesem Fall in der Docker-Registry. Wir haben mit Docker Hub online begonnen, aber wir wollten eine schnellere Bereitstellung und mehr Kontrolle darüber, wer auf die Images zugreifen kann, also haben wir unsere private Docker-Registry vor Ort eingeführt. Das funktioniert hervorragend und wir stellen täglich etwa 30 bis 50 Images bereit. Das Versions-Tag, das wir für einen Container verwenden, ist das Datum und die Uhrzeit, zu der er erstellt wurde. Wenn der Build beginnt, versehen wir die Quellen in Git mit einem Namen, der auf dem Datum und der Uhrzeit basiert, z.B. 20150619_1504. Komponenten, die den Test bestanden haben, werden auf der Grundlage einer Textdatei, einer Komposition, die alle Komponenten auflistet, die Teil einer Version sein sollen, zu einer Version zusammengestellt. Die Komposition ist mit einem c_-Präfix und einem Datums-/Zeitstempel versehen und wird in der Integrationstestumgebung bereitgestellt. Dann wird ein neuer Test durchgeführt, um herauszufinden, ob die Zusammenstellung noch funktioniert. Wenn ja, wird die Komposition mit einem neuen rc-Tag versehen, in unserem Beispiel rc_20150619_1504. Releases, die den Integrationstest bestehen, werden für die Abnahme und schließlich für die Produktion bereitgestellt, allerdings nicht automatisch. Wir haben uns dafür entschieden, die Bereitstellung zu einer Verwaltungsentscheidung zu machen, die von einem Jenkins-Job ausgeführt wird. Diese Strategie ermöglicht es uns, eine Version der Software aus dem Quellcode neu zu erstellen, indem wir die Tags, aus denen eine Version besteht, auschecken und neu erstellen, oder aus dem Docker-Repository, indem wir alle Versionen der Komponenten so bereitstellen, wie sie in der Kompositionsdatei aufgeführt sind. Komponenten von Drittanbietern werden mit der Versionsnummer des Anbieters gekennzeichnet. Bereitstellung ohne Ausfallzeiten Um eine hohe Verfügbarkeit zu erreichen, haben wir uns für Ansible entschieden, um einen Docker-Container auf der Grundlage der oben erwähnten Kompositionsdatei bereitzustellen. Ansible stellt eine Verbindung zu einem Host her und verwendet dann den Docker-Befehl, um Folgendes zu tun:
  1. Prüfen Sie, ob sich die laufende Containerversion von der Version unterscheidet, die wir bereitstellen möchten
  2. Wenn die Version unterschiedlich ist, beenden Sie den alten Container und starten Sie den neuen
  3. Wenn die Version dieselbe ist, tun Sie nichts.
Das spart eine Menge Zeit, denn Ansible ändert nur die Container, die geändert werden müssen, und lässt alle anderen in Ruhe. Mit Ansible können wir auch Zero Downtime Deployment implementieren:
  1. Schalten Sie zunächst den Health Container auf einem Knoten aus
  2. Dies veranlasst den Load Balancer, den Knoten aus der Liste der aktiven Knoten zu entfernen
  3. Aktualisieren Sie den ersten Knoten
  4. Starten Sie den Gesundheitscontainer neu
  5. Führen Sie das Update-Skript parallel auf allen anderen Knoten aus.
Sicherheit Das Problem mit der Docker-API ist, dass Sie entweder in oder out sind und es keine Stufen dazwischen gibt. Das bedeutet z.B., dass Sie, wenn Sie den Docker-Socket zu einem Container hinzufügen, um die Docker-Statistiken einzusehen, auch das Starten und Stoppen von Images erlauben. Oder wenn Sie den Zugriff auf die ausführbare Datei von Docker erlauben, gewähren Sie auch Zugriff auf Konfigurationsinformationen wie Passwörter, die dem Container bei der Bereitstellung übergeben wurden. Um dieses Problem zu lösen, haben wir einen Docker-Wrapper erstellt. Dieser Wrapper verbietet den Start von privilegierten Containern und verbirgt einige Informationen, die von Docker inspect zurückgegeben werden. Eine einfache Sicherheitsregel besagt, dass Software, die nicht installiert ist oder nicht läuft, auch nicht ausgenutzt werden kann. Auf Docker-Images angewandt bedeutet dies, dass wir alles, was wir nicht brauchen, entfernt und das Image so klein wie möglich gemacht haben. Die Teams erweitern das Basis-Linux-Image nur durch Hinzufügen der jar-Datei für ihre Anwendung. Kürzlich haben wir begonnen, mit Go zu experimentieren, um Dienstprogramme auszuführen, da eine ausführbare Go-Datei keine zusätzliche Software benötigt, um zu laufen. Wir testen auch kleinere Container-Images. Denken Sie schließlich daran, nicht als root zu laufen und sorgfältig zu überlegen, welche Dateisysteme zwischen Container und Host freigegeben werden sollen. Zusammenfassung Zusammenfassend lässt sich sagen, dass wir einen Weg gefunden haben, Software in Containern zu verpacken, und zwar sowohl Standard-Dienstprogramme als auch Scala-Komponenten, eine mit Tags versehene und versionierte Komposition zu erstellen, die getestet wird und als Einheit von einer Umgebung zur nächsten wandert. Mithilfe von Ansible haben wir die Bereitstellung neuer Versionen orchestriert und dabei immer mindestens einen Server in Betrieb gehalten. In Zukunft wollen wir die Größe der Images verringern, indem wir das Basisbetriebssystem entfernen und mehr Dienstprogramme als Go-Container bereitstellen. Außerdem werden wir die Arbeit an unserem Sicherheits-Wrapper fortsetzen und planen, Consul zu untersuchen, um unsere hausgemachte Service-Registry zu ersetzen. Dieser Blog basiert auf einem Vortrag von Armin ÄŒoralić auf der XebiCon 2015. Sehen Sie sich Armins Präsentation hier an.

Verfasst von

Cristiana

Some bio goes here

Contact

Let’s discuss how we can support your journey.