CI/CD mit GitHub und AWS CodePipeline, Teil 2 Node.JS-App per CLI auf Elastic Beanstalk bereitstellen

Von Dipl. -Ing. Thomas Drilling 6 min Lesedauer

Früher oder später wollen wir einen GitHub-Workflow für unsere Node.js-App einrichten. Vorher schauen wir uns aber an, wie sich eine Beanstalk-App über die AWS- bzw. die Elastic-Beanstalk-Kommandozeile bereitstellen können.

Mit einem Setup-Skript gelingt die EB-CLI-Installation am schnellsten.
Mit einem Setup-Skript gelingt die EB-CLI-Installation am schnellsten.
(Bild: Drilling / AWS)

Mit AWS Elastic Beanstalk (EB) lässt sich eine App in einer entsprechenden Laufzeitumgebung bereitstellen. Wie bereits mehrfach beschrieben, erstellt Elastic Beanstalk vollständig verwaltetet „Umgebungen“, die dann wiederrum z. B. ein EC2-Cluster und die zugehörige Infrastruktur verwalten.

Ob Node.js, .NET oder Docker: Der Workflow zum Bereitstellen einer App in einer vorhandenen Elastic-Beanstalk-Umgebung ist – unabhängig von der Laufzeitumgebung – immer derselbe. Im vorherigen Artikel haben wir gezeigt, wie man eine Elastic-Beanstalk-Anwendung über die Weboberfläche der AWS Management Console bereitstellt. Das Bereitstellen neuer Versionen der Anwendung lässt sich dann mit Hilfe von AWS CodePipeline orchestrieren.

Elastic Beanstalk verfügt allerdings auch über eine mächtige Kommandozeile in der Azure CLI. So wird z. B. beim Ausführen von „eb deploy“ die Anwendung komprimiert und in einen S3-Bucket hochgeladen, der dann von Ihrer Elastic-Beanstalk-Umgebung abgerufen wird.

Ist die Runtime beispielsweise Docker, erwartet Beanstalk, eine Docker-Datei im Stammverzeichnis Ihres Projektverzeichnisses zu finden. Ist dies der Fall, erstellt der Service das Image in einer der EC2-Instanzen des EC2-Clusters, bevor es als Container ausgeführt wird. Ist die Laufzeit hingegen Node.js, Java, PHP, Python oder .NET, wird der Code direkt ausgeführt.

Wie können wir das Ganze nun aber per Command Line Interface (CLI) automatisieren und mit einer CI/CD-Pipeline verknüpfen? Zur Nutzung von „eb deploy“ muss das EB CLI installiert und konfiguriert sein. Die Installation ist relativ einfach und in der AWS-Dokumentation gut beschrieben. In Kürze:

Einrichten der EB-CLI.
Einrichten der EB-CLI.
(Bild: Drilling / AWS)

1. Python und Pip installieren

sudo dnf install python
sudo dnf install pip

2. Anschließend die awsebcli installieren, via:

sudo pip install awsebcli --upgrade -–user

Die Option „--upgrade“ sorgt dafür, dass alle bereits installierten Abhängigkeiten aktualisiert werden. Die Option „--user“ weist pip an, das Programm in einem Unterverzeichnis des Benutzerverzeichnisses zu installieren, um Änderungen an vom Betriebssystem verwendeten Bibliotheken zu vermeiden. Treten beim Versuch, die EB-CLI mit pip zu installieren, Probleme auf, lässt sich das Tool auch in einer virtuellen Umgebung installieren. Auf diesem Weg ist es möglich, das Tool und seine Abhängigkeiten zu isolieren, oder eine andere Version von Python zu verwenden.

Die dritte Option zur Installation der EB-CLI besteht darin, sich von https://github.com/aws/aws-elastic-beanstalk-cli-setup ein passendes Setup-Skript herunterzuladen, den so genannten Elastic Beanstalk CLI Installer. Allerdings erfordert dies ebenfalls eine virtuelle Umgebung (virtualenv). Unter Amazon Linux klappt das wie folgt (bei der Arbeit mit Ubuntu ist „dnf install“ durch „apt-get install“ zu ersetzen:

python -m pip install --user virtualenv
python -m virtualenv --help

Mit einem Setup-Skript gelingt die EB-CLI-Installation am schnellsten.
Mit einem Setup-Skript gelingt die EB-CLI-Installation am schnellsten.
(Bild: Drilling / AWS)

Dann installieren wir die EB-CLI über das Setup-Skript …

git clone https://github.com/aws/aws-elastic-beanstalk-cli-setup.git

… gefolgt von …

python ./aws-elastic-beanstalk-cli-setup/scripts/ebcli_installer.py

Das Ergebnis sollte so aussehen, wie im vorangestellten Bild.

3. Es gibt mehrere Möglichkeiten, die EB-CLI zu konfigurieren (Befehlszeilenargumente, Konfigurationsdateien, Umgebungsvariablen). Wir werden hier Umgebungsvariablen verwenden. Warum? Umgebungsvariablen sind Variablen, auf die das gesamte System zugreifen kann. Sie werden häufig zum Festlegen von Parametern wie API-Schlüsseln, Anmeldeinformationen und anderen Variablen verwendet, die aus Sicherheitsgründen nicht fest codiert werden sollten.

Umgebungsvariablen lassen sich in einem Container-Image oder einem beliebigen Betriebssystem mit nur einem Befehl festlegen. Auf Plattformen wie GitHub können Sie Umgebungsvariablen als GitHub-Secrets definieren, auf die Sie über einen GitHub Actions-Runner zugreifen können, wie z. B.:

export AWS_ACCESS_KEY_ID="MY_ACCESS_KEY_ID"
export AWS_SECRET_ACCESS_KEY="MY_SECRET_ACCESS_KEY"
export AWS_DEFAULT_REGION="us-east-1"

GitHub-Secrets

Wir wollen die Beanstalk-Anwendung in nächsten Teil dieses Beitrags mit Hilfe eines Workflows in GitHub-Actions bereitstellen. Dazu verwenden Umgebungsvariablen in unserem Workflow, welche zu diesem Zweck als so genannte GitHub-Secrets abgelegt werden. Bei GitHub-Secrets handelt es sich um eine Funktion, die über die Einstellungen des Repositorys auf GitHub verfügbar ist.

Jedes Secret ist ein Schlüssel-Wert-Paar, das verschlüsselt ist und auf das man über einen GitHub-Actions-Runner zugreifen kann. Im entsprechenden GitHub-Repository werden die Geheimnisse in den Einstellungen des Repositories konfiguriert. Hierfür wählt man auf der rechten Registerkarte „Settings“ in der linken Seitenleiste „Secrets and variables / „Actions“ aus und klickt rechts oben auf „New repository secret“. Nun legen wir nacheinander die drei erforderlichen Geheimnisse für die Interaktion von GitHub mit AWS fest, also:

Jetzt Newsletter abonnieren

Täglich die wichtigsten Infos zu Softwareentwicklung und DevOps

Mit Klick auf „Newsletter abonnieren“ erkläre ich mich mit der Verarbeitung und Nutzung meiner Daten gemäß Einwilligungserklärung (bitte aufklappen für Details) einverstanden und akzeptiere die Nutzungsbedingungen. Weitere Informationen finde ich in unserer Datenschutzerklärung.

Aufklappen für Details zu Ihrer Einwilligung
AWS_ACCESS_KEY_ID
AWS_DEFAULT_REGION
AWS_SECRET_ACCESS_KEY

Git-Hub-Secrets dienen letztlich dem sicheren Speichern von Verbindungsschlüssel, außerhalb des Codes.
Git-Hub-Secrets dienen letztlich dem sicheren Speichern von Verbindungsschlüssel, außerhalb des Codes.
(Bild: Drilling / GitHub)

Die Werte finden sich in der IAM-Console. Die Secrets sind jetzt im GitHub-Actions-Workflow mit dieser Syntax zugänglich.

${{ secrets.SECRET_NAME }}

GitHub-Secrets für AWS.
GitHub-Secrets für AWS.
(Bild: Drilling / GitHub)

Das Ergebnis sollte etwa so aussehen, wie im vorangestellten Bild. Im Folgenden wollen wir dann eine Beanstalk-App über GitHub bereitstellen und dabei die kontinuierliche Integration mit Hilfe von GitHub-Actions einrichten.

GitHub-Actions

GitHub Actions ist eine relativ neue GitHub-Funktion, mit dem Sie ganz einfach einen CI/CD-Workflow auf GitHub ausführen können, um Ihre Änderungen zu erstellen, zu testen und bereitzustellen. Sie können dabei so genannte Workflows definieren, die immer dann ausgeführt werden, wenn ein Pull Request geöffnet oder zusammengeführt wird.

Mit GitHub Actions definieren Sie Workflows in einer YAML-Datei, die in z. B. in PROJECT_ROOT/.github/workflows/YOUR_CONFIG.yml gespeichert wird. Ein Workflow besteht aus Schritten (step), Aktionen (action) und Aufträgen (job), die in einem Runner ausgeführt werden:

  • step: Ein Shell-Befehl oder eine Aktion
  • action: eine benutzerdefinierte Anwendung für GitHub Actions, die wir hier nicht benötigen
  • job: Eine Reihe von Schritten, die nacheinander auf demselben Runner ausgeführt werden
  • runner: Die Umgebung, in der ein Auftrag ausgeführt wird, kann man sich als Container vorstellen

Hier ist ein Beispiel für einen Workflow:

name: example-workflow
on: [push]
jobs:
  example-job:
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: '14'
          cache: 'npm'
      - run: npm install
      - run: npm test

Der Workflow heißt „example-workflow“ und enthält einen einzelnen Auftrag mit dem Namen „example-job“, der aus 4 Schritten besteht:

  • 1. actions/checkout@v2 ist eine Aktion, die das Repository im Runner auscheckt - ohne diese kann Ihr Workflow nicht auf den Code in Ihrem Repository zugreifen.
  • 2. actions/setup-node@v2 ist eine Aktion, die Node.js auf dem Runner einrichtet.
  • 3. npm install ist ein Schritt, mit dem NPM-Abhängigkeiten installiert werden. Beachten Sie, dass npm nur verfügbar ist, weil Node.js im vorherigen Schritt installiert wurde.

npm test ist ein Schritt, der einen NPM-Befehl zum Ausführen von Tests ausführt.

Zusätzlich definiert on: [push] ein Ereignis, das bedeutet, dass der Workflow jedes Mal ausgelöst wird, wenn jemand etwas in das Repository pusht.

Im nächsten Teil wollen wir den ganzen Bereitstellungprozess automatisieren und einer CI/CD-Pipeline versehen. Im Groben sähe dann ein Bereitstellungsskript etwa so aus:

# Install Python 3.9
sudo apt-get install python3.9
# Install pip
curl -O https://bootstrap.pypa.io/get-pip.py
python3 get-pip.py --user
# Install the EB CLI
pip install awsebcli
# Export the env variables required
# by the EB CLI
export AWS_ACCESS_KEY_ID="MY_ACCESS_KEY_ID"
export AWS_SECRET_ACCESS_KEY="MY_SECRET_ACCESS_KEY"
export AWS_DEFAULT_REGION="us-east-1"
# Deploy to EB
# This command will zip up the files in the directory
# and upload the archive to S3
eb deploy

Klicken Sie im GitHub-Dashboard auf das Register „Actions“, können Sie eigene Workflows einrichten. Die Auswahl der mitgelieferten Vorlagen reicht von „Simple workflows“ mit einer einfachen Basis-Struktur bis hin zu sehr spezifischen Vorlagen für „Deployment“, „Security“, „Continous Integration“ oder „Automation“.

GitHub-Workflows, eine Übersicht.
GitHub-Workflows, eine Übersicht.
(Bild: Drilling / GitHub)

Im nächsten Teil werden wir uns dann intensiv mit einem passenden Workflow zum Bereitstellen einer Node-Anwendung auf einer eb-Umgebung befassen.

(ID:49833892)