Hugo Deployment S3

In diesem Step-By-Step Tutorial lernen Sie, wie sie ihre statische Hugo Website mit Hilfe von AWS S3 und GitLab CI/CD, BitBucket Pipelines oder GitHub veröffentlichen können.

TL;DR

  1. S3 Bucket mit Option “Statisches Website Hosting” anlegen
  2. CloudFront Distribution mit Origin S3 Bucket (Statisches Website Hosting - Endpunkt) anlegen
  3. SSL Zertifikat über ACM erstellen
  4. Deployment Template: GitLab (GitLab CI/CD) / Bitbucket (Bitbucket Pipelines)

Anlegen des S3 Buckets

Zur S3 Konsole

Amazon Simple Storage Service (Amazon S3)

ist ein Objektspeicherservice, der branchenführende Skalierbarkeit, Datenverfügbarkeit, Sicherheit und Leistung bietet.
Kunden aller Größen und aus allen Branchen können also mit diesem Service beliebige Mengen an Daten speichern und sichern – für die unterschiedlichsten Anwendungsfälle
wie Websites, mobile Anwendungen, Sicherung und Wiederherstellung, Archivierung, Unternehmensanwendungen, IoT-Geräte und Big-Data-Analysen.

Zuerst muss der S3 Bucket angelegt werden, in dem später die statischen HTML sowie Asset Dateien (JS, CSS, Images, etc.) bereitgestellt werden.
S3 bietet von Haus aus verschiedene Zugriffseinstellungen an - so sind Buckets nach dem Erstellen generell “private” und Objekte können nur vom Ersteller gelesen und geschrieben werden.
Weiterhin verhält sich der S3 Bucket ähnlich wie z.B. Dropbox & co. als reine Dateiablage.
Damit unsere Website später aus dem Internet erreichbar ist, muss der Bucket für das Hosting von statischen Websites konfiguriert werden und die Objekte für “public” lesbar sein.
Um unseren Bucket zu konfigurieren müssen folgenden Schritten Schritte durchgeführt werden:

1. Name und Region

Erstellen Sie einen neuen S3 Bucket, als Namen wählen sie den gleichen Namen wie ihre Domain (z.B. www.anw.net), Wählen Sie die Region in welcher der Bucket angelegt werden soll.

2. Optionen konfigurieren

Hier können Sie weitere Einstellungen vornehmen, in diesem Tutorial verwenden wir die Standardeinstellungen von AWS

3. Berechtigungen

Wie bereits erwähnt, sind neu angelegte Buckets mit einem Schutzmechanismus versehen, welcher verhindern soll, dass Objekte unbeabsichtigt öffentlich zugänglich gemacht werden können.
Da unsere Website öffentlich erreichbar sein soll, müssen wir hier alle Optionen für “Öffentliche Zugriffskontrolllisten” und “Öffentliche Bucket-Richtlinien” abwählen, damit wir öffentliche Berechtigungen auf unsere Objekte vergeben dürfen.

4. Prüfen

Abschließend erhalten Sie nochmals eine Übersicht über ihre Konfiguration, schließen Sie die Erstellung mit “Bucket erstellen” ab.

5. Statisches Webhosting aktivieren

Wählen Sie ihren neu erstellten Bucket einmal an und wechseln Sie auf den Reiter “Eigenschaften” - hier aktivieren Sie die Option “Hosten einer statischen Website”
Wählen Sie hier die Option “Diesen Bucket zum Hosten einer Website verwenden” und geben Sie als Indexdokument “index.html” und Fehlerdokument “error.html” an.
Beachten Sie die Option “Endpunkt” die Ihnen in diesem Dialog angezeigt wird - diese von AWS generierte Subdomain kann später von Ihnen genutzt werden, um ihre Website aufzurufen.

CloudFront anlegen

Zur CloudFront Konsole

Amazon CloudFront

ist ein schneller Content Delivery-Service (CDN), der Daten, Videos, Anwendungen und APIs sicher, mit niedriger Latenz, hoher Übertragungsgeschwindigkeit und innerhalb einer entwicklerfreundlichen Umgebung an Kunden auf der ganzen Welt liefert. CloudFront arbeitet nahtlos
mit Diensten wie AWS Shield für DDoS-Minderung, Amazon S3, Elastic Load Balancing oder Amazon EC2 als Ursprung für Ihre Anwendungen zusammen, sowie Lambda @ Edge, welcher den benutzerdefinierten Code näher an den Benutzern der Kunden und deren Benutzererfahrung näher bringt.

CloudFront bietet neben der Möglichkeit unsere Website über Amazon’s Content-Delivery Network zu veröffentlichen auch die Bereitstellung der Website mittels TLS Endpunkt.
Um unseren S3 Bucket mit CloudFront zu verbinden müssen folgende Schritte durchgeführt werden:

1. CloudFront Distribution anlegen

Wechseln Sie in die CloudFront Konsole und erstellen Sie eine neue CloudFront Distribution

2. Verteilungsart wählen

Wählen Sie als Verteilungsart “Web”

3. Web Distribution anlegen

Origin konfigurieren

CloudFront benötigt einen “Ursprung” (Origin) von welchem die Files unserer Website abgerufen werden.
Geben Sie bei “Origin Domain Name” den Endpunkt aus dem Dialog “Statisches Webhosting aktivieren” ohne Protokoll (http://) ein.

Cacheverhalten konfigurieren

Konfigurieren Sie nun das (Cache)-Verhalten des Ursprungs aus.
Wählen Sie die Option “Redirect HTTP to HTTPS” aus um sämtliche HTTP anfragen automatisch auf HTTPS umzuleiten.
Für die weiteren Einstellungen verwenden wir die von AWS vorgebenenen Standardwerte

Distributionseinstellungen

Im letzten Schritt haben Sie nun die Möglichkeit auszuwählen, an welche “Edge Locations” ihre Website verteilt werden soll.
Beachten Sie, je höher Sie den Verteilungsgrad auswählen desto mehr Kosten stellt AWS ihnen in Rechnung.
Für unser Tutorial ändern Sie die Option “Price Class” in “Use Only U.S., Canada and Europe”

Geben Sie anschließend bei “Alternate Domain Names” ihren Domainnamen an (z.B. www.anw.net)
Damit unsere Website über HTTPS erreichbar ist, muss ein entsprechendes SSL Zertifikat beantragt werden, dies können Sie über einen Klick auf “Request or Import a Certificate with ACM” erstellen.

SSL Zertifikat beantragen

Zur ACM Konsole

AWS Certificate Manager (ACM)

ist ein Service, mit dem Sie problemlos öffentliche und private SSL- und TLS-Zertifikate (Secure Sockets Layer/Transport Layer Security) zur Verwendung mit AWS-Services und Ihren internen verbundenen Ressourcen bereitstellen und verwalten können.
SSL-/TLS-Zertifikate werden verwendet, um die Netzwerkkommunikation zu sichern und die Identität von Websites im Internet sowie von Ressourcen in privaten Netzwerken nachzuweisen.
AWS Certificate Manager macht den zeitaufwändigen manuellen Prozess des Kaufens, Hochladens und Erneuerns von SSL-/TLS-Zertifikaten überflüssig.

Domainnamen hinzufügen

Im nachfolgenden Wizard fügen Sie ihren Domainnamen (z.B. www.anw.net) hinzu für welche ein SSL Zertifikat erstellt werden soll.
Die Validierung erfolgt wahlweise über E-Mail oder Einträge in ihrer DNS Zone.
Beachten Sie, dass eine Validierung über E-Mail zeitlich begrenzt und einen manuellen Eingriff zur Re-Validierung erfordert.
Wenn Sie die DNS Methode nutzen, wird ihr Zertifikat automatisch verlängert und erfordert keinen manuellen Eingriff.

Sobald die Validierung abgeschlossen ist, wechseln Sie zurück in die CloudFront Einstellungen und wählen Sie das neu erstellte Zertifikat aus.
Schließen Sie die Erstellung der CloudFront Distribution durch einen Klick auf “Create Distribution” ab.

DNS Anpassungen für CloudFront

Nach Abschluss wird Ihnen ein neuer CloudFront Domain Name (z.B. 123456asdfjkl.cloudfront.net) angezeigt unter welcher ihre Distribution erreichbar ist.
Legen Sie einen neuen CNAME an (z.B. www.) und wählen Sie als Ziel ihren CloudFront Domain Namen - wie sie dies durchführen entnehmen sie der Hilfe ihres DNS Providers.
Nutzen Sie unbedingt den Domainnamen, welchen Sie auch für die Schritte “SSL Zertifikat beantragen” benutzt haben.

IAM Berechtigungen anlegen

Zur IAM Konsole

Mit AWS Identity and Access Management (IAM)

können Sie den Zugriff auf AWS-Services und -Ressourcen sicher verwalten.
Mithilfe von IAM können Sie AWS-Benutzer und -Gruppen anlegen und verwalten und mittels Berechtigungen ihren Zugriff auf AWS-Ressourcen zulassen oder verweigern.

Wechseln Sie zur “Benutzer” Übersicht und wählen dort “Benutzer hinzufügen”.
Im nachfolgenden Dialog vergeben Sie dem neuen Benutzer einen Benutzernamen und wählen sie anschließend die Option “Programmgesteuerter Zugriff” aus.
Wechseln Sie in den Tab “Vorhandene Richtlinien direkt anfügen” und klicken Sie auf “Richtlinie erstellen”.

Für das spätere Deployment der Website benötigt der Benutzer Lese/Schreib-Rechte auf unserem S3 Bucket.
Kopieren Sie hierzu folgende IAM Policy im nachfolgenden Dialog in den Editor, wechseln Sie hierzu auf den Tab “JSON”:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "S3Deploy0",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObjectAcl",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:DeleteObject",
                "s3:PutObjectAcl"
            ],
            "Resource": [
                "arn:aws:s3:::<MYBUCKET>",
                "arn:aws:s3:::<MYBUCKET>/*",
            ]
        },
        {
            "Sid": "S3Deploy1",
            "Effect": "Allow",
            "Action": [
                "s3:ListAllMyBuckets",
                "s3:HeadBucket"
            ],
            "Resource": "*"
        }
    ]
}

Ändern Sie den Inhalt der Policy “” mit dem Namen ihres S3 Buckets ab.

Speichern Sie die Änderungen mit “Richtlinie überprüfen” ab und vergeben Sie einen Namen für die Richtlinie (z.B. S3FullAccess)
Wechseln Sie zurück in den Wizard zur Erstellung unseres neuen Benutzers und klicken Sie oben rechts auf “Aktualisieren”.
Suchen Sie nun nach der neu erstellten Richtlinie und wählen Sie diese aus.
Klicken Sie nun auf “Weiter: Tags”, “Weiter: Prüfen” und abschließend auf “Benutzer erstellen”.
Notieren Sie sich “Zugriffsschlüssel-ID” sowie “Geheimer Zugriffsschlüssel”, oder laden Sie optional die Credentials als CSV Datei herunter.

Automatische Verteilung ihrer Website

anw.net GmbH - Docker Hub

Im abschließenden Schritt richten wir das Deployment ein.
Die drei großen Anbieter GitLab, Bitbucket und GitHub stellen hierzu jeweils eigene Lösungen bereit, um ein automatisiertes Deployment einzurichten.
Sowohl GitLab als auch Bitbucket kommen von Haus aus mit einer eigenen CI/CD Lösung, GitHub hingegen bietet die Möglichkeit, verschiedene externe Anbieter für CI/CD über den Marketplace als Extension anzusteuern.
Die Einrichtung und Konfiguration unterscheidet sich hierdurch stark nach gewählter Erweiterung, weshalb wir un unserem Beispiel nur die beiden Möglichkeiten von GitLab und Bitbucket betrachten.

Alle drei Anbieter ermöglichen das Deployment mit Hilfe von Docker Images und einer Konfigurationsdatei, welchen den Ablauf des Deployments beschreibt.
In unserem Beispiel verwenden wir zwei Stages: Development und Production.
Sobald ein Commit in den “development” erfolgt, wird das Deployment getriggert und unser aktueller Entwickluns- bzw. Testing-Stand veröffentlicht.
Ein Production Release wird nach Vergabe eines Git-Tags getriggert.
Hierdurch besteht die Möglichkeit auch später zu verschiedenen Versionen durch erneuter Ausführung des jeweiligen Deployment-Jobs zurück zu wechseln.

Docker Images

ANW bietet verschiedene öffentliche Docker Images an - diese finden Sie im > Docker Hub < und stehen Ihnen zur freien Nutzung bereit.

Unabhängig des Stages werden folgende Schritte ausgeführt:

  1. Installation der Abhängigkeiten (z.B. Hugo Themes als Submodule)
  2. Hugo “build” wird ausgeführt (Generierung der statischen Dateien)
  3. Push nach AWS S3 (Upload der Dateien, Invalidierung des CloudFront Caches)


Docker Image Berechtigungen

Damit das Docker Image mit AWS kommunizieren darf, müssen folgende Umgebungsvariablen an den Docker Container übergeben werden:

Credentials:

  • AWS_ACCESS_KEY_ID (=> Zugriffsschlüssel-ID)
  • AWS_SECRET_ACCESS_KEY (=> Geheimer Zugriffsschlüssel)
  • AWS_DEFAULT_REGION (=> Ihre AWS Account Region z.B. “eu-central-1”)

Je nach Anbieter unterscheidet sich die Art wie sie die Umgebungsvariablen über das CI/CD System an den Container übergeben.
Weitere Informationen hierzu finden Sie hier: GitLab bzw. Bitbucket

(Optional) GitLab CI/CD

GitLab bietet mit dem Feature “GitLab CI/CD” eine komplett eigenständige und nahtlos integrierte Lösung für “Continuous Integration & Delivery” an.
Hierzu wird im jeweiligen Projekt Repository eine spezielle Datei mit dem Namen “.gitlab-ci.yml” angelegt, welche die Konfiguration und Ablauf des jeweiligen Deployments enthält.
Nähere Informationen hierzu können Sie der Dokumentation entnehmen: GitLab Continuous Integration

Eine mögliche Implementierung der “.gitlab-ci.yml” könnte wie folgt aussehen:

stages:
  - development
  - development:publish
  - production
  - production:publish

dev:build:
  stage: development
  image: anwnet/hugo:latest
  before_script:
    - git submodule sync --recursive
    - git submodule update --init --recursive
    - git submodule update --remote --merge
  script:
    - build "development"
  artifacts:
    paths:
      - public/
  only:
    - development
  tags:
    - docker

dev:publish:
  stage: development:publish
  image: anwnet/hugo:latest
  script:
    - deploy "development"
  artifacts:
    paths:
      - public/
  only:
    - development
  tags:
    - docker
  dependencies:
    - dev:build


prod:build:
  stage: production
  image: anwnet/hugo:latest
  before_script:
    - git submodule sync --recursive
    - git submodule update --init --recursive
    - git submodule update --remote --merge
  script:
    - build "production"
  artifacts:
    paths:
      - public/
  only:
    - /^v(\d+\.)?(\d+\.)?(\*|\d+)$/
  except:
    - branches
  tags:
    - docker

prod:publish:
  stage: production:publish
  image: anwnet/hugo:latest 
  script:
    - deploy "production"
  artifacts:
    paths:
      - public/
  only:
    - /^v(\d+\.)?(\d+\.)?(\*|\d+)$/
  except:
    - branches
  tags:
    - docker
  dependencies:
    - prod:build

(Optional) Bitbucket Pipelines

Bitbucket bietet mit dem Feature “BitBucket Pipelines” eine komplett eigenständige und nahtlos integrierte Lösung für “Continuous Integration & Delivery” an.
Hierzu wird im jeweiligen Projekt Repository eine spezielle Datei mit dem Namen “bitbucket-pipelines.yml” angelegt, welche die Konfiguration und Ablauf des jeweiligen Deployments enthält.
Nähere Informationen hierzu können Sie der Dokumentation entnehmen: Configure bitbucket-pipelines.yml

Eine mögliche Implementierung der “bitbucket-pipelines.yml” könnte wie folgt aussehen:

image:
  name: 'anwnet/hugo'

pipelines:
  default:
    
  branches:
    development:
      - step:
        name: Update Dependencies
        script:
          - git submodule sync --recursive
          - git submodule update --init --recursive
          - git submodule update --remote --merge
      - step:
        name: Build (Testing)
        script:
          - build "development"
        artifacts:
          - public/**
      - step:
          name: Deployment (Testing)
          script:
            - deploy "development"
  tags:
    'v[0-9]*.[0-9]*.[0-9]*':
      - step:
        name: Update Dependencies
        script:
          - git submodule sync --recursive
          - git submodule update --init --recursive
          - git submodule update --remote --merge
      - step:
        name: Build (Production)
        script:
          - build "production"
        artifacts:
          - public/**
      - step:
          name: Deployment (Production)
          script:
            - deploy "production"

Fazit

Amazon Web Services bietet Ihnen umfangreiche Möglichkeiten zum Hosten einer statischen Website.
Die Möglichkeiten des Deployments sind je nach Anbieter recht unterschiedlich und erfordern eine Einarbeitung in die jeweiligen Features.
Dank der Nutzung von Docker Images ist der erforderliche Aufwand jedoch überschaubar und erlaubt eine agile Methode zur kontinuierlichen und automatischen Veröffentlichung von neuen Inhalten.
Auch Erweiterungen wie die Ausführung von Unit Tests oder ähnlichen, weiteren Zwischenschritten können so jederzeit problemlos in den Workflow integriert werden.