Zum Hauptinhalt springen

Verwaltung und Bereitstellung von containerisierten Anwendungen

Starten einer containerisierten Anwendung

Um einen Container über das mStudio zu starten, folge diesen Schritten:

  1. Navigiere zu dem Projekt, in dem du den Container erstellen möchtest.
  2. Wähle den Menüpunkt "Container" in der Seitenleiste aus.
  3. Klicke auf die Schaltfläche "Container erstellen".
  4. Wähle im Installationsassistenten das Container-Image aus, das verwendet werden soll, um deine Anwendung zu starten, und schließe den Assistenten ab, indem du die gewünschte Konfiguration bezüglich Umgebungsvariablen, Volumes und Netzwerkports angibst.

Der interne DNS-Name deines Containers wird aus dem Namen des Containers abgeleitet. Wenn du beispielsweise einen Container mit dem Namen "Mein Container" erstellst, ist der daraus abgeleitete interne DNS-Name mein-container. Du kannst den internen DNS-Namen in der UI einsehen, nachdem der Container erstellt wurde.

Container mit Ressourcenlimits starten

Du kannst Container mit CPU- und Arbeitsspeicher-Limits starten, um die Ressourcen zu kontrollieren, die deine containerisierte Anwendung verbrauchen kann. Dies ist nützlich, um sicherzustellen, dass deine Container nicht mehr Ressourcen verbrauchen als erwartet, und um die Ressourcenzuweisung über mehrere Container hinweg zu optimieren.

Um einen Container mit Ressourcenlimits über die CLI zu starten, kannst du die Flags --cpus und --memory mit dem Befehl mw container run verwenden:

$ mw container run \
--name my-container \
--cpus 0.5 \
--memory 512m \
--env FOO=BAR \
-p 8000:8000/tcp \
my-registry/my-container:latest

Das --cpus-Flag gibt die maximale Anzahl an CPUs an, die der Container verwenden kann (z. B. 0.5 für eine halbe CPU, 2 für zwei CPUs). Das --memory-Flag gibt die maximale Menge an Arbeitsspeicher an, die der Container verwenden kann (z. B. 512m für 512 Megabyte, 1g für 1 Gigabyte).

Wenn du eine Docker Compose-kompatible Datei hast, kannst du Ressourcenlimits auch mit der standardmäßigen Docker Compose-Syntax angeben:

services:
mycontainer:
image: my-registry/my-container:latest
ports:
- "8000:8000/tcp"
environment:
FOO: BAR
deploy:
resources:
limits:
cpus: '0.5'
memory: 512m

Dann deploye den Stack mit dem Befehl mw stack deploy:

$ mw stack deploy

Weitere Informationen findest du in der Dokumentation zum mw container run Befehl.

Verwendung privater Registries

Wenn dein Container-Image aus einer privaten Registry geladen werden soll, musst du diese Registry zuerst für das jeweilige Projekt definieren. Du kannst eine Registry wie folgt erstellen:

Um eine neue Container-Registry über das mStudio zu erstellen, folge diesen Schritten:

  1. Navigiere zu dem Projekt, in dem du den Container erstellen möchtest.
  2. Wähle den Menüpunkt "Container" in der Seitenleiste aus.
  3. Wechsle zum Tab "Registries".
  4. Klicke auf die Schaltfläche "Registry hinzufügen".
  5. Konfiguriere die Registry-URL und die Anmeldeinformationen für die Registry.

Eigene, selbst-gehostete Docker-Image-Registry

Wenn keine private Registry existiert oder aus irgendeinem Grund nicht verfügbar ist, kannst du deine eigene Docker-Image-Registry im mittwald Container-Hosting hosten.

Weitere detaillierte Anweisungen und Konfigurationsoptionen findest du in dieser Anleitung.

Um eine neue Container-Registry über das mStudio zu erstellen, folge diesen Schritten:

  1. Navigiere zu dem Projekt, in dem du den Container erstellen möchtest.
  2. Wähle den Menüpunkt "Container" in der Seitenleiste aus.
  3. Klicke im geöffneten "Container"-Tab auf die Schaltfläche "Erstellen".
  4. Konfiguriere den Container nach Bedarf und verwende das Image library/registry:3.
  5. Richte Umgebungsvariablen nach deinen Wünschen ein, siehe die obige Anleitung für Details.

Die in diesem Kapitel eingerichtete Registry kann als private Registry verwendet werden. Stelle daher sicher, dass die Registry erreichbar ist, z.B. indem du eine Subdomain in deinem Projekt erstellst, die auf die eigene Registry verweist.

Eine eigene Registry könnte beispielsweise eine Domain wie docker.p-XXXXXX.project.space haben, die als Registry für zukünftige Container-Deployments konfiguriert werden kann.

Basis-Authentifizierung für selbst-gehostete Docker-Registry

Um eine Basis-Authentifizierung zu unserer Registry hinzuzufügen, müssen wir Zugangsdaten vorbereiten, die wir dann in unsere Registry deployen.

Der erste Schritt besteht darin, die Anmeldedatei lokal zu erstellen:

user@local $ mkdir -p auth
user@local $ docker run \
--entrypoint htpasswd \
httpd:2 -Bbn exampleuser examplepassword > auth/htpasswd

Dies erstellt die htpasswd-Anmeldedatei, die wir jetzt übertragen müssen.

Um die Anmeldedatei persistent zu speichern, beginnen wir mit der Erstellung eines neuen Volumes für unseren Registry-Container:

Um ein neues Container-Volume über das mStudio zu erstellen, folge diesen Schritten:

  1. Navigiere zu dem Projekt, in dem du die Registry erstellt hast.
  2. Wähle den Menüpunkt "Container" in der Seitenleiste aus und wähle dann den Registry-Container aus.
  3. Navigiere im geöffneten "Container"-Tab zum Tab "Volumes".
  4. Klicke im Tab "Volumes" auf "Erstellen".
  5. Konfiguriere den neuen Volume-Einhängepunkt auf /auth und klicke auf "Speichern".

Danach konfigurieren wir unsere Registry neu, um die neuen Basis-Authentifizierungs-Zugangsdaten zu verwenden.

Um die Konfiguration des selbst-gehosteten Registry-Containers abzuschließen, folge diesen Schritten:

  1. Navigiere zu dem Projekt, in dem du die Registry erstellt hast.
  2. Wähle den Menüpunkt "Container" in der Seitenleiste aus und wähle dann den Registry-Container aus.
  3. Navigiere im geöffneten "Container"-Tab zum Tab "Umgebungsvariablen".
  4. Verwende die Schaltfläche "Hinzufügen", um Umgebungsvariablen wie folgt zu erstellen:
REGISTRY_AUTH=htpasswd
REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm
REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd

Erstelle den Container mit den festgelegten Volumes und Umgebungsvariablen. Dann übertragen wir unsere Anmeldedatei und überschreiben die Standard-Benutzerzugangsdaten (die bei Bedarf in den Logs zu finden sind).

user@local $ mw container cp -r auth/ example-registry:/

Als letzten Schritt erstelle eine Subdomain in deinem Projekt und verweise sie auf den Registry-Container.

Um eine Subdomain in deinem Projekt hinzuzufügen und zu verlinken, folge diesen Schritten:

  1. Navigiere zu dem Projekt, in dem du die Registry erstellt hast.
  2. Wähle den Menüpunkt "Domains" in der Seitenleiste aus und klicke dann auf "Hinzufügen" -> "Subdomain".
  3. Verwende als Subdomain zum Beispiel docker.p-XXXXXX.project.space.
  4. Wähle den Registry-Container als Ziel aus und klicke auf "Erstellen".

Nachdem die Domain eingerichtet wurde, können wir mit dem Testen beginnen. Da wir die Basis-Authentifizierung konfiguriert haben, sollten wir überprüfen, ob unsere Registry diese tatsächlich verwendet. Erstelle und tagge ein beliebiges Docker-Image und pushe es dann zur neuen Registry:

user@local $ cd path/to/your/project
user@local $ docker build -t <Your Image> .
user@local $ docker tag <Your Image>:latest docker.p-XXXXXX.project.space/<Your Image>
user@local $ docker push docker.p-XXXXXX.project.space/<Your Image>:latest

Dein Push muss aufgrund fehlender Basis-Authentifizierungs-Zugangsdaten abgelehnt werden:

user@local $ docker push docker.p-XXXXXX.project.space/<Your Image>:latest
...
push access denied, repository does not exist or may require authorization: authorization failed: no basic auth credentials

Wenn es ohne Fehler funktioniert hat, ist deine Einrichtung unvollständig und keine Authentifizierung ist aktiv! Melde dich jetzt an:

user@local $ docker login docker.p-XXXXXX.project.space

Wiederhole docker push, was jetzt nach erfolgreicher Anmeldung funktioniert! Herzlichen Glückwunsch, du hast erfolgreich deine eigene private, selbst-gehostete Docker-Registry erstellt. Abhängig von deiner Projektstruktur und deinem Anwendungsfall kann eine generische Docker-Registry in einem separaten Projekt oder eine Registry pro Projekt erstellt und verwendet werden.

Deployment-Strategien

Wenn du deine Anwendung mithilfe von Containern deployst, wirst du typischerweise neue Versionen deiner Anwendung bereitstellen, indem du ein neues Container-Image erstellst und es im selben Container-Stack bereitstellst. Dies ist eine gängige Praxis in containerisierten Umgebungen, da sie eine einfache Versionierung und Rückgängigmachung ermöglicht.

Es gibt zwei Varianten dieses Ansatzes:

  1. Immutable Deployment: Jede neue Version der Anwendung wird in einem neuen Container-Image bereitgestellt, und das alte Image wird für Rollback-Zwecke aufbewahrt. Dies ist der häufigste Ansatz in containerisierten Umgebungen.
  2. Mutable Deployment: Dasselbe Container-Image (im einfachsten Fall das latest-Tag) wird für alle Versionen der Anwendung verwendet, und jede neue Version ersetzt die alte.

Beide Strategien können mit mStudio-Containern implementiert werden. Die folgenden Abschnitte beschreiben, wie man sie umsetzt.

Ein neues Tag für jedes Release pushen

Mit dieser Strategie erstellst du ein neues Container-Image für jedes Release deiner Anwendung. Mit docker-Befehlen könnte das so aussehen (das v1.0.1-Tag ist nur ein Beispiel für ein Tag, das mit jedem Release erhöht werden könnte):

docker build -t my-registry/my-container:v1.0.1 .
docker push my-registry/my-container:v1.0.1

Nachdem das Image erstellt wurde, kannst du es in deinem Container-Stack bereitstellen.

Um das Container-Image eines bestehenden Containers zu aktualisieren, verwende den Befehl mw container update:

$ mw container update \
--image my-registry/my-container:v1.0.1 \
my-container

Aktualisieren eines veränderlichen Tags

Mit dieser Strategie wirst du typischerweise immer wieder dasselbe Container-Image-Tag aktualisieren. Mit docker-Befehlen könnte das so aussehen:

docker build -t my-registry/my-container:latest .
docker push my-registry/my-container:latest

Standardmäßig werden Container-Images nicht automatisch aktualisiert, wenn das Image-Tag nicht geändert wird. Du kannst die POST/v2/stacks/{stackId}/services/{serviceId}/actions/pull/-Operation oder den CLI-Befehl mw container recreate --pull verwenden, um das neueste Image für den Container-Stack zu ziehen. Dies wird das Image-Tag auf die neueste Version aktualisieren.

Verwendung von Volumes

Um persistente Daten in deiner containerisierten Anwendung zu verwalten, kannst du Volumes verwenden. Volumes sind eine Möglichkeit, Daten außerhalb des Containers zu speichern, sodass sie nicht verloren gehen, wenn der Container gestoppt oder entfernt wird.

Du kannst zwei verschiedene Arten von Volumes verwenden:

  1. Das Projekt-Volume ist ein Volume, das für jedes Projekt erstellt wird und von allen Containern und allen Managed Apps in diesem Projekt zugänglich ist. Dies ist nützlich, um Daten zwischen Containern und Apps zu teilen.
  2. Du kannst auch Volumes als Teil eines Stacks deklarieren. Diese sind an den Container-Stack gebunden und von anderen Stacks nicht zugänglich. Dies ist nützlich, um Daten zu speichern, die nur von einem bestimmten Container-Stack benötigt werden.

Verwendung des Projekt-Volumes

Um das Projekt-Volume zu verwenden, verwende eine Volume-Deklaration wie diese:

PUT /v2/stacks/{stackId} HTTP/1.1
Host: api.mittwald.de
Content-Type: application/json

{
"services": {
"mycontainer": {
"image": "my-registry/my-container:v1.0.1",
"volumes": [
"/home/p-XXXXX/html:/var/www"
]
}
}
}
See full request reference at: PUT/v2/stacks/{stackId}/

Deklarieren von Volumes in Stacks

Um ein Volume innerhalb des Stacks zu deklarieren, definiere deinen Container wie folgt:

PUT /v2/stacks/{stackId} HTTP/1.1
Host: api.mittwald.de
Content-Type: application/json

{
"services": {
"mycontainer": {
"image": "my-registry/my-container:v1.0.1",
"volumes": [
"myvolume:/var/www"
]
}
},
"volumes": {
"myvolume": {}
}
}
See full request reference at: PUT/v2/stacks/{stackId}/

Backup & Wiederherstellung

Alle Volumes (sowohl Projekt-Volumes als auch Stack-Volumes) werden automatisch als Teil des Projekt-Backups gesichert. Das bedeutet, dass du deine Daten im Falle eines Ausfalls oder Datenverlusts wiederherstellen kannst.

Aber, ein einfaches Dateisystem-Backup ist möglicherweise nicht für alle Anwendungs-Workloads ausreichend. Wenn deine Anwendung beispielsweise eine Datenbank verwendet, solltest du sicherstellen, dass die Datenbank sich in einem konsistenten Zustand befindet, bevor du ein Backup machst. Dies kann durch die Verwendung der integrierten Backup-Funktionalität der Datenbank oder durch die Verwendung einer Drittanbieter-Backup-Lösung erfolgen.

Netzwerkverbindung zwischen Containern und Apps

Managed Apps und Container sind mit demselben Netzwerk verbunden. Das bedeutet, dass du auf Apps von deinen Containern und umgekehrt zugreifen kannst. Der Hostname des Containers ist der Schlüssel des Containers in der Stack-Definition; wenn du den Container über die UI erstellt hast, wird der Hostname aus dem Namen des Containers abgeleitet. Wenn du beispielsweise einen Container mit dem Namen Mein Container erstellst, wird der interne DNS-Name mein-container sein. Du kannst den internen DNS-Namen in der UI einsehen, nachdem der Container erstellt wurde.

Um einen Containerport von innerhalb deines Projekts zugänglich zu machen, kannst du die ports-Eigenschaft in der Container-Deklaration verwenden. Das erstellt eine Portzuordnung zwischen dem Containerport und dem per DNS ansprechbaren Service, auf den du aus dem Rest deiner Hosting-Umgebung zugreifen kannst. Um beispielsweise den Port 80 des Containers für andere Workloads, die im selben Projekt laufen (sei es andere Container oder verwaltete Apps), zugänglich zu machen, kannst du die folgende Deklaration verwenden:

PUT /v2/stacks/{stackId} HTTP/1.1
Host: api.mittwald.de
Content-Type: application/json

{
"services": {
"mycontainer": {
"image": "my-registry/my-container:latest",
"ports": [
"80:80/tcp"
]
}
}
}
See full request reference at: PUT/v2/stacks/{stackId}/

Container über HTTP aus dem Internet zugänglich machen

Um einen Container-HTTP-Port aus dem Internet zugänglich zu machen, musst du eine Ingress-Ressource definieren, die auf den gegebenen Container verweist.

Um eine Ingress-Ressource mit einem Container zu verknüpfen, benutze den mw domain virtualhost create-Befehl mit dem --path-to-container-Flag:

mw domain virtualhost create --hostname domain.example --path-to-container /:[container-uid]:80/tcp

Das --path-to-container-Flag sollte drei Werte enthalten, getrennt durch Doppelpunkte:

  1. Der URL-Pfad, der auf den Container verweist.
  2. Die Container-ID.
  3. Der Port (im Format portnummer/protokoll, also beispielsweise 80/tcp), auf dem der Container lauscht.