Container-Cluster unter AWS Amazon Elastic Container Service, Teil 1 – Konzepte

Für den Betrieb von Cloud-native Apps gibt es verschiedene Cluster Manager. In der Cloud sollte Software-Architekten dabei auch AWS ECS, den Elastic Container Service, mit in die engere Wahl nehmen. Wir stellen den älteren der beiden AWS-Container-Cluster-Manager vor.

AWS bietet mit ECS und EKS derzeit gleich zwei verwaltete Container-Cluster-Manager zum Betrieb Cloud-nativer Apps an. Dabei ist ECS zwar der ältere Cluster Manager, der gegenüber EKS aber besser (mit AWS) integriert und weiter entwickelt ist. Dafür ist er eine komplette Eigenentwicklung von AWS und setzt nicht wie EKS im Kern auf Kubernetes auf.

Konkret handelt es sich bei ECS um einen voll verwalteten, aber regionalen Compute-Service. Er dient dazu, Anwendungscontainer über mehrere Availability Zones innerhalb einer Region hinweg hochverfügbar auszuführen. Nutzer können neue ECS-Cluster jeweils in einer neuen oder bestehenden VPC erstellen. Ist der Cluster in Betrieb, können Nutzer wahlweise Single-Tasks auf Basis von so genannten Task-Definitionen oder komplette Services definieren. Dabei definieren sowohl Tasks als auch Services jeweils, welche Docker-Containerabbilder im Cluster ausgeführt werden sollen. Die Container-Images selbst sind im Normalfall in der Amazon Container-Registry (ECR) gespeichert und werden daraus abgerufen. Die Registry kann sich aber bei Bedarf auch außerhalb der AWS-Infrastruktur (Custom Repo oder Docker Hub) befinden. Die grundlegenden Konzepte und Begrifflichkeiten sind Folgende:

Container / Images

Für das Bereitstellen von Anwendungen auf ECS müssen alle Anwendungskomponenten als Container konzipiert sein. Container sind bekanntlich standardisierte Einheiten der Softwareentwicklung, die alles beinhalten, was die Anwendung zur Ausführung benötigt, wie z. B. Code, Runtime, Systemtools, Systembibliotheken usw. Container werden aus einer schreibgeschützten Vorlage (Docker-Abbild) instanziiert.

Die Images selber werden anhand einer Docker-Datei (dockerfile) erstellt, welche alle in dem Container enthaltenen Komponenten angibt. Die Abbilder sind in einer Registry gespeichert, aus der sie heruntergeladen und auf dem Cluster ausgeführt werden können, im Kontext von ECS üblicherweise die Amazon Container Registry. ECR ist „aufrufkompatibel“ mit Docker Hub, im „Backend“ aber in AWS gespeichert und mit anderen AWS-Diensten integriert.

Tasks und Services

Die atomare Deployment-Einheit in ECS ist eine einfache Task. Tasks bestehen aus einem oder mehreren eng miteinander gekoppelten Containern, welche vom „ECS task scheduler“ verwaltet, d. h. platziert, verschoben, gelöscht oder neu gestartet werden. Task können entweder genau einmal ausgeführt werden oder in Intervallen. Sie sind optimal für Batch-Jobs geeignet. Tasks müssen aber nicht für sich allein laufen, sondern können auch Teil eines langlebigen Service sein. Neben dem Task-Scheduler stellt der ECS-Cluster-Manager noch einen zweiten Scheduler, den „ECS service scheduler“ zum Verwalten von Services bereit.

Tasks und Services

Ein Service besteht aus eine konfigurierbaren Anzahl von Tasks hinter einem Load Balancer. Schlägt ein Service fehl oder beendet sich, startet der Service Scheduler eine neue Instanz des Services als Ersatz. Services sind außerdem mit Autoscaling integriert und „AZ-aware“ (AZ = Availability Zone, Hochverfügbarkeitszone). Damit eignen sich Tasks vor allem für On-Demand Workloads, während Services für lang laufenden Applikationen gedacht sind.

Sofern man in der zugehörigen Task-Definition (Ausgabendefinition, s. u.) den Launch-Type „EC2“ auswählt, werden Tasks von einzelnen EC2-Instanzen gehostet, welche den eigentlichen Cluster bilden. Hierbei handelt es sich um gewöhnliche EC2-Instanzen mit Amazon Linux, die jeweils so konfiguriert sind, dass Sie den Docker-Daemon sowie einen EC2-Agenten ausführen.

Task-Definition

Bevor man also einen Task oder Service auf einem ECS-Cluster einplanen kann, müssen ein oder mehrere Tasks auf Basis einer Task-Definition instanziiert werden. Eine solche Aufgabendefinition ist formal eine einfache Textdatei im JSON-Format, in der ein oder mehrere Container (bis zu zehn) beschrieben sind, welche letztendlich den Task darstellen. Man kann sich die Task-Definition auch als Masterplan für die Anwendungserstellung vorstellen.

Aufgabendefinitionen erlauben das Angeben verschiedener Parameter für die Anwendung, etwa …

  • welche Container zu verwenden sind,
  • welcher Starttyp benutzt wird (EC2 oder „Fargate“),
  • welche Ressourcen der/die Task maximal konsumieren darf (anteilige CPU-Units und Memory),
  • welche Ports für die Anwendung geöffnet werden sollen,
  • welche Daten-Volumes mit den Containern in der Task verwendet werden sollen oder
  • ob und wie die Task Zugriff auf eine VPC-Umgebung hat.

Folgende recht einfache Task-Definition für einen NGINX-Webservice basiert auf dem Container-Typ „Fargate“, bei dem sich der Nutzer selbst nicht um die Bereitstellung des Container-Clusters kümmern muss. Dies macht die Sache für den Start zwar einfacher, allerdings hat Fargate auch Einschränkungen – etwa die, dass sich kein persistenter Speicher einbinden lässt.

{
   „family“: „webserver“,
   „containerDefinitions“: [ 
      {
         „name“: „web“,
         „image“: „nginx“,
         „memory“: „100“,
         „cpu“: „99“
      },
   ],
   „requiresCompatibilities“: [
      „FARGATE“
   ],
   „networkMode“: „awsvpc“,
   „memory“: „512“,
   „cpu“: „256“,
}

Container Agent

Schauen wir uns daher zunächst an, wie die Task- oder Service-Platzierung auf einen Container-Cluster aussieht, der auf EC2 basiert. Beim Container-Typ „EC2“ werden Tasks oder langlebige Services auf EC2-Instanzen gehostet, welche zu einem Cluster zusammengefasst werden.

Dieser Cluster ist regionsspezifisch, kann sich aber über mehrere Verfügbarkeitszonen erstrecken. Dabei führt jede EC2-Instanz im ECS-Cluster sowohl Docker als auch den ECS-Agenten aus, der beim Erstellen des ECS-Cluster automatisch auf den ansonsten handelsüblichen EC2-Instanzen erstellt wird – sofern man ein ECS-optimiertes AMI wie Amazon Linux 2 verwendet.

Die ECS- Architektur

Der Amazon ECS-Container-Agent erlaubt es den Container-Instanzen, sich mit dem Cluster zu verbinden. Nutzer können den Agenten aber auch auf jeder anderen Amazon-EC2-Instanz installieren, die die Amazon ECS-Spezifikation unterstützt.

Der Quellcode für den Amazon ECS-Container-Agenten ist auf GitHub verfügbar und kann daher bei Bedarf auch vom Nutzer modifiziert werden. Auch bei der von AWS automatisch verwalteten Infrastruktur zur Tasks-Platzierung Fargate wird der Agent installiert und erfordert dann keine weitere Konfiguration. Wir wollen aber im Folgenden mit „echten“ EC2-Instanzen arbeiten.

Placement-Strategien

Das Besondere an ECS als AWS-Eigengewächs (im Unterschied zu Kubernetes/ECS) sind u. a. die vielseitigen Platzierungsstrategien für Container. Bei einem Request zum Erstellen eines Tasks oder Services gibt man im Rahmen der Task- und/oder Service-Definition wie oben erwähnt z. B. die Anzahl der CPU Units (eine volle Host-CPU umfasst 1024 CPU-Units), den gewünschten Memory-Verbrauch und die Netzwerkanforderungen an.

Ferner lassen sich sogenannte „Custom-Constraints“ angeben, um z. B. gezielt auf Instance-Typ, AMI, AZ oder andere Custom-Attribute zu filtern. Zusätzlich enthält jede Task- oder Service-Definition eine Angabe zur gewünschten Placement-Strategie. Derzeit werden drei Parameter unterstützt:

  • binpack: platziert Tasks aufgrund der geringsten verfügbaren Menge von CPU oder Arbeitsspeicher. Dadurch wird die Anzahl der in Gebrauch befindlichen Instanzen minimiert. Der Name „binpack“ orientiert sich an einem bekannten mathematischen Problem aus der Kombinatorik dem „Behälterproblem“ (wie lassen sich n Objekte so auf m „Behälter“ verteilen (packing), dass keiner der „Behälter“ überläuft?). Dies nennt man auch ein NP-vollständiges Optimierungsproblem
  • random: verteilt Task zufällig über die verfügbaren Instanzen
  • spread: platziert Tasks gleichmäßig auf Basis des hier angegebenen Wertes. Akzeptierte Werte sind Attributschlüssel/Wert-Paare, wie „instanceId“ oder „host“.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.