Quel type d'approche est recommandé pour mettre à jour le conteneur d'un service qui s'exécute dans Amazon ECS?
documentation AWS indique: "Si vous avez mis à jour l'image Docker de votre application, vous pouvez créer une nouvelle définition de tâche avec cette image et la déployer sur votre service, une tâche à la fois." C'est à peu près tout ce qui est actuellement disponible dans la documentation actuellement (13 avril 2015).
Ai-je bien compris que la seule façon de mettre à jour mon conteneur d'applications dans Amazon ECS est de créer une nouvelle tâche, puis d'arrêter l'ancienne tâche et de démarrer la nouvelle tâche?
J'ai utilisé avec succès une balise "latest" avec Core OS & Fleetctl. Cela a l'avantage de ne pas avoir besoin de changer la balise de l'image Docker pour les nouvelles mises à jour, car le rechargement du service verra de nouvelles modifications et mettra à jour le conteneur (en utilisant la même balise "latest").
Quel type d'approches avez-vous utilisé pour mettre à jour votre service avec une image Docker mise à jour dans Amazon ECS?
Je ne sais pas si cela est considéré comme une question abandonnée - suis tombé dessus tout en résolvant mon problème et en ajoutant maintenant ma solution maintenant qu'elle est résolue.
Pour mettre à jour le service avec un nouveau conteneur, vous devez:
Si la tâche de service n'est pas mise à jour vers la dernière version, vérifiez l'onglet "événements" pour les erreurs. Par exemple, ECS n'a peut-être pas pu démarrer une nouvelle version de votre service: vous n'avez qu'une seule instance ec2 dans le cluster et le port d'application est déjà utilisé sur l'hôte. Dans ce cas, définissez les limites "min health/max health" sur "0%, 100%" - de cette façon, ECS choisira de supprimer l'ancien conteneur avant d'en déployer un nouveau. Cela se produit également en quelques minutes - ne vous précipitez pas si vous ne voyez pas de rétroaction immédiate.
Voici un exemple de script de déploiement pour mettre à jour le conteneur dans un cluster et un service préconfigurés. Notez qu'il n'est pas nécessaire de spécifier les versions si vous voulez simplement dire "utiliser les dernières versions de la famille".
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
Pour mettre à jour votre application, mettez à jour la définition de tâche, puis mettez à jour le service. Voir http://docs.aws.Amazon.com/AmazonECS/latest/developerguide/update-service.html
Je sais que c'est un vieux fil de discussion, mais la solution est beaucoup plus facile que la plupart des réponses ici ne semblent l'être.
Ce qui suit suppose que vous disposez d'un service exécutant une tâche qui fait référence à un conteneur marqué latest
(ou à toute autre balise statique qui ne change pas entre les mises à jour du conteneur).
Si l'objectif est que nous obtenions une nouvelle construction dans la nature, nous n'avons pas vraiment besoin de compter sur notre service pour cela (et je dirais que nous ne devrions pas comptez dessus). Si vous tuez votre tâche, le service reconnaîtra qu'il n'a pas le Desired Count
des tâches en cours d'exécution et simplement en créer une nouvelle. Cela déclenchera une nouvelle extraction de votre conteneur, basée sur la même balise.
Les services ECS sont un filet de sécurité HA, pas un remplacement pour votre pipeline CD/CI.
Bonus: Si l'objectif est qu'un service reconnaisse qu'un nouveau conteneur a été poussé (indépendamment des balises), nous devons considérer les implications de cela. Voulons-nous vraiment un service de base contrôlant notre pipeline de déploiement pour nous? Probablement pas. Idéalement, vous pousserez vos conteneurs avec différentes balises (en fonction des versions de sortie ou quelque chose). Dans ce cas, l'obstacle au déploiement est que le service doit être informé de quelque chose de nouveau - encore une fois, c'est un filet de sécurité pour le service, et rien de plus.
container:tag
vers le référentieltag
minimum healthy
mis à 0%
comme le suggèrent d'autres réponses, vous donnez à AWS le pouvoir de supprimer l'intégralité de votre service afin de déployer la nouvelle définition de tâche. Si vous préférez un déploiement progressif/progressif, définissez votre minimum sur quelque chose >0%
.minimum healthy
à 100%
et ton maximum healthy
de quelque chose >100%
pour permettre à votre service de déployer les nouvelles tâches avant de tuer les anciennes (en minimisant l'impact sur vos utilisateurs).À partir de ce moment, votre service reconnaîtra automatiquement que vous avez spécifié une nouvelle tâche et travaillera à son déploiement en fonction des seuils sains minimum
/maximum
que vous avez configurés.
J'utilise une partie de script ecs-deploy avec mes améliorations (il prend des images de chaque description de conteneur et remplace sa partie balise par $ 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"
Après avoir téléchargé une nouvelle image Docker, même si elle a la même balise que celle utilisée par une tâche, il faut copier la dernière tâche, puis configurer le service pour utiliser cette nouvelle tâche. Facultativement, on pourrait simplement avoir 2 tâches en double et configurer le service pour permuter entre elles chaque fois que l'image Docker est mise à jour.
Fondamentalement, pour provoquer la création d'un nouveau Docker Container par ECS, une mise à jour du service doit le déclencher, et la seule façon de faire le déclencheur de service est de le mettre à jour d'une manière ou d'une autre - comme en lui disant d'utiliser un numéro de tâche différent.
Notez que les conteneurs en cours d'exécution peuvent ne pas s'arrêter automatiquement simplement parce que le service a été mis à jour - vous devrez peut-être consulter votre liste de tâches et les arrêter manuellement.
L'approche qui fonctionne pour moi est similaire à la précédente. Après avoir créé votre service et votre tâche, et commencé tout ce qui se passe, modifiez le Auto-Scaling Group et assurez-vous min , max et souhaité sont définis sur 1.
Le groupe peut être celui par défaut; si vous n'êtes pas sûr, vous pouvez y accéder en sélectionnant l'onglet Instances ECS dans votre cluster, puis à partir de Dans la liste déroulante Actions , choisissez Ressources de cluster et cliquez sur le lien en bas de la boîte de dialogue qui s'ouvre.
Lorsque tout est en place, chaque fois que vous souhaitez déployer une image de conteneur mise à jour, accédez à la zone Tâche du cluster et Arrêtez la tâche. Vous recevrez un avertissement, mais à condition que la mise à l'échelle automatique soit configurée, le service recommencera à fonctionner avec la dernière Push.
Pas besoin de créer de nouvelles versions du service ou de la tâche.
Notez que le service/la tâche se met à jour instantanément à une minute environ. Si vous obtenez une attente désespérée, vous pouvez simplement exécuter une nouvelle tâche manuellement. Le service ne le possédera pas, il n'est donc pas idéal, mais il en fera toujours un nouveau s'il meurt.
Vous pouvez utiliser --force-new-deployment
option sur ecs update-service
appel api. Il n'est pas nécessaire d'avoir une mise à jour pour le service lui-même. De docs :
Indique s'il faut forcer un nouveau déploiement du service. Les déploiements ne sont pas forcés par défaut. Vous pouvez utiliser cette option pour déclencher un nouveau déploiement sans modification de la définition de service. Par exemple, vous pouvez mettre à jour les tâches d'un service pour utiliser une image Docker plus récente avec la même combinaison image/balise (my_image: latest) ou pour rouler des tâches Fargate sur une version de plate-forme plus récente.
C'est aussi simple que cela avec aws-cli:
aws ecs update-service --cluster my-cluster --service my-service --force-new-deployment