Entwicklung und stetige Auslieferung einer Angular-App in der AWS Cloud

Leitfaden: Wir bauen eine Angular-App in der AWS Cloud
1 Kommentar

Lokal ein neues Angular-Projekt aufzusetzen funktioniert dank Angular CLI im Handumdrehen. Doch um eine App professionell zu entwickeln und zu warten, bedarf es neben einem guten Entwicklungsprozess auch einer guten Entwicklungsumgebung. Oft ist eine Webanwendung die Schnittstelle eines Systems mit dem Backend in einer Cloud – es ist also auch sinnvoll, die Webanwendung in der Cloud zu entwickeln und abzulegen.

Eine Angular-App in der AWS Cloud

Wir wollen agil arbeiten, wollen also neue Anforderungen in kurzen Iterationen ausliefern, um möglichst schnell Feedback zu bekommen. Dazu ist es wichtig, dass wir auch innerhalb der Entwicklungszyklen schnell Feedback bekommen. Um das zu erreichen, muss der aktuelle Entwicklungsstand der App stetig integriert und zur Verfügung gestellt werden. Es ergeben sich einige Fragen: Wo verwalten wir unseren Code? Wie und wo können wir die Anwendung stetig integrieren und bauen?

Wie bekommen wir zeitnah Feedback aus unseren Tests? Und wie können wir den derzeitigen Stand unserer App auf verschiedenen Stages automatisiert ausliefern, um auch fortlaufend fachliches Feedback zu bekommen? Für dieses Szenario gibt es etliche Lösungen mit verschiedenen Stärken und Schwächen. Meist stellt die Webanwendung die Schnittstelle eines mehr oder weniger komplexen Systems dar, dessen Backend immer häufiger in einer Cloud liegt. Dadurch macht es Sinn, auch die Webanwendung in der Cloud zu entwickeln und abzulegen. In diesem Tutorial realisieren wir dieses Szenario durch eine Angular SPA, die wir innerhalb der AWS Cloud (Abb. 1) entwickeln und auch dort hosten.

Abb. 1: Übersicht

Die Infrastruktur verwalten

Sobald wir einen AWS-Account angelegt haben, können wir uns in die AWS-Konsole einloggen. Die Konsole stellt die grafische Schnittstelle zur Verwaltung sämtlicher Ressourcen und Services der AWS Cloud dar. Je nach Vorlieben und Bedarf bietet Amazon ein mächtiges AWS CLI sowie diverse SDK und Toolkits zur Verwaltung unserer Cloud. Hier verwenden wir die Konsole, für komplexere Systeme empfehle ich jedoch, die Infrastruktur als Code zu verwalten (Kasten „Infrastructure as Code“).

Infrastructure as Code
Als Infrastructure as Code (IaC) wird das Konzept bezeichnet, IT-Infrastrukturen in Form von Code zu definieren, zu verwalten und darüber automatisiert bereitstellen zu können. Amazon hat dieses Konzept in ihrem proprietären AWS CloudFormation umgesetzt. Es gibt jedoch auch sehr gute herstellerunabhängige Lösungen wie Terraform.

Zugriffssteuerung mit AWS IAM

IAM steht für Identity and Access Management, mit dessen Hilfe die Zugriffe auf die Ressourcen verwaltet werden. Wir erreichen den IAM Service in der Konsole über das Services-Menü. Er befindet sich in der Kategorie Security, Identity and Compliance. Es hat sich als gute Praxis herausgestellt, nicht mit dem Root-Account eines Systems zu arbeiten. Dementsprechend erstellen wir uns zuerst einen Admin-Account, mit dem wir zukünftig weiterarbeiten.

Via USERS | ADD USER erstellen wir uns einen neuen Admin-Benutzer, dem wir sowohl programmatischen Zugriff als auch Zugriff auf die AWS-Management-Konsole gewähren. Das Konsolenpasswort lässt sich dabei automatisch generieren oder auch individuell vergeben. Die Option REQUIRE PASSWORT RESET deaktivieren wir. Einen Schritt weiter weisen wir dem neuen User via ATTACH EXISTING POLICIES DIRECTLY Administratoraccess zu. Sobald wir den Admin-Benutzer angelegt haben, laden wir uns die Zugangsdaten als CSV-Datei herunter. Diese enthalten einen Anmeldelink sowie die Zugangsdaten des neu erstellten Admin-Accounts.

Nachdem wir uns angemeldet haben, erstellen wir noch einen operativen Benutzer, etwa developer1, um im nächsten Schritt auf die Codeverwaltung zuzugreifen. Wie gehabt legen wir uns einen neuen Benutzer an, diesmal allerdings nur mit programmatischen Zugriffsrechten, dem wir via ATTACH EXISTING POLICIES DIRECTLY AWSCodeCommitFullAccess gewähren. Wir öffnen nun nochmal den Administrationsbereich dieses Users und erstellen unter SECURITY CREDENTIALS | HTTPS GIT CREDENTIALS FOR AWS CODECOMMIT | GENERATE neue Zugangsdaten für den Git-Zugriff. Diese speichern wir uns im CSV-Format.

iJS React Cheat Sheet

Free: React Cheat Sheet

You want to improve your knowledge in React or just need some kind of memory aid? We have the right thing for you: the iJS React Cheat Sheet (written by Joel Lord). Now you will always know how to React!

Quellcodeverwaltung in AWS CodeCommit

Der von Amazon bereitgestellte, proprietäre Web-Service zum Verwalten von Quellcodes nennt sich AWS CodeCommit und hostet Git Repositories. Eine Integration von Bitbucket oder GitHub Repositories wäre ebenso möglich. Über das Service-Menü der Konsole gelangen wir zu AWS CodeCommit und können uns dort ein neues Repository anlegen, beispielsweise javamagazin.

Angular-Projekt in AWS CodeCommit Repository pushen

Unser Repository ist eingerichtet und wartet darauf, befüllt zu werden. AWS CodeCommit hostet ein Git Repository. Falls nicht bereits geschehen, installieren wir uns also einen Git-Client. Wir erstellen über die Angular CLI ein neues Angular-Projekt: ng new javamagazin und wechseln in das neue Projektverzeichnis. Zunächst sollten wir prüfen, ob alle Unit-, Integrations- und E2E-Tests erfolgreich durchlaufen und diese unter Umständen fixen.

Anschließend benötigen wir den Link zum Git Repository und die zugehörigen Zugangsdaten. Den Link finden wir in der Konsole unter SERVICES | AWS CODECOMMIT | REPOSITORY | CLONE URL (RECHTS) | HTTPS. Die Git-Zugangsdaten liegen in der heruntergeladen CSV-Datei des operativen Benutzers developer1. Jetzt initialisieren wir Git für das Projektverzeichnis und fügen dem Repository alle darin befindlichen Dateien hinzu.

 
git init
git add .

Wir bestätigen die Änderungen, legen den Endpunktpunkt fest und verifizieren ihn.

 
git commit -m "init angular project"
git remote add origin https://git-codecommit...... 
git remote -v // verify the repo url

Abschließend schieben wir den Commit in das Repository.

 
git push origin master (enter the AWS IAM user´s security credentials)

Sollte sich dabei das Fenster des Git Credential Manager for Windows öffnen, können Sie diesen verwenden, um ihre Zugangsdaten zu speichern, oder Sie schließen den Dialog via ABBRECHEN. Dementsprechend hat der Credential Manager die Zugangsdaten bereits übermittelt, oder es erscheint die Aufforderung dazu in der Konsole. Das Git Repository ist nun lokal eingerichtet und der initiale Stand eingecheckt (Listing 1).

_>git push origin master
Username for 'https://git-codecommit.eu-central-1.amazonaws.com': developer1-at-0123456789
Password for 'https://developer1-at-0123456789@git-codecommit.eu-central-1.amazonaws.com':
Enumerating objects: 38, done.
Counting objects: 100% (38/38), done.
Delta compression using up to 4 threads.
Compressing objects: 100% (36/36), done.
Writing objects: 100% (38/38), 93.93 KiB | 3.91 MiB/s, done.
Total 38 (delta 1), reused 0 (delta 0)
To https://git-codecommit.eu-central-1.amazonaws.com/v1/repos/javamagazin
 * [new branch]      master -> master

Über ein AWS S3 Bucket hosten

AWS S3 ist ein Onlinedatenspeicher. Man spricht hierbei von S3 Buckets (Behälter). Unsere Angular-App werden wir über ein S3 Bucket hosten. Dazu erstellen wir uns via KONSOLE | SERVICES | S3 | CREATE BUCKET unter Verwendung der vorgegebenen Standardkonfiguration eine neue Datenbehälter. Bucket-Namen müssen innerhalb der gesamten AWS Cloud eindeutig sein und einer Namenskonvention entsprechen. Im Administrationsbereich unseres neuen Buckets aktivieren wir via PROPERTIES | STATIC WEBSITE HOSTING das statische Hosten von Websites und legen die index.html als Startseite fest.

Abb. 2: Static Website Hosting

Im Dialogfenster aus Abbildung 2 finden wir den Endpoint des S3 Buckets. Über diesen Link wird die App später erreichbar sein. Vorerst sollte ein 403-Fehler auftreten, wenn wir dem Link folgen.

An dieser Stelle könnten wir die App bereits lokal bauen und die Artefakte manuell in das S3 Bucket laden. Wir wollen den Build-Prozess jedoch automatisieren.

Die App mit AWS CodeBuild bauen

Im nächsten Schritt möchten wir unsere App automatisiert bauen. Dazu erstellen wir zunächst eine passende Build-Umgebung in AWS CodeBuild. Wichtig ist zu wissen, dass Amazon diesen Service über die Build-Zeit abrechnet. Im aktuellen Einstiegspaket umfasst das kostenlose Kontingent 100 Minuten pro Monat.

Wir nennen das Projekt analog javamagazin und wählen als Quelle unser entsprechendes AWS CodeCommit Repository, das wir in voller Tiefe klonen wollen. Als Build-Umgebung legen wir Ubuntu mit einer Node.js 8 Runtime fest. Es sollen keine Artefakte ausgeliefert werden. Für die restlichen Einstellungen verwenden wir die Defaultwerte.

Die Rechte des Build-Clients werden über eine Service-Rolle definiert. Standardmäßig wird für jedes neue Build eine neue Servicerolle angelegt. Wird der Build nun gestartet, erscheint berechtigterweise eine Fehlermeldung, dass keine buildspec.yml gefunden werden kann.

Die buildspec.yml beschreibt, wie ein Projekt gebaut wird, und ist im Root-Verzeichnis des Repository abzulegen.

Vorweg erweitern wir unsere package.json um ein Script zur Erstellung des produktiven Builds, indem wir unter scripts den Eintrag prodbuild“: „ng build –prod –progress false hinzufügen. Anschließend erstellen wir im Root-Verzeichnis eine buildspec.yml (Listing 2). In dieser minimalen Spezifikation wird definiert, dass zunächst alle NPM-Abhängigkeiten installiert und danach die produktive App gebaut wird.

version: 0.2

phases:
  install:
    commands:
      # install dependencies needed for running tests
      - npm install

  build:
    commands:
      # trigger production build
      - ng run prodbuild

Nun können wir unsere Änderungen in das Git Repository pushen. Starten wir nun unseren AWS CodeBuild erneut, wird dieser erfolgreich durchlaufen. Ein direktes Ausführen von ng build –prod ist auch möglich, wenn wir innerhalb der Installationsphase die Angular CLI global durch npm install -g @angular/cli installieren.

Continuous Integration durch AWS CodePipeline

Wir möchten den Build selbstverständlich nicht jedes Mal manuell anstoßen, sondern automatisiert, wenn Änderungen in den Master-Branch gepusht werden. Dazu erstellen wir eine einfache Pipeline über AWS CodePipeline, die den Build-Prozess entsprechend anstößt. Wir legen eine neue Pipeline mit dem Namen javamagazin an und verweisen diese auf den Master-Branch unseres AWS CodeCommit Repository.

Das Projekt soll über unser zuletzt angelegtes AWS CodeBuild-Projekt gebaut, aber nicht deployt werden. Auch die Rechte der AWS CodePipeline werden über Rollen definiert. Diese können wir via CREATE ROLE mit zwei Klicks erstellen. Die Pipeline wird normalerweise kurz nach dem Erstellen automatisch das erste Mal ausgeführt. Wir können sie jedoch pragmatisch manuell testen, indem wir eine Leerzeile am Ende der README.MD des Projekts hinzufügen und diese Änderung in das Git Repository pushen. Nach kurzer Zeit werden wir sehen, dass die Pipeline angestoßen wird.

Automatisiert testen

Da die Build-Pipeline steht, können wir nun endlich auch unsere Tests in den automatisierten Build integrieren. Dazu werden wir Karma und Protractor um eine Headless-Konfiguration erweitern. Headless bedeutet, dass der Browser ohne grafische Oberfläche gestartet wird. Wir erweitern die Karma-Konfigurationsdatei karma.conf.js um die Konfiguration HeadlessChrome, um Chrome im Headless-Moduls starten zu können (Listing 3).

// ...
customLaunchers: {
  HeadlessChrome: {
    base: 'ChromeHeadless',
    flags: ['--no-sandbox','--headless','--disable-gpu']
  }
}
// ...

Anschließend fügen wir der package.json ein neues Script hinzu, das die Integrations- und Unittests headless ausführt.

"test-headless": "ng test --browsers HeadlessChrome --watch false –progress false",

Wir erstellen innerhalb des E2E-Verzeichnisses eine Kopie der Protractor-Konfiguration protractor.conf.js und nennen diese protractor.headless.conf.js. Der capability Property fügen wir Startparameter hinzu, um Chrome im Headless-Modus zu starten (Listing 4) und fügen der package.json ein neues Script hinzu, das auch die E2E-Tests headless ausführt: e2e-headless“: „ng e2e –protractor-config ./e2e/protractor.headless.conf.js

capabilities: {
  browserName: 'chrome',
  chromeOptions: {
    args: ['--no-sandbox', '--headless', '--disable-gpu', '--window-size=800x600']
  }
},

Nun können wir unsere buildspec.xml entsprechend Listing 5 anpassen.

version: 0.2

phases:
  install:
    commands:
      # install dependencies needed for running tests
      - npm install
      # Get Chrome Information
      - curl -sS -o - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
      - echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list
      - apt-get -y update
      - apt-get -y install google-chrome-stable

  build:
    commands:
      # trigger production build
      - npm run prodbuild

  post_build:
    commands:
      # trigger headless karma tests
      - npm run test-headless
      # trigger headless e2e tests
      - npm run e2e-headless

Innerhalb der Installationsphase werden nun sämtliche APT-Pakete der Build-Umgebung aktualisiert und Chrome installiert. Nach der Build-Phase führen wir Headless die Unit-, Integrations- und E2E-Tests durch. Wir pushen diese Änderungen ins Git Repository und der Build samt Tests sollte erfolgreich durchlaufen.

Automatisiert ausliefern

Nun müssen unsere getesteten Artefakte noch ausgeliefert werden. Bestenfalls sollte das Ausliefern der Artefakte auf einer extra Stage stattfinden, die die Artefakte der Build-Stage entgegennimmt und sie an das S3 Bucket ausliefert. Ich habe allerdings keinen eleganten Weg gefunden, die Artefakte in einer extra Stage in ein S3 Bucket zu kopieren und sie gleichzeitig öffentlich freizugeben. Deshalb werden wir die Artefakte innerhalb der Build-Stage über das AWS CLI in das S3 Bucket kopieren. Das könnte man selbstverständlich auch in eine explizite CodeBuild-Stage auslagern. In unserem Beispiel werden wir diesen Schritt in das bestehende Build-Skript integrieren. Dafür müssen wir unserer Service-Rolle zunächst die entsprechenden Rechte einrichten (Kasten: „Rechte für die Service-Rolle“).

Rechte für die Service-Rolle

Wir bearbeiten die Service-Rolle unseres Build-Clients in AWS IAM. In unserem Fall lautet der Name unserer Service-Rolle codebuild-javamagazin-service-role. Diese enthält die Policy CodeBuildBasePolicy-javamagazin-eu-central-1, die wir auswählen und via EDIT POLICY editieren. Wir wählen durch den S3-Bereich und darin anschließend den Actions-Bereich aus. Dort selektieren wir die Checkbox ALL S3 ACTIONS. Anschließend können wir im Ressourcenbereich den Zugriff auf unser Bucket freischalten. Dazu klicken wir im Bucket-Bereich auf ADD ARN und geben im darauffolgenden Dialog den Namen unseres Buckets an. In unserem Fall lautet er javamagazin, woraus sich die ARN arn:aws:s3:::javamagazin ergibt. Wir benötigen keine Einschränkung auf Objektebene, selektieren hier somit any. Auf Ressourcenebene benötigen wir ebenfalls keine Beschränkungen und können diese entfernen.

Die Servicerolle verfügt ab sofort über die benötigten Rechte, um in unser AWS S3 Bucket kopieren zu dürfen. Da wir den Namen unseres Buckets nicht fest in die buildspec.yml eintragen möchten, werden wir diesen über eine Variable übergeben. Wir editieren dazu unseren AWS CodeBuild und definieren im eingeklappten Bereich ganz unten eine Umgebungsvariable S3_BUCKET, die als Wert den Namen unseres Buckets als Plain-Text beinhaltet.

Wir speichern diese Änderung und erweitern nun die buildspec.yml unseres Projekts im Post-Build-Bereich um den Befehl

aws s3 cp --recursive dist/javamagazin s3://$S3_BUCKET/ --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers

Er kopiert die kompilierten Artefakte aus dist/javamagazin in unser AWS S3 Bucket und macht diese öffentlich zugänglich (Listing 6).

 
// …
  post_build:
    commands:
      # trigger headless karma tests
      - npm run test-headless
      # trigger headless e2e tests
      - npm run e2e-headless
      # copy artifacts to the S3 bucket
      - aws s3 cp --recursive dist/javamagazin s3://$S3_BUCKET/ --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers

Nach dem Commit unserer Änderungen in das Git Repository wird die Pipeline ausgelöst. Sobald das Build erstellt wurde, sollten wir die Artefakte in unserem S3 Bucket sehen und die Angular-App ist über den Endpoint des Buckets erreichbar (BUCKET | PROPERTIES | STATIC WEBSITE HOSTING).

Route 53

Route 53 bringt, wie die Zahl bereits vermuten lässt, nicht Biker, sondern Surfer ans Ziel. Es handelt sich um die Domainverwaltung der AWS Cloud. Hier könnten wir nun eine Domain registrieren und an unser S3 Bucket weiterleiten.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Hinterlasse einen Kommentar

1 Kommentar auf "Leitfaden: Wir bauen eine Angular-App in der AWS Cloud"

avatar
400
  Subscribe  
Benachrichtige mich zu:
Sven Jeppsson
Gast

Hey, danke für diesen Artikel.
Ich habe es gerade bis zum CodeBuild durchgespielt.
Bekomme den Fehler: „/codebuild/output/tmp/script.sh: ng: not found“.
Habe die buildspec.yml angepasst mit „npm run prodbuild“ läuft es

X
- Gib Deinen Standort ein -
- or -