Aktualisieren Sie den Container eines Dienstes in Amazon ECS

32

Welche Vorgehensweise wird zum Aktualisieren des Containers eines Dienstes empfohlen, der in Amazon ECS ausgeführt wird?

In der AWS-Dokumentation heißt es: "Wenn Sie das Docker-Image Ihrer Anwendung aktualisiert haben, können Sie eine neue Aufgabendefinition mit diesem Image erstellen und es für jeden Dienst einzeln bereitstellen." Dies ist so ziemlich alles, was derzeit in der Dokumentation verfügbar ist (13. April 2015).

Habe ich richtig verstanden, dass die einzige Möglichkeit zum Aktualisieren meines Anwendungscontainers in Amazon ECS darin besteht, eine neue Aufgabe zu erstellen, die alte Aufgabe zu beenden und die neue Aufgabe zu starten?

Ich habe erfolgreich einen Tag "latest" mit Core OS & Fleetctl verwendet. Dies hat den Vorteil, dass das Tag des Docker-Images für neue Updates nicht geändert werden muss, da beim erneuten Laden des Dienstes neue Änderungen angezeigt werden und der Container aktualisiert wird (mit demselben Tag "latest").

Welche Ansätze haben Sie zum Aktualisieren Ihres Dienstes mit einem aktualisierten Docker-Image in Amazon ECS verwendet?

Petrus Repo
quelle
Versuchen Sie auch, dies herauszufinden, da wir hoffen, ECS für die Bereitstellung einer Vielzahl von Daemons zu verwenden, die kontinuierlich in der Produktion ausgeführt werden müssen.
Parent5446
1
Zur Bestätigung haben Sie gesagt, dass beim Neustart eines ecs-Dienstes die neueste Version eines Images heruntergeladen wird. Ich habe nach Dokumentation dafür gesucht und kann sie nirgendwo finden.
MMILLERUVA
1
Gibt es eine Bestätigung dazu?
Lior Ohana
@ LiorOhana Leider ist es wahr. Siehe meine Antwort für Details.
hamx0r
Ich habe unten eine neue ausführliche Antwort gepostet, aber um dies zu verdeutlichen: Ihr Service wird immer versuchen, eine neue Kopie Ihres Containers aus dem Repo zu ziehen, basierend auf dem von Ihnen festgelegten Tag. Wenn eine Aufgabe beendet wird und der Dienst sie erneut bereitstellt, kann er sich nicht daran erinnern, was sich im Repo befand , sondern nur daran, was sich im Repo befindet.
MrDuk

Antworten:

18

Ich bin mir nicht sicher, ob dies als aufgegebene Frage angesehen wird. Ich bin auf diese Frage gestoßen, als ich mein Problem behebte und meine Lösung jetzt hinzufügte, da sie behoben ist.

Um den Dienst mit einem neuen Container zu aktualisieren, müssen Sie:

  1. Neuen Container in das Repository hochladen;
  2. Aktualisierung der Aufgabendefinition auslösen;
  3. Container-Update auslösen;
  4. Wichtig: Stellen Sie sicher, dass die Dienstregeln das Starten einer neuen Version der Aufgabe ermöglichen.

Wenn die Serviceaufgabe nicht auf die neueste Version aktualisiert wurde, überprüfen Sie die Registerkarte "Ereignisse" auf Fehler. Beispielsweise konnte ECS möglicherweise keine neue Version Ihres Dienstes starten: Sie haben nur eine ec2-Instanz im Cluster und der Anwendungsport wird bereits auf dem Host verwendet. In diesem Fall setzen Sie die Grenzwerte für "min health / max health" auf "0%, 100%". Auf diese Weise entscheidet sich ECS, den alten Container zu töten, bevor ein neuer bereitgestellt wird. Dies geschieht auch innerhalb weniger Minuten. Beeilen Sie sich nicht, wenn Sie keine unmittelbare Rückmeldung erhalten.

Unten finden Sie ein Beispiel für ein Bereitstellungsskript zum Aktualisieren des Containers in einem vorkonfigurierten Cluster und Dienst. Beachten Sie, dass Sie keine Versionen angeben müssen, wenn Sie nur "Neueste aus der Familie verwenden" meinen.

awsRegion=us-east-1
containerName=..
containerRepository=..
taskDefinitionFile=...
taskDefinitionName=...
serviceName=...


echo 'build docker image...'
docker build -t $containerName .

echo 'upload docker image...'
docker tag $containerName:latest $containerRepository:$containerName
docker push $containerRepository:$containerName

echo 'update task definition...'
aws ecs register-task-definition --cli-input-json file://$taskDefinitionFile --region $awsRegion > /dev/null

echo 'update our service with that last task..'
aws ecs update-service --service $serviceName --task-definition $taskDefinitionName --region $awsRegion  > /dev/null
Uiron
quelle
2
Dies zwingt mich, eine Aufgabendefinition als Datei lokal zu haben. Wenn ich das richtig verstehe, ist dies der einzige Ort, an dem ich Umgebungsvariablen definieren kann. Gibt es eine Möglichkeit, dies zu tun, ohne die Umgebungsvariablen lokal zu haben? Idealerweise möchte ich einen Befehl ausgeben, um auf ein neues Docker-Image-Tag zu verweisen, ohne andere Informationen über die Aufgabe / den Dienst / den Container / usw. Zu senden.
rmac
1
Die Kommentare zu set "min health/max health" limits to "0%, 100%"ist golden. Ich danke dir sehr!
Sivabudh
1
Ein Wort der Warnung hier, wenn Sie setzen Ihr minzu 0%, wenn Sie die Aufgabendefinition Ihren Dienst entfaltet ändern, werden Sie es im Wesentlichen die volle Autorität geben zu Fall zu bringen , alle für diesen Bereitstellungsaufgaben zur gleichen Zeit.
MrDuk
1

Ich verwende einen Teil des ecs-deploy-Skripts mit meinen Verbesserungen (es nimmt Bilder aus jeder Containerbeschreibung und ersetzt den Tag-Teil durch $ TAG_PURE): https://gist.github.com/Forever-Young/e939d9cc41bc7a105cdcf8cd7ab9d714

# based on ecs-deploy script
TASK_DEFINITION_NAME=$(aws ecs describe-services --services $SERVICE --cluster $CLUSTER | jq -r .services[0].taskDefinition)
TASK_DEFINITION=$(aws ecs describe-task-definition --task-def "$TASK_DEFINITION_NAME" | jq '.taskDefinition')
NEW_CONTAINER_DEFINITIONS=$(echo "$TASK_DEFINITION" | jq --arg NEW_TAG $TAG_PURE 'def replace_tag: if . | test("[a-zA-Z0-9.]+/[a-zA-Z0-9]+:[a-zA-Z0-9]+") then sub("(?<s>[a-zA-Z0-9.]+/[a-zA-Z0-9]+:)[a-zA-Z0-9]+"; "\(.s)" + $NEW_TAG) else . end ; .containerDefinitions | [.[] | .+{image: .image | replace_tag}]')
TASK_DEFINITION=$(echo "$TASK_DEFINITION" | jq ".+{containerDefinitions: $NEW_CONTAINER_DEFINITIONS}")
# Default JQ filter for new task definition
NEW_DEF_JQ_FILTER="family: .family, volumes: .volumes, containerDefinitions: .containerDefinitions"
# Some options in task definition should only be included in new definition if present in
# current definition. If found in current definition, append to JQ filter.
CONDITIONAL_OPTIONS=(networkMode taskRoleArn)
for i in "${CONDITIONAL_OPTIONS[@]}"; do
  re=".*${i}.*"
  if [[ "$TASK_DEFINITION" =~ $re ]]; then
    NEW_DEF_JQ_FILTER="${NEW_DEF_JQ_FILTER}, ${i}: .${i}"
  fi
done

# Build new DEF with jq filter
NEW_DEF=$(echo $TASK_DEFINITION | jq "{${NEW_DEF_JQ_FILTER}}")
NEW_TASKDEF=`aws ecs register-task-definition --cli-input-json "$NEW_DEF" | jq -r .taskDefinition.taskDefinitionArn`

echo "New task definition registered, $NEW_TASKDEF"

aws ecs update-service --cluster $CLUSTER --service $SERVICE --task-definition "$NEW_TASKDEF" > /dev/null

echo "Service updated"
Für immer jung
quelle
Es wird empfohlen, die nützlichen Informationen aus Links in Ihrer Antwort bereitzustellen, um link-rot bereitzustellen. Könnten Sie das bitte tun?
BE77Y
1
Meine Antwort wurde aktualisiert
ForeverYoung
1

Nachdem Sie ein neues Docker-Image hochgeladen haben, müssen Sie, selbst wenn es dasselbe Tag wie ein von einer Aufgabe verwendetes aufweist, die neueste Aufgabe kopieren und den Dienst für die Verwendung dieser neuen Aufgabe konfigurieren. Optional können Sie einfach zwei Aufgaben duplizieren und den Dienst so konfigurieren, dass er bei jeder Aktualisierung des Docker-Image zwischen ihnen wechselt.

Damit ein neuer Docker-Container von ECS erstellt werden kann, muss er durch eine Aktualisierung des Dienstes ausgelöst werden. Der Service kann nur ausgelöst werden, indem er auf eine bestimmte Weise aktualisiert wird, z andere Aufgabennummer.

Beachten Sie, dass vorhandene Container möglicherweise nicht automatisch gestoppt werden, nur weil der Dienst aktualisiert wurde. Möglicherweise müssen Sie Ihre Aufgabenliste einsehen und sie manuell stoppen.

hamx0r
quelle
Dies ist nicht der Fall - Sie können eine Aufgabe immer manuell beenden, anstatt sich auf Ihren Dienst zu verlassen. Wenn der Dienst feststellt, dass er getötet wurde, versucht er, ihn erneut tag
aufzurufen
1

Der Ansatz, der für mich funktioniert, ist ähnlich wie oben. Bearbeiten Sie nach dem Erstellen Ihres Dienstes und Ihrer Aufgabe und dem Starten aller Funktionen die Auto-Scaling-Gruppe und stellen Sie sicher , dass min , max und desired auf 1 gesetzt sind .

Die Gruppe kann die Standardgruppe sein. Wenn Sie sich nicht sicher sind, können Sie auf die Registerkarte ECS-Instanzen in Ihrem Cluster zugreifen. Wählen Sie dann in der Dropdown- Liste Aktionen die Option Clusterressourcen aus und klicken Sie auf den Link unten im Dialogfeld, das geöffnet wird.

Wenn dies erledigt ist, wechseln Sie zu jedem Zeitpunkt, an dem Sie ein aktualisiertes Container-Image bereitstellen möchten, in den Aufgabenbereich des Clusters und beenden Sie die Aufgabe . Sie erhalten eine Warnung, aber wenn die automatische Skalierung eingerichtet ist, wird der Dienst mit dem letzten Push wieder gestartet.

Es müssen weder für den Dienst noch für die Aufgabe neue Versionen erstellt werden.

Beachten Sie, dass sich der Dienst / die Aufgabe von sofort auf ungefähr eine Minute aktualisiert. Wenn Sie verzweifelt warten müssen, können Sie die neue Aufgabe einfach manuell ausführen. Der Service wird es nicht besitzen, also ist es nicht ideal, aber es wird immer noch ein neues hochfahren, wenn es stirbt.

K Cartlidge
quelle
1

Ich weiß, dass dies ein alter Thread ist, aber die Lösung ist viel einfacher, als die meisten Antworten hier vermuten lassen.

So aktualisieren Sie den laufenden Container in zwei Schritten:

Im Folgenden wird davon ausgegangen, dass ein Dienst eine Aufgabe latestausführt, die auf einen Container mit Tags verweist (oder auf ein anderes statisches Tag, das sich nicht auf Containeraktualisierungen bezieht).

  1. Laden Sie Ihren neuen Container in das Repository hoch
  2. Töte deine Aufgaben manuell

Wenn es unser Ziel ist, ein neues Gebäude in die Wildnis zu bringen, müssen wir uns nicht wirklich auf unseren Service verlassen (und ich würde argumentieren, wir sollten uns nicht darauf verlassen). Wenn Sie Ihre Aufgabe beenden, erkennt der Dienst, dass keine Desired CountAufgaben ausgeführt werden, und startet einfach eine neue Aufgabe. Dies löst ein erneutes Ziehen Ihres Containers basierend auf demselben Tag aus.

ECS-Dienste sind ein HA-Sicherheitsnetz und kein Ersatz für Ihre CD / CI-Pipeline.


Bonus: Wenn das Ziel ist, dass ein Dienst erkennt, dass ein neuer Container verschoben wurde (unabhängig von Tags), müssen wir die Auswirkungen berücksichtigen. Wollen wir wirklich einen Basisdienst, der unsere Bereitstellungspipeline für uns steuert? Wahrscheinlich nicht. Im Idealfall werden Sie Ihre Container mit verschiedenen Tags versehen (basierend auf Release-Versionen oder Ähnlichem). In diesem Fall besteht das Hindernis für die Bereitstellung darin, dass der Dienst über etwas Neues informiert werden muss - wiederum ist dies ein Sicherheitsnetz für den Dienst und nicht mehr.


So stellen Sie neue Tags in drei Schritten bereit:

  1. Laden Sie Ihr neues container:tagin das Repository hoch
  2. Erstellen Sie eine neue Aufgabendefinition, die auf die neue verweist tag
  3. Aktualisieren Sie Ihren Service, um auf die neue Aufgabendefinition zu verweisen
    • Vorsicht hier! Wenn Sie minimum healthyfestlegen , 0%wie einige andere Antworten vorschlagen, sind Sie AWS volle Autorität geben Ihren gesamten Service zu töten , um die neue Aufgabendefinition zu implementieren. Wenn Sie eine fortlaufende / schrittweise Bereitstellung bevorzugen, stellen Sie Ihr Minimum auf etwas ein >0%.
    • Stellen Sie alternativ " minimum healthyto" 100%und "your maximum healthyto" so ein >100%, dass Ihr Dienst die neuen Aufgaben bereitstellen kann, bevor die alten beendet werden (um die Auswirkungen auf Ihre Benutzer zu minimieren).

Ab diesem Zeitpunkt erkennt Ihr Service automatisch, dass Sie eine neue Aufgabe angegeben haben, und arbeitet daran, diese Aufgabe basierend auf den von Ihnen konfigurierten Schwellenwerten für minimum/ funktionsfähig bereitzustellen maximum.

MrDuk
quelle
Schön, danke, besser als andere Antworten
Olegzandr Denman