Tipps für Git und Bamboo im Continuous-Delivery-Prozess (Teil 1)

Die verteilte Versionskontrolle Git und das Continuous-Delivery-Vorgehen bilden gemeinsam einen mächtigen Prozess, um Software sicher zu entwickeln und kontinuierlich auszuliefern. In diesem zweiteiligen Artikel wollen wir diskutieren, wie Builds im CI-Server Bamboo und Git-Repositories in Bitbucket möglichst reibungslos zusammenspielen können.

Große Dateien im Repository vermeiden

Eine Regel bei der Arbeit mit Git lautet, keine großen Dateien ins Repository zu packen, also Binaries, Medien-Dateien, archivierte Artefakte usw. Der Grund dafür ist, dass eine hinzugefügte Datei für immer in der Historie des Repositorys bleibt. Wann immer jemand das Repo klont, wird auch die große Datei mitkopiert.

Eine Datei wieder aus einem Repo rauszubekommen, ist heikel – eine schwere Operation an der Code-Basis. Und dieser chirurgische Eingriff verändert die gesamte Historie des Repositorys. Wir haben also kein klares Bild mehr davon, wenn welche Änderungen gemacht wurden. Das sind gute Gründe, große Dateien grundsätzlich zu vermeiden.

Mit jedem Build muss unser CI-Server unser Repository ins Arbeits-Build-Verzeichnis kopieren. Und wenn das Repo mit großen Artefakten vollgestopft ist, verlangsamt dies den Prozess und verlängert die Wartezeit auf die Build-Ergebnisse.

So weit, so gut. Aber was ist, wenn der Build auf Binaries aus anderen Projekten oder großen Artefakten basiert? Diese Situation tritt häufig auf, und die Frage lautet immer: Wie lässt sich das effektiv handhaben?

Ein externes Speichersystem wie Artifactory (für das es ein entsprechendes Bamboo-Plugin gibt), Nexus oder Archiva kann bei Artefakten helfen, die von unserem oder von uns nahestehenden Teams generiert worden sind. Die Dateien, die wir benötigen, können zu Beginn des Builds in das Build-Verzeichnis gezogen werden – wie bei 3rd-Party-Bibliotheken, die wir via Maven oder Gradle holen.

Wenn die Artefakte sich häufig verändern, sollten wir der Versuchung widerstehen, unsere großen Dateien jede Nacht mit dem Build-Server zu syncen. Sonst stehen wir zwischen den nächtlichen Syncs am Ende mit veralteten Versionen der Artefakte da. Außerdem brauchen Entwickler diese Dateien für Builds sowieso auf ihren lokalen Workstations. Der sauberste Weg besteht darin, den Artefakt-Download einfach zum Bestandteil des Builds zu machen.

Mit flachen Kopien arbeiten

Immer, wenn ein Build ausgeführt wird, klont unser Build-Server unser Repository in das aktuelle Arbeitsverzeichnis. Wir haben schon besprochen, dass Git beim Klonen per Voreinstellung die gesamte Historie klont. Mit der Zeit dauert diese Operation naturgemäß länger und länger, es sei denn wir aktivieren in Bamboo flaches Kopieren (Shallow Cloning). Damit wird nur der aktuelle Snapshot des Repos heruntergezogen. Das kann sehr hilfreich sein, um Build-Zeiten zu verkürzen, speziell wenn wir mit großen und/oder alten Repos arbeiten.

Aber nehmen wir an, dass unser Build die komplette Historie erfordert – wenn beispielsweise ein Schritt im Build die Versionsnummer in unserem POM aktualisiert oder wenn wir mit jedem Build zwei Branches mergen. In beiden Fällen muss Bamboo die Änderungen zurück zum Repository pushen.

Git bietet die Möglichkeit, einfache Änderungen an Dateien (wie die Aktualisierung einer Versionsnummer) zu pushen, ohne dass die gesamte Historie vorliegt. Aber das Mergen erfordert immer noch die Historie des Repos, denn Git muss zurückschauen und den gemeinsamen Vorfahren der beiden Branches finden – und das wird zu einem Problem, wenn unser Build flache Kopien nutzt. Damit kommen wir zum dritten Tipp.

Repo-Caching nutzen

Das Caching beschleunigt das Klonen ebenfalls, und Bamboo tut das tatsächlich standardmäßig. Wir dürfen aber nicht vergessen, dass das Repo-Caching nur von Vorteil ist, wenn wir Agents nutzen, die von Build zu Build persistent sind. Wenn wir jedes Mal, wenn ein Build läuft, Build-Agents auf EC2 oder einem anderen Cloud-Provider erstellen und wieder abreißen, hat das Caching keine Auswirkungen, denn wir arbeiten mit einem leeren Build-Verzeichnis und müssen sowieso jedes Mal eine komplette Kopie des Repos beziehen.

Flache Kopien plus Repo-Caching, aufgesplittet nach persistenten und elastischen Agents, führt zu unterschiedlichen interessanten Szenarien, die hier aufgeführt sind:

Persistente Agents Elastische Agents
Keine Änderungen Emoticon check Flache Kopien
Emoticon check Repo-Caching
Emoticon check Flache Kopien
Emoticon error Repo-Caching
Einfache Änderungen Emoticon check Flache Kopien
Emoticon check Repo-Caching
Emoticon check Flache Kopien
Emoticon error Repo-Caching
Auto-Merging Emoticon error Flache Kopien
Emoticon check Repo-Caching
Emoticon error Flache Kopien
Emoticon error Repo-Caching

Im zweiten Teil des Artikels folgen zwei weitere Tipps, um möglichst effizient mit Git und Bamboo zu arbeiten.

Weiterführende Infos

Continuous Delivery in der Praxis: Deployment auf Knopfdruck und Release-Verwaltung mit Bamboo
Individuelle Software-Entwicklung: Workflows, Branching-Modelle und Continuous Delivery
Bamboo: Continuous Integration auf Enterprise-Skala
Continuous Deployment: Software-Entwicklung nach dem Lean-Startup-Konzept