it-swarm.com.de

Best Practice für die Aktualisierung von AWS ECS-Serviceaufgaben

Ich versuche gerade, ein einfaches CI einzurichten, das mein Projekt neu aufbaut, ein neues Docker-Image erstellt, das neue Image in ein Amazon-Ecr-Repo pushen, eine neue Revision einer vorhandenen Aufgabendefinition mit dem neuesten Docker-Image erstellen und aktualisieren Dienst mit der neuen Revision der Aufgabendefinition ausführen und schließlich die bestehende Task mit der alten Revision beenden und mit der neuen Revision starten.

Alles funktioniert gut, außer die neue Revision der Aufgabe zu starten.

Der letzte Befehl, den ich anrufe, lautet:

aws ecs update-service --cluster "$CLUSTER" --service "$SERVICE" --task-definition "$TASK_DEFINITION":"$REVISION"

Dies führt zu einem Ereignisfehler von:

(service rj-api-service) was unable to place a task because no container instance met all of its requirements. The closest matching (container-instance bbbc23d5-1a09-45e7-b344-e68cc408e683) is already using a port required by your task.

Das macht Sinn, da der Container, den ich ersetze, genau derselbe ist wie der neue und auf demselben Port ausgeführt wird. Er enthält nur die neueste Version meiner Anwendung.

Ich hatte den Eindruck, der update-service-Befehl würde die vorhandene Aufgabe stoppen und die neue starten, aber es sieht so aus, als ob sie zuerst die neue startet, und wenn sie erfolgreich ist, wird die alte beendet.

Was ist die beste Vorgehensweise, um damit umzugehen? Soll ich die alte Aufgabe zuerst beenden? Soll ich den Dienst zuerst in meinem Skript löschen und den gesamten Dienst bei jedem Update neu erstellen?

Momentan brauche ich nur eine Instanz der Aufgabe, aber ich möchte mich nicht selbst einschließen, wenn ich dies für die automatische Skalierung auf mehrere Instanzen benötige. Irgendwelche Vorschläge, wie man dies am besten angehen kann?

19
on3al

Die Meldung, die Sie erhalten, ist, dass ECS versucht, eine blau-grüne Bereitstellung durchzuführen. Dies bedeutet, dass versucht wird, Ihre neue Aufgabenversion zuzuordnen, ohne die aktuelle Aufgabe zu stoppen, um Ausfallzeiten in Ihrem Service zu vermeiden. Sobald die neueste Aufgabe fertig ist (stabiler Zustand), wird die alte endgültig entfernt. 

Das Problem bei dieser Art der Bereitstellung ist, dass Sie über ausreichend free resources in Ihrem Cluster verfügen müssen, um die zwei (alten und neuen) Aufgaben für einen bestimmten Zeitraum aufrechtzuerhalten und auszuführen. Wenn Sie beispielsweise eine Task mit 2 GB Arbeitsspeicher und 2 CPUs bereitstellen, muss Ihr Cluster über diese Menge an freien Ressourcen verfügen, um den Dienst mit einer neuen Taskversion aktualisieren zu können. 

Sie haben 2 Möglichkeiten:

  1. Skalieren Sie Ihren Cluster, indem Sie eine neue EC2-Instanz hinzufügen, sodass Sie über genügend freie Ressourcen verfügen und die Bereitstellung durchführen können.
  2. Ändern Sie Ihre Servicekonfiguration, um keine blau-grüne Bereitstellung durchzuführen (nur 1 Task gleichzeitig in Ihrem Cluster zulassen).

Um Option Nummer 2 auszuführen, müssen Sie nur die folgenden Werte festlegen:

  • Minimun gesunder Prozentsatz: 0
  • Maximale Prozent: 100

Beispiel

 Example

Dies bedeutet, dass Sie nur 100% Ihrer gewünschten Aufgaben ausführen möchten (und nicht mehr!) Und dass Sie bereit sind, Ausfallzeiten zu verursachen, während Sie eine neue Version bereitstellen (0% des fehlerfreien Diensts).

In dem Beispiel gehe ich davon aus, dass Sie nur eine gewünschte Aufgabe wünschen, die Werte für Minimun prozentualer Prozentsatz und Maximun-Prozentsatz funktionieren jedoch für jede gewünschte Anzahl von gewünschten Aufgaben.

Ich hoffe es hilft! Lassen Sie mich wissen, wenn Sie weitere Zweifel haben.

21
Fabian Rivera

Sie können die neue Revision von Aufgaben mit den folgenden Schritten unter Verwendung eines Shell-Skripts in Ihrer Build-Umgebung starten.

  1. Speichern Sie die task definition json template in Ihrer Build-Umgebung in einer Datei (zum Beispiel ist die Vorlagendatei web-server.json und die Taskdefinitionsfamilie web-server).

  2. Verwenden Sie das Dateiverzeichnis als aktuelles Verzeichnis und führen Sie die Definition der Registeraufgabe aus (passiert beim ersten Durchlauf, falls nicht vorhanden).

    aws ecs register-task-definition --cli-input-json file://web-server.json

  3. Ruft die laufende Task-ID (TASK_ID) für eine Variable im Shell-Skript ab.

    TASK_ID=`aws ecs list-tasks --cluster default --desired-status RUNNING --family web-server | egrep "task" | tr "/" " " | tr "[" " " | awk '{print $2}' | sed 's/"$//'`

  4. Rufen Sie die Taskversion (TASK_REVISION) für Variablen im Shell-Skript ab.

    TASK_REVISION=`aws ecs describe-task-definition --task-definition web-server | egrep "revision" | tr "/" " " | awk '{print $2}' | sed 's/"$//'`

  5. Stoppen Sie die Ausführung der aktuellen Aufgabe

    aws ecs stop-task --cluster default --task ${TASK_ID}

  6. Starten Sie sofort eine neue Aufgabe

    aws ecs update-service --cluster default --service web-server --task-definition web-server:${TASK_REVISION} --desired-count 1

Als bewährte Methode können Sie die Anzahl der gewünschten Werte für zwei Aufgaben (zwei Aufgaben, die im Service ausgeführt werden) mindestens beibehalten und Aktualisierungen (jeweils eine Aufgabe aktualisieren) durchführen, indem Sie das folgende Skript (Erweiterung der obigen Schritte für mehrere Container) mit Null verwenden Ausfallzeit (Stellen Sie sicher, dass Sie nach den ersten Containeraktualisierungen ausreichend Zeit einhalten, z. B. den Ruhezustand 30, um neue Anforderungen annehmen zu können).

cd /<directory-containing-web-server.json>
aws ecs register-task-definition --cli-input-json file://web-server.json
OLD_TASK_ID=`aws ecs list-tasks --cluster default --desired-status RUNNING --family web-server | egrep "task" | tr "/" " " | tr "[" " " |  awk '{print $2}' | sed 's/"$//'`

TASK_REVISION=`aws ecs describe-task-definition --task-definition web-server | egrep "revision" | tr "/" " " | awk '{print $2}' | sed 's/"$//'`
aws ecs stop-task --cluster default --task ${OLD_TASK_ID}

OLD_TASK_ID=`aws ecs list-tasks --cluster default --desired-status RUNNING --family web-server | egrep "task" | tr "/" " " | tr "[" " " |  awk '{print $2}' | sed 's/"$//'`
aws ecs update-service --cluster default --service web-server --task-definition web-server:${TASK_REVISION} --desired-count 1

sleep 30
aws ecs stop-task --task ${OLD_TASK_ID}
aws ecs update-service --cluster default --service web-server --task-definition web-server:${TASK_REVISION} --desired-count 2

Hinweis: Sie müssen die Aufgabendefinitionsfamilie, die Anzahl der gewünschten Instanzen und die Vorlagendefinitionsvorlage entsprechend konfigurieren.

2
Ashan

So aktualisieren Sie eine Aufgabendefinition in den im Dienst ausgeführten "Aufgaben" Sie müssen die Aufgaben löschen und eine neue Aufgabe starten.

Auf diese Weise löse ich das Problem der Aktualisierung der Aufgabendefinition in Aufgaben

Ich habe folgenden Code geschrieben:

    # Register a new Task definition 
    aws ecs register-task-definition --family testing-cluster --cli-input-json file://scripts/taskdefinition/testingtaskdef.json --region $AWS_REGION

    # Update Service in the Cluster
    aws ecs update-service --cluster $CLUSTER_NAME --service $SERVICE --task-definition testing-cluster --desired-count 1 --region $AWS_REGION 



    DECRIBED_SERVICE=$(aws ecs describe-services --region $AWS_REGION --cluster $CLUSTER_NAME --services $SERVICE);
    CURRENT_DESIRED_COUNT=$(echo $DECRIBED_SERVICE | jq --raw-output ".services[0].desiredCount")
    #    - echo $CURRENT_DESIRED_COUNT

    CURRENT_TASK_REVISION=$(echo $DECRIBED_SERVICE | jq -r ".services[0].taskDefinition")
    echo "Current Task definition in Service" + $CURRENT_TASK_REVISION

    CURRENT_RUNNING_TASK=$(echo $DECRIBED_SERVICE | jq -r ".services[0].runningCount")
    echo $CURRENT_RUNNING_TASK

    CURRENT_STALE_TASK=$(echo $DECRIBED_SERVICE | jq -r ".services[0].deployments | .[] | select(.taskDefinition != \"$CURRENT_TASK_REVISION\") | .taskDefinition")
    echo "Task defn apart from current service Taskdefn" +  $CURRENT_STALE_TASK
    #   - echo $CURRENT_STALE_TASK

    tasks=$(aws ecs --region $AWS_REGION list-tasks --cluster $CLUSTER_NAME | jq -r '.taskArns | map(.[40:]) | reduce .[] as $item (""; . + $item + " ")')
    echo "Tasks are as follows" 
    echo $tasks
    TASKS=$(aws ecs --region $AWS_REGION describe-tasks --cluster $CLUSTER_NAME --task $tasks);
    #    - echo $TASKS
    OLDER_TASK=$(echo $TASKS | jq -r ".tasks[] | select(.taskDefinitionArn!= \"$CURRENT_TASK_REVISION\") | .taskArn | split(\"/\") | .[1] ")
    echo "Older Task running  " + $OLDER_TASK
    for old_task in $OLDER_TASK; do
        aws ecs --region us-east-1 stop-task --cluster $CLUSTER_NAME --task $old_task
    done    

    # Run new tasks with the updated new Task-definition
    aws ecs --region $AWS_REGION run-task --cluster $CLUSTER_NAME --task-definition $CURRENT_TASK_REVISION
1
Roopa

Verwenden Sie -> AWS CLI

Rufe OLD_TASK_ID ab

aws ecs list-tasks --cluster ${ecsClusterName} --desired-status RUNNING --family ${nameTaskDefinition} | egrep "task/" | sed -E "s/.*task\/(.*)\"/\1/"

Stoppen Sie die Aufgabe

aws ecs stop-task --cluster ${ecsClusterName} --task ${OLD_TASK_ID}

Aktualisieren Sie den ECS-Service

aws ecs update-service --cluster ${ecsClusterName} --service ${nameService} --task-definition ${nameTaskDefinition}:${version} --desired-count 1 --force-new-deployment
0
user3740244

Also muss ich jetzt arbeiten.

Nachdem ich aws ecs update service mit der neuen Aufgabendefinition aufgerufen habe, rufe ich aws ecs list-tasks auf und führe dann 'aws stop task' für jede ausgeführte Aufgabe für den Dienst aus. Da die gewünschte Anzahl für den Dienst 1 ist, versucht er sofort, die Aufgaben zu starten, und verwendet die neue Dienstdefinition.

Das ist nicht sehr hübsch, aber es scheint gut genug zu funktionieren.

0
on3al