
Teilen Sie:
Yonatan war an einigen großartigen Projekten in der Akademie und in der Industrie beteiligt - von C/C++ über Matlab bis hin zu PHP und Javascript. Früher war er CTO bei Webiks und Softwarearchitekt bei WalkMe. Derzeit ist er Softwarearchitekt bei Vonage und egghead-Dozent.
Einrichten von CI/CD mit Github-Aktionen
Lesedauer: 7 Minuten
Kontinuierliche Integration und kontinuierliches Deployment sind ein Muss für Unternehmen, die skalieren und qualitativ hochwertige Software mit hoher Geschwindigkeit bereitstellen möchten. Dieser Artikel führt Sie durch den Prozess der Verwendung von Github-Aktionen zur Erstellung von CI/CD-Abläufen.
Was ist CI/CD?
CI/CD ist ein Prozess, der die Entwicklung mit der Bereitstellung durch einen automatisierten Integrationsprozess verbindet. Die Idee dahinter ist, dass Entwickler Codeänderungen als einzigen Schritt für die Bereitstellung dieser Änderungen vornehmen können.
Die CI-Pipeline ermöglicht eine reibungslose Teamarbeit, indem sie Standards automatisiert und die Softwarequalität sicherstellt. Tools wie Linters und automatisierte Tests liefern Feedback, auf dessen Grundlage die Änderungen in den Hauptzweig integriert werden können. Diese integrierten Änderungen werden schließlich an die Endbenutzer (Produktion) ausgeliefert.
Die CD-Pipeline erhält den getesteten und genehmigten Code. Sie bestätigt, dass alle benötigten Artefakte an der richtigen Stelle bereitgestellt werden. Einige Beispiele: Bereitstellung einer Webanwendung auf einem Server, Veröffentlichung einer Bibliothek in einem Paketmanager-Repository oder Veröffentlichung einer mobilen App im App Store.
Die Automatisierung dieser Prozesse gewährleistet zwei wichtige Dinge: Der Prozess läuft schnell ab, und er ist weniger fehleranfällig.
Möchten Sie erfahren, wie Teams ihre Entwicklungs-, Integrations- und Bereitstellungsprozesse beschleunigen können? Sind Sie bereit, eine neue CI/CD-Pipeline aufzubauen? Los geht's!
Ein grundlegender CI/CD-Ablauf
Verschieben Sie eine Änderung in einen Funktionszweig.
Erstellen Sie einen Pull Request für diese Änderung
Der Informatiker schaltet sich ein und führt die folgenden Schritte aus:
Lint, Test, Build
Sobald die CI abgeschlossen ist, wird der PR als gültig markiert und ein Code-Review-Prozess beginnt
Wenn der PR genehmigt ist, wird der Code in den Master eingebunden.
Nach der Zusammenführung setzt der CD-Prozess ein:
Lint, Test, Bump Version, Bereitstellung
Wir werden ein CI/CD für eine einfache Anwendung erstellen, die Sie hier klonen können hier.
Hinzufügen eines Github-Workflows zu Ihrem Projekt
Erstellen Sie einen Ordner .github/workflows. In diesem Ordner werden wir unsere Github-Aktionen hinzufügen. Die Aktionen werden in yaml-Dateien in einer recht einfachen Struktur festgelegt, die aus drei Teilen besteht:
Name: der Name des Arbeitsablaufs, in unserem Fall Test and Build
auf: der Auslöser, der den Workflow startet, wenn die Bedingungen erfüllt sind. In unserem Fall wollen wir, dass der Workflow läuft, wenn ein Pull Request erstellt und veröffentlicht wird. Beispiele für andere Auslöser werden wir später im Tutorial sehen.
Aufträge: die eigentlichen Befehle, die im Ablauf ausgeführt werden. Dies können mehrere Aufträge sein, die parallel laufen, oder Aufträge, die voneinander abhängig sind. In diesem Beispiel gibt es einen Auftrag namens build-testder nur unter dem Betriebssystem ubuntu-latest läuft.
name: Test and Build
on:
pull_request:
branches:
- main
jobs:
build-test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Setup NodeJS 14
uses: actions/setup-node@v1
with:
node-version: 14
- name: Install yarn
run: npm install -g yarn
- name: Install dependencies
run: yarn install
- name: Test
run: yarn testDer erste Schritt ist das Auschecken des Repositorys mit einer vorgefertigten Aktion actions/checkout@v2 aus dem Marktplatz für Aktionen. Wir übergeben die fetch-depth: 0 Variable mit der mit Eigenschaft, die dem Checkout-Prozess mitteilt, dass er das Repository mit seiner gesamten Historie abrufen soll. Die folgenden Schritte beziehen sich auf die Installation und die Ausführung von Bash-Befehlen.
Aufbau eines kontinuierlichen Integrationsworkflows
Auslösen des Ablaufs mit einem Pull Request
Starten Sie die Maschine
Installieren Sie nodeJs auf dem Rechner
Prüfen Sie das Repository
Abhängigkeiten installieren
Test, Lint, Build
Anzeige der Ergebnisse auf der PR-Seite
Erste Schritte
Wenn Sie das Repository noch nicht geforkt und geklont haben, tun Sie das jetzt und erstellen Sie einen Zweig "add-ci".
Erstellen Sie eine Datei
.github/workflows/ci.ymlund kopieren Sie den Inhalt von dieser Datei in die neue Datei.Commitieren Sie die Änderungen und schieben Sie sie in den neuen Zweig. Öffnen Sie eine Pull-Anfrage vom neuen Zweig zum Hauptzweig.
Wenn Sie sich den Pull-Request auf Github ansehen, sollten Sie sehen, dass die Tests laufen:

Sie werden feststellen, dass Github bereits den Namen des Workflows, den Namen des Auftrags und den Auslöser kennt. Nach der Fertigstellung sollte er wie folgt aussehen:

Können Sie ein Problem in diesem Prozess erkennen?
Hinzufügen von Zusammenführungsregeln
Das erste Problem ist, dass die Pull-Anfrage zusammenführen bereits während des CI-Prozesses verfügbar war, obwohl wir die Zusammenführung erst dann ermöglichen wollen, wenn alle erforderlichen Arbeitsabläufe abgeschlossen sind.
Wir können dies in den Repo-Einstellungen beheben, indem wir zu gehen: Einstellungen>Branchen>Regel hinzufügen

Hier wählen wir Statusprüfungen vor dem Zusammenführen bestehen lassen und überprüfen alles darunter. Sie sehen alle Arbeitsabläufe, die erforderlich sind, um die Zusammenführung zu ermöglichen - in unserem Fall haben wir nur build-test.

Für Muster für Zweignamen einfügen main ein und erstellen Sie die Regel. Und wenn Sie zurück zur Pull-Request-Seite gehen, werden Sie sehen, dass keine Pull-Requests zusammengeführt werden können, bevor die Tests bestanden sind, es sei denn natürlich, Sie haben Admin-Rechte.

Zusammenführung nach Codeüberprüfung
Bevor wir weitermachen, müssen wir auch entscheiden, wie wir die Weitergabe von Pull Requests handhaben. Es gibt drei Hauptansätze:
Erlauben Sie jedem die Zusammenführung, sobald die Tests bestanden sind
Automatisches Zusammenführen nach bestandenen Tests
Eine Überprüfung des Codes ist für die Zusammenführung erforderlich.
Wir entscheiden uns für die erste Option, die am häufigsten vorkommt und die wir ändern können, indem wir die gerade erstellte Verzweigungsregel bearbeiten. Am Anfang der Liste wählen Sie Pull-Anfragen vor der Zusammenführung überprüfen lassen und klicken Sie auf Speichern.
Das war's mit der kontinuierlichen Integration! Jetzt werden alle neuen Pull Requests getestet und geprüft, bevor sie in die Hauptversion eingebunden werden! Der nächste Schritt ist die Bereitstellung.
Aufbau eines kontinuierlichen Verteilungsworkflows
Das Deployment kann vom Hochladen statischer Dateien auf Github über die Veröffentlichung von npm-Paketen bis hin zum Deployment eines ganzen Microservices-Netzes alles sein. Hier ist der Prozess, den wir für unsere Anwendung befolgen werden, sobald der Code in das Haupt-Repository eingebunden ist:
Abhängigkeiten installieren
Test
Bump-Version
Bauen Sie
Markieren Sie die Freigabe
Bei npm veröffentlichen
Bereitstellen der Demo-Anwendung
Schauen wir uns die verschiedenen Teile der yaml-Datei an, die die Aktionen handhabt:
Der Auslöser
Dies sind die Bedingungen, unter denen unser Bereitstellungscode ausgeführt wird. Er wird ausgelöst, wenn eine Pull-Anfrage geschlossen und zusammengeführt wurde.
name: Test, Build and Deploy
on:
pull_request:
types: [closed]
jobs:
build-test-release:
if: github.event.action == 'closed' && github.event.pull_request.merged == true
runs-on: ubuntu-latest
Berechtigungen für Git-Aktionen
Im Checkout-Schritt fügen wir eine zusätzliche Zeile ein, die in der vorherigen yaml-Datei nicht vorhanden war:
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
token: ${{ secrets.CI_REPOSITORY_ACCESS_TOKEN }}Wir müssen das Token explizit festlegen, damit wir Dinge tun können, für die das Standard-Token, secrets.GITHUB_TOKENkeine Berechtigungen hat. In unserem Fall wollen wir eine Änderung ohne eine Codeüberprüfung an main weitergeben, also brauchen wir ein Token mit Admin-Rechten. Wir legen dieses Token unter Einstellungen -> Geheimnisse fest.
Paketversionen anheben
Dieser Schritt ist von Projekt zu Projekt unterschiedlich. Es geht darum, die Version des Pakets, das Sie im Paket-Repository veröffentlichen wollen, zu erhöhen. Dazu gehen wir alle Bibliotheken durch, die sich in diesem Zweig geändert haben, und erhöhen ihre NPM-Version:
- name: Raise version of affected libraries
run: |
LATEST_TAG=$(git tag -l "v*" --sort=-version:refname | head -n 1)
LIBS=$(yarn nx affected:libs --base=$LATEST_TAG --head=HEAD --plain | awk 'NR > 2 && $1 != "Done" { print $1 }')
for LIBRARY in $LIBS
do
cd ./libs/$LIBRARY
npm version minor --no-git-tag-version --no-push
echo "Bumping $LIBRARY"
cd ..
cd ..
done
npm version minor --no-git-tag-version --no-push
Beachten Sie, dass wir NX verwenden, ein Monorepo-Management-Framework, mit dem sich Builds und Entwicklung deutlich beschleunigen lassen. Wir verwenden das affected Funktion, die uns sagt, welche Bibliotheken von der PR "betroffen" waren.
Bauen Sie
Der Erstellungsprozess verwendet die affected Funktion ebenfalls. Er baut die geänderten Bibliotheken, die sich vom Hauptzweig aus geändert haben, mit Produktionsvorgaben:
- name: Build components
run: yarn nx affected:build --prod --with-deps --base=main Markieren Sie die Freigabe
Die Freischaltung erfolgt in zwei Schritten:
Die erste, get-npm-versionverwendet eine Aktion des Marktplatzes, die die Version des Hauptpakets extrahiert. Der zweite Schritt überträgt die Änderungen aus dem oben genannten Raise version Schritt vorgenommenen Änderungen, erstellt ein Tag mit der Version aus der neuen package.json und überträgt die Änderung.
Erinnern Sie sich an das CI_REPOSITORY_ACCESS_TOKEN Geheimnis? Hier kommt es ins Spiel. Da wir das Zusammenführen zu Master ohne eine Pull-Request-Prüfung verhindern, benötigen wir für diesen Teil ein Admin-Token, das es uns ermöglicht, die Regel zu umgehen und die Änderungen automatisch zu veröffentlichen.
- name: get-npm-version
id: package-version
uses: martinbeentjes/npm-get-version-action@master
- name: Tag the release
run: |
git fetch
git config user.email "unicorn.ci@yonatankra.com"
git config user.name "Unicorn CI"
git add --all
git commit -m "update versions to ${{ steps.package-version.outputs.current-version }}"
git push
- name: Tag release
run: |
git tag -a v${{ steps.package-version.outputs.current-version }} -m "tag release v${{ steps.package-version.outputs.current-version }}"
git push --follow-tags Bereitstellen der Demo-Anwendung
Zum Schluss erstellen wir unsere Anwendung und stellen sie bereit:
- name: Build Demo
run: yarn build:deploy
- name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@3.7.1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BRANCH: gh-pages # The branch the action should deploy to.
FOLDER: dist/apps/unicorn-hunt # The folder the action should deploy.
CLEAN: true # Automatically remove deleted files from the deploy branchDen vollständigen yaml-Code finden Sie hier
Optimieren des CI/CD-Flusses
Caching in Github-Aktionen verwenden
Wenn Sie den CI/CD-Ablauf verfolgt und erstellt haben, werden Sie vielleicht feststellen, dass er eine Weile braucht, um zu laufen. Eine einfache Lösung dafür ist die Verwendung des Cache und die Einsparung von Zeit für die Installation von Abhängigkeiten, was wir auch mit Github-Aktionen tun können.
Die Zwischenspeicherung funktioniert, indem geprüft wird, ob ein Treffer im Cache vorliegt, und wenn dies der Fall ist, wird der Schritt zur Installation der Abhängigkeiten übersprungen. So sieht der Code aus:
- name: Install yarn
run: npm install -g yarn
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn config get cacheFolder)"
- name: Cache yarn dependencies
uses: actions/cache@v2
id: yarn-cache
with:
path: |
${{ steps.yarn-cache-dir-path.outputs.dir }}
**\node_modules
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install dependencies
if: steps.yarn-cache.outputs.cache-hit != 'true'
run: yarn installIm ersten Schritt wird Garn global installiert. Im zweiten Schritt wird der Pfad des Garn-Cache-Ordners ermittelt. Dann verwendet der eigentliche Caching-Schritt die Cache-Aktion und übergibt die Pfade zum Cache (node_modules und den yarn-Cache-Ordner) und gibt ihm einen Cache-Schlüssel durch Hashing der Datei yarn.lock. Wenn wir auf diese Weise eine neue Abhängigkeit installieren oder eine Abhängigkeit aktualisieren, würde dies einen Cache miss. Der letzte Schritt setzt eine Bedingung für den install-dependencies Schritt unter Verwendung des Cache-Treffer Variable, die durch die Cache-Aktion gesetzt wurde.
Modularisierung des Prozesses
Das CI/CD läuft also. Es nutzt den Cache. Vorhin haben wir erwähnt, dass wir unsere beiden Bibliotheken auch in den libs Ordner in npm veröffentlichen. Technisch gesehen können wir einen weiteren Schritt zu unserem CD-Prozess hinzufügen, aber das könnte ihn umständlich und schwer zu pflegen machen.
Stattdessen haben wir den Prozess in separate Workflows aufgeteilt, die durch den CD-Hauptprozess ausgelöst werden. Der CD-Prozess würde dann eine Version erstellen, die die anderen Prozesse auslöst und die Bereitstellung und Veröffentlichung in NPM bewirkt.
Dies ermöglicht nicht nur eine bessere Wartbarkeit, sondern auch eine bessere Fehlerbehandlung. Denn nehmen wir an, die Versionierung war erfolgreich, die Veröffentlichung war erfolgreich, aber die Bereitstellung ist fehlgeschlagen. Dann können wir das Deployment einfach noch einmal ausführen und debuggen, bis es erfolgreich ist.
Den vollständigen Code für die Lösung finden Sie hier.
Zusammenfassung
In diesem Artikel haben wir einen CI/CD-Prozess mit Github-Aktionen aufgebaut.
Wir begannen mit dem Hinzufügen des CI-Prozesses, der die Tests durchführt und unseren Code-Reviewern mitteilt, dass der Pull Request für die Überprüfung bereit ist. Wir haben auch gelernt, wie man das Zusammenführen in einen Zweig blockiert, ohne dass die Tests und die Überprüfung erfolgreich sind. Wir haben uns einen vereinfachten CI-Code angeschaut, aber Sie können weitere Bash-Befehle zur Testphase hinzufügen, oder sogar weitere Schritte wie Linting oder Prettier.
Anschließend haben wir einen CD-Prozess entwickelt, der die Versionierung und das Deployment der Demo durchführt. Wir lernten, wie wir die Installation der Abhängigkeiten zwischenspeichern können, um Zeit zu sparen, und wie wir den CD-Prozess modularisieren können, um mehr Kontrolle und Wartbarkeit zu erhalten.
Es gibt so viel mehr, was man mit Github-Aktionen machen kann. Wir hoffen, dass dieses Tutorial Ihnen den Einstieg in den Aufbau eines CI/CD-Prozesses ermöglicht hat, der für Ihr Team hilfreich und sinnvoll ist.
Teilen Sie:
Yonatan war an einigen großartigen Projekten in der Akademie und in der Industrie beteiligt - von C/C++ über Matlab bis hin zu PHP und Javascript. Früher war er CTO bei Webiks und Softwarearchitekt bei WalkMe. Derzeit ist er Softwarearchitekt bei Vonage und egghead-Dozent.