Mettre à jour le conteneur d'un service dans Amazon ECS


32

Quel type d'approche est recommandé pour mettre à jour le conteneur d'un service qui s'exécute dans Amazon ECS?

La 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, tâche par tâche." C'est à peu près tout ce qui est actuellement disponible dans la documentation (13 avril 2015).

Ai-je bien compris que le seul moyen 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 "dernière" avec Core OS & Fleetctl. Cela présente 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 les nouvelles modifications et mettra à jour le conteneur (en utilisant la même balise "latest").

Quel type d'approches que vous avez utilisé pour mettre à jour votre service avec une image de menu fixe mise à jour dans Amazon ECS?


Nous essayons également de comprendre cela, car nous espérons utiliser ECS pour déployer divers démons devant fonctionner en permanence en production.
parent5446

1
Juste pour confirmer, vous avez dit que le redémarrage d'un service ecs affichera la dernière version d'une image? Je cherchais de la documentation à ce sujet et je ne la trouve nulle part.
mmilleruva

1
Une confirmation sur celui-ci?
Lior Ohana

@ LiorOhana Malheureusement, c'est vrai. Voir ma réponse pour plus de détails.
Hamx0r

J'ai posté une nouvelle réponse détaillée ci-dessous, mais pour préciser: votre service essaiera toujours d'extraire une nouvelle copie de votre conteneur du rapport, en fonction du tag que vous avez défini. Si une tâche est tué, lorsque le service se déploie à nouveau, il n'a aucun souvenir de ce qui était dans le repo, que ce qui est dans le repo.
MrDuk

Réponses:


18

Je ne sais pas si cela est considéré comme une question abandonnée - je suis tombé sur cette question 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:

  1. télécharger un nouveau conteneur dans le référentiel;
  2. déclencher la mise à jour de la définition de la tâche;
  3. déclencher la mise à jour du conteneur;
  4. important: assurez-vous que les règles de service permettent de lancer une nouvelle version de la tâche.

Si la tâche de service n'est pas mise à jour à la dernière version, vérifiez les erreurs dans l'onglet "événements". Par exemple, peut-être qu'ECS n'a 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 "santé minimale / santé maximale" sur "0%, 100%". De cette façon, ECS choisira de supprimer l'ancien conteneur avant de déployer le nouveau. Cela se produit également en quelques minutes - ne vous précipitez pas si vous ne voyez pas de retour immédiat.

Vous trouverez ci-dessous un exemple de script de déploiement pour mettre à jour un 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 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

2
Cela me force à avoir une définition de tâche sous forme de fichier localement, et si je comprends bien, c'est le seul endroit où je peux définir des variables d'environnement. Est-il possible de faire cela sans avoir les variables d'environnement localement? Idéalement, j'aimerais envoyer une commande pour pointer vers une nouvelle balise d'image docker sans envoyer d'autres informations sur la tâche / service / conteneur / etc.
rmac

1
Les commentaires set "min health/max health" limits to "0%, 100%"sont dorés. Merci beaucoup!
Sivabudh

1
Attention, si vous définissez la valeur minsur 0%, lorsque vous modifiez la définition de la tâche déployée par votre service, vous lui donnez essentiellement le droit de supprimer toutes les tâches simultanément pour ce déploiement.
MrDuk


1

J'utilise une partie du 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/e939d9cc41bc7a105cdcf8cd7f9ab9d714

# 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"

Il est recommandé de fournir les informations utiles à partir des liens de votre réponse, afin de fournir lien-pourriture. Pourriez-vous le faire, s'il vous plaît?
BE77Y

1
Mise à jour de ma réponse
ForeverYoung

1

Après avoir 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, vous pouvez simplement avoir 2 tâches en double et configurer le service pour les permuter entre elles à chaque mise à jour de l'image Docker.

Fondamentalement, pour que ECS crée un nouveau conteneur Docker, une mise à jour du service doit le déclencher, et le seul moyen de le déclencher 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 ne peuvent 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.


Ce n'est pas vrai en réalité - vous pouvez toujours supprimer manuellement une tâche au lieu de compter sur votre service pour le faire. Lorsque le service détecte qu'il a été tué, il tentera de le tag
rappeler

1

L'approche qui fonctionne pour moi est semblable à la précédente. Après avoir créé votre service et des tâches, et commencer tout va, modifier le groupe Auto-échelle et assurer min , max et souhaité sont fixés à 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 de votre cluster, puis dans le menu déroulant Actions , choisissez Ressources du cluster et cliquez sur le lien situé au 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 le relancera avec le dernier envoi.

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 de façon instantanée, instantanément ou à une minute près. Si vous attendez désespérément, vous pouvez simplement exécuter manuellement une nouvelle tâche. Le service ne le possédera pas, il n'est donc pas idéal, mais il en créera un nouveau s'il meurt.


1

Je sais que c'est un vieux fil, mais la solution est beaucoup plus facile que la plupart des réponses ne le prétendent.

Comment mettre à jour le conteneur en cours d'exécution en deux étapes:

Ce qui suit suppose que vous avez un service exécutant une tâche qui référence un conteneur étiqueté latest(ou toute autre balise statique qui ne change pas entre les mises à jour du conteneur).

  1. Téléchargez votre nouveau conteneur dans le référentiel
  2. Tuer manuellement vos tâches

Si l'objectif est que nous ayons une nouvelle construction dans la nature, nous n'avons pas vraiment besoin de compter sur notre service (et je dirais même que nous ne devrions pas compter sur lui). Si vous supprimez votre tâche, le service reconnaîtra que les Desired Counttâches ne sont pas en cours d'exécution et en crée simplement une nouvelle. Cela déclenchera une nouvelle extraction de votre conteneur, basée sur la même balise.

Les services ECS constituent un filet de sécurité HA et ne remplacent pas votre pipeline CD / CI.


Bonus: si l'objectif est de faire reconnaître à un service qu'un nouveau conteneur a été poussé (indépendamment des balises), nous devons en examiner les implications. Voulons-nous vraiment un service de base contrôlant notre pipeline de déploiement pour nous? Probablement pas. Idéalement, vous allez pousser vos conteneurs avec différentes balises (en fonction des versions des versions ou de quelque chose). Dans ce cas, l'obstacle au déploiement réside dans le fait que le service doit être averti de quelque chose de nouveau - encore une fois, c'est un filet de sécurité pour le service et rien de plus.


Comment déployer de nouvelles balises en trois étapes:

  1. Téléchargez votre nouveau container:tagdans le référentiel
  2. Créer une nouvelle définition de tâche référençant la nouvelle tag
  3. Mettez à jour votre service pour référencer la nouvelle définition de tâche
    • Attention ici! Si vous avez minimum healthydéfini sur 0%comme le suggèrent d'autres réponses, vous accordez à AWS tous les droits nécessaires pour supprimer l'ensemble 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 à quelque chose >0%.
    • Vous pouvez également définir votre minimum healthyà 100%et votre maximum healthyà quelque chose >100%pour permettre à votre service pour déployer les nouvelles tâches avant de tuer les anciens (réduisant au minimum l'impact sur les utilisateurs).

À partir de ce moment, votre service reconnaîtra automatiquement que vous avez spécifié une nouvelle tâche et déploiera cette tâche en fonction des seuils minimum/ maximumsanté que vous avez configurés.


gentil, merci, mieux que d'autres réponses
Olegzandr Denman
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.