Aggiorna il contenitore di un servizio in Amazon ECS


32

Quale tipo di approccio è consigliato per l'aggiornamento del contenitore di un servizio in esecuzione su Amazon ECS?

La documentazione di AWS dice: "Se hai aggiornato l'immagine Docker della tua applicazione, puoi creare una nuova definizione di attività con quell'immagine e distribuirla al tuo servizio, un'attività alla volta". Questo è praticamente tutto ciò che è attualmente disponibile nella documentazione attualmente (13 aprile 2015).

Ho capito bene che l'unico modo per aggiornare il mio contenitore di applicazioni in Amazon ECS è creare una nuova attività, quindi interrompere la vecchia attività e iniziare la nuova attività?

Ho usato con successo un tag "più recente" con Core OS e Fleetctl. Questo ha il vantaggio di non dover cambiare il tag dell'immagine Docker per i nuovi aggiornamenti, dal momento che ricaricare il servizio vedrà nuove modifiche e aggiornerà il contenitore (usando lo stesso tag "ultimo").

Che tipo di approcci hai utilizzato per aggiornare il tuo servizio con l'immagine docker aggiornata in Amazon ECS?


Anche cercando di capire anche questo, poiché speriamo di usare ECS per distribuire una varietà di demoni che devono funzionare continuamente in produzione.
parent5446

1
Giusto per confermare, hai detto che il riavvio di un servizio ecs eliminerà l'ultima versione di un'immagine? Ho cercato documentazione su questo e non riesco a trovarlo da nessuna parte.
mmilleruva,

1
Qualche conferma su questo?
Lior Ohana,

@LiorOhana Purtroppo è vero. Vedi la mia risposta per i dettagli.
hamx0r

Di seguito ho pubblicato una nuova risposta dettagliata, ma per chiarire qui: il servizio tenterà sempre di estrarre una nuova copia del contenitore dal repository, in base al tag impostato. Se un'attività viene terminata, quando il servizio la distribuisce di nuovo, non ha alcun ricordo di ciò che era nel repository, ma solo di ciò che è nel repository.
Mr Duk,

Risposte:


18

Non sono sicuro che questa sia considerata una domanda abbandonata - ci siamo imbattuti in questo durante la risoluzione del problema e ora aggiungendo la mia soluzione ora che è stata risolta.

Per aggiornare il servizio con un nuovo contenitore, è necessario:

  1. caricare un nuovo contenitore nel repository;
  2. attivare l'aggiornamento della definizione dell'attività;
  3. innescare l'aggiornamento del contenitore;
  4. importante: assicurarsi che le regole di servizio consentano l'avvio di una nuova versione dell'attività.

Se l'attività di servizio non viene aggiornata all'ultima versione, controllare la scheda "eventi" per errori. Ad esempio, forse ECS non è stato in grado di avviare una nuova versione del servizio: hai solo un'istanza ec2 nel cluster e la porta dell'applicazione è già utilizzata sull'host. In questo caso, impostare i limiti "min salute / salute massima" su "0%, 100%" - in questo modo, ECS sceglierà di uccidere il vecchio contenitore prima di distribuirne uno nuovo. Ciò accade anche nel giro di pochi minuti: non affrettarti se non vedi un feedback immediato.

Di seguito è riportato un esempio di script di distribuzione per aggiornare il contenitore in un cluster e servizio preconfigurati. Nota che non è necessario specificare le versioni se intendi semplicemente "usa gli ultimi dalla famiglia".

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
Questo mi obbliga ad avere una definizione di attività come file localmente e, se capisco correttamente, è l'unico posto in cui posso definire le variabili di ambiente. C'è un modo per farlo senza avere le variabili di ambiente a livello locale? Idealmente, vorrei emettere un comando per puntare a un nuovo tag immagine docker senza inviare altre informazioni sull'attività / servizio / contenitore / ecc.
rmac

1
I commenti su set "min health/max health" limits to "0%, 100%"sono d'oro. Grazie mille!
sivabudh,

1
Un avvertimento qui, se si imposta minsu 0%, quando si modifica la definizione di attività distribuita dal servizio, essenzialmente si sta dando la piena autorità per abbattere tutte le attività contemporaneamente per quella distribuzione.
Mr Duk,


1

Uso parte dello script ecs-deploy con i miei miglioramenti (prende le immagini da ogni descrizione del contenitore e sostituisce la sua parte tag con $ 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"

Si consiglia di fornire le informazioni utili dai collegamenti nella risposta, per fornire il collegamento-marcio. Potresti farlo, per favore?
BE77Y,

1
Aggiornato la mia risposta
ForeverYoung

1

Dopo aver caricato una nuova immagine Docker, anche se ha lo stesso tag utilizzato da un'attività, è necessario copiare l'attività più recente e quindi configurare il servizio per utilizzare quella nuova attività. Facoltativamente, si potrebbero semplicemente avere 2 attività duplicate e configurare il Servizio per scambiarle ogni volta che si aggiorna l'immagine Docker.

Fondamentalmente, al fine di causare un nuovo Docker Container da parte di ECS, un aggiornamento al Servizio deve attivarlo e l'unico modo per attivare il Servizio è aggiornarlo in qualche modo, come dicendogli di usare un numero di attività diverso.

Si noti che i contenitori in esecuzione esistenti potrebbero non arrestarsi automaticamente solo perché il servizio è stato aggiornato: potrebbe essere necessario esaminare l'elenco delle attività e arrestarle manualmente.


Questo non è in realtà vero: puoi sempre uccidere manualmente un'attività invece di fare affidamento sul tuo servizio per farlo. Quando il servizio rileva che è stato ucciso, tenterà di riattivarlo, forzando una nuova estrazione dello stessotag
MrDuk

1

L'approccio che funziona per me è simile al precedente. Dopo aver creato il servizio e l'attività e aver avviato tutto, modificare il gruppo di ridimensionamento automatico e assicurarsi che min , max e desiderato siano impostati su 1 .

Il gruppo può essere quello predefinito; se non sei sicuro, puoi accedervi selezionando la scheda Istanze ECS nel tuo cluster, quindi dal menu a discesa Azioni scegli Risorse cluster e fai clic sul collegamento nella parte inferiore della finestra di dialogo che si apre.

Quando è tutto a posto, ogni volta che vuoi distribuire un'immagine contenitore aggiornata vai nell'area Attività del cluster e Interrompi l'attività . Riceverai un avviso, ma a condizione che il ridimensionamento automatico sia impostato, il servizio ricomincerà a funzionare con l'ultima pressione.

Non è necessario creare nuove versioni del servizio o dell'attività.

Si noti che il servizio / attività si aggiorna da qualsiasi momento da istantaneamente a circa un minuto circa. Se ricevi un'attesa disperata, puoi semplicemente eseguire Nuova attività manualmente. Il servizio non lo possiede, quindi non è l'ideale, ma se ne muore continuerà a farne uno nuovo.


1

So che si tratta di un vecchio thread, ma la soluzione è molto più semplice di quanto la maggior parte delle risposte qui non siano.

Come aggiornare il contenitore in esecuzione in due passaggi:

Di seguito si presume che abbiate un servizio che esegue un'attività che fa riferimento a un contenitore taggato latest(o qualsiasi altro tag statico che non cambia attraverso gli aggiornamenti del contenitore).

  1. Carica il tuo nuovo contenitore nel repository
  2. Uccidi manualmente i tuoi compiti

Se l'obiettivo è di ottenere una nuova build in libertà, non abbiamo davvero bisogno di fare affidamento sul nostro servizio per quello (e direi, non dovremmo fare affidamento su di esso). Se uccidi il tuo compito, il servizio riconoscerà che non ha le Desired Countattività in esecuzione e ne farà semplicemente una nuova. Ciò attiverà un nuovo pull del contenitore, basato sullo stesso tag.

I servizi ECS sono una rete di sicurezza HA, non un rimpiazzo per la pipeline CD / CI.


Bonus: se l'obiettivo è far riconoscere un servizio a un nuovo contenitore (indipendentemente dai tag), dobbiamo considerare le implicazioni di ciò. Vogliamo davvero un servizio di base che controlla la nostra pipeline di distribuzione per noi? Probabilmente no. Idealmente, spingi i tuoi contenitori con tag diversi (in base alle versioni di rilascio o qualcosa del genere). In questo caso, la barriera all'implementazione è che il servizio deve essere informato di qualcosa di nuovo - di nuovo, è una rete di sicurezza per il servizio e niente di più.


Come distribuire nuovi tag in tre passaggi:

  1. Carica il tuo nuovo container:tagnel repository
  2. Creare una nuova definizione di attività facendo riferimento al nuovo tag
  3. Aggiorna il tuo servizio per fare riferimento alla nuova definizione di attività
    • Attento qui! Se hai minimum healthyimpostato 0%come suggerito da altre risposte, stai dando ad AWS la massima autorità per interrompere l'intero servizio al fine di distribuire la nuova definizione di attività. Se si preferisce una distribuzione continua / graduale, impostare il minimo su qualcosa >0%.
    • In alternativa, impostare il vostro minimum healthyper 100%e la vostra maximum healthya qualcosa >100%per permettere al vostro servizio per distribuire i nuovi compiti prima di uccidere i vecchi (riducendo al minimo l'impatto sugli utenti).

Da questo punto, il tuo servizio riconoscerà automaticamente che hai specificato una nuova attività e lavorerà sulla sua distribuzione in base alle soglie minimum/ maximumintegre che hai configurato.


bello, grazie, meglio di altre risposte
Olegzandr Denman
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.