Eine Deploy-Pipeline mit AWS CodePipeline
December 1, 2017Das Problem
Wer kennt es nicht. Die Stories sind alle abgearbeitet, das BurnDown-Chart geht gegen null, die Product Ownerin frohlockt. Dann kommt die Frage:
“Ist es denn schon live?”
“Öh, jein. Wir müssen nur noch deployen…”
Hektische Betriebsamkeit macht sich breit. Das Release-Datum wird um zwölf Wochen verschoben. Die bisherigen Schätzungen waren alle falsch.
Geht es auch anders?
Doch so muss es nicht sein. Für uns gehört der Deployment-Prozess als vollwertiger Bestandteil zur Produktentwicklung dazu. Also sollte er zum Beginn des Entwicklungsprozesses geplant und mit etwas Liebe bedacht werden. Im folgenden Zeigen wir Euch, wie die Deployment-Pipeline für eben diese Webseite funktioniert und aufgebaut ist.
Continuous Delivery
Für eine Continuous Delivery Pipeline benötigen wir zum einen ein herkömmliches CI-System wie zum Beispiel Jenkins oder Travis. Zum Anderen ein Skript, das unser Projekt baut, testet und live stellt. Hierfür genügt ein Bash-Skript oder ein Makefile. Jenkins ist für gewöhnlich mit operativem Mehraufwand verbunden und nicht ohne weiteres verfügbar. Travis ist mit relativ hohen Kosten verbunden, die sich erst ab einer gewissen Größe lohnen.
Eine Pipeline mit AWS-Bordmitteln
Wir setzen aber vollends auf unseren Cloud-Provider AWS. Amazon stellt mit der AWS CodePipeline einen CI/CD-Service zur Verfügung, der obigen Alternativen in nichts nachsteht. Im Gegenteil - die CodePipeline lässt sich per API konfigurieren und somit durch Code beschreiben. Wir nutzen für AWS-Automatisierungsaufgaben CloudFormation. Hier integriert sich die CodePipeline perfekt.
Eine Pipeline gliedert sich in mehrere Phasen, sogenannte Stages. Eine Stage wiederum besteht aus ein oder mehreren Aktionen. AWS CodePipeline unterstützt folgende Aktionen:
Source
- den Source-Code auscheckenBuild
- ein Artefakt bauenTest
- Tests durchführenDeploy
- Deployment durchführenApproval
- Bestätigung durch Nutzer/Rolle einholenInvoke
- eine AWS Lambda Funktion ausführen
Für unsere Webseite genügen uns zwei Stages. Eine Source
-Stage die Code von GitHub auscheckt. Und eine DeployWebsite
-Stage, die das Artefakt baut und die Webseite in einen S3-Bucket kopiert. In der AWS-Konsole sieht das ganze so aus:
Die Konfiguration für die Source
-Stage sieht wie folgt aus:
- Name: Source
Actions:
- Name: SourceAction
ActionTypeId:
Category: Source
Owner: ThirdParty
Version: 1
Provider: GitHub
InputArtifacts: []
OutputArtifacts:
- Name: SourceOutput
Configuration:
Owner: superluminar-io
Repo: superluminar-website
Branch: master
OAuthToken: !Ref GithubOauthToken
RunOrder: 1
Hier wird eine Action vom Typ Source
verwendet. Damit wird der Source-Code unserer Webseite ausgecheckt. Wichtig ist hierbei der Parameter OAuthToken
. Dies muss ein OAuth Token für GitHub mit dem Scope repo
sein. Weitere Informationen dazu lassen sich hier finden.
Die Konfiguration für die darauffolgende DeployWebsite
-Stage sieht wie folgt aus:
- Name: DeployWebsite
Actions:
- Name: DeployWebsiteAction
ActionTypeId:
Category: Build
Owner: AWS
Version: 1
Provider: CodeBuild
InputArtifacts:
- Name: SourceOutput
OutputArtifacts:
- Name: DeployWebsiteActionOutput
Configuration:
ProjectName:
Ref: DeployWebsiteBuild
RunOrder: 2
Hier verwenden wir eine Action vom Typ Build
. Dies mag widersprüchlich sein, aber wir kombinieren den Build- und den Deploy-Step zu einem. Würden wir auf EC2-Instanzen deployen wollen, wäre eine Action vom Typ Deploy
angebracht. Der spannende Teil hieran ist im Parameter Configuration
mit dem Namen DeployWebsiteBuild
zu finden. Hier wird folgender Teil referenziert:
DeployWebsiteBuild:
Type: AWS::CodeBuild::Project
Properties:
Artifacts:
Type: CODEPIPELINE
Environment:
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/ubuntu-base:14.04
Type: LINUX_CONTAINER
EnvironmentVariables:
- Name: WEBSITE_BUCKET
Value: !Ref WebsiteBucket
Name: !Sub DeployWebsiteBuild-${DeploymentStage}
ServiceRole: !Ref DeployWebsiteRole
Source:
Type: CODEPIPELINE
BuildSpec: |
version: 0.1
phases:
install:
commands:
- make install
build:
commands:
- make build
post_build:
commands:
- make deploy
Der eigentliche Build-Step sieht so aus. Die Spezifikation beschreibt das Format. Dies ähnelt dem Format wie Ihr es z.B. von Travis kennt.
version: 0.1
phases:
install:
commands:
- make install
build:
commands:
- make build
post_build:
commands:
- make deploy
Drei Schritte: die Abhängigkeiten installieren, das Artefakt (unsere Webseite) bauen, die Website in einen S3-Bucket kopieren. Das Makefile für unsere Webseite stellt die obigen drei Targets bereit. Ausgeführt wird das ganze in einem Docker-Container (Image: aws/codebuild/ubuntu-base:14.04
, s.o.). Es stehen verschiedene Docker-Images zur Auswahl. Das gesamte Cloudformation-Template findet Ihr hier.
Fazit
Zugegebenermaßen hat AWS CloudFormation eine steile Lernkurve. Doch die Investition macht sich bezahlt. Wir haben eine Pipeline für unsere Webseite ohne weitere Komponenten gebaut. Ab jetzt können wir unsere Webseite nach Gusto ändern. Gefällt uns etwas nicht, ändern wir es einfach auf GitHub. Unsere Pipeline stellt sicher, das Änderungen binnen Minuten live sind. Eine Sorge weniger. Bis zum nächsten Artikel!