Atualizar o contêiner de um serviço no Amazon ECS

32

Que tipo de abordagem é recomendada para atualizar o contêiner de um serviço em execução no Amazon ECS?

A documentação da AWS diz: "Se você atualizou a imagem do Docker do seu aplicativo, pode criar uma nova definição de tarefa com essa imagem e implantá-la no seu serviço, uma tarefa por vez." Isso é praticamente tudo o que está disponível atualmente na documentação (13 de abril de 2015).

Entendi corretamente que a única maneira de atualizar meu contêiner de aplicativo no Amazon ECS é criar uma nova tarefa, interromper a tarefa antiga e iniciar a nova tarefa?

Uso com sucesso a tag "latest" no Core OS e no Fleetctl. Isso tem o benefício de não precisar alterar a tag da imagem do Docker para novas atualizações, pois o recarregamento do serviço verá novas alterações e atualiza o contêiner (usando a mesma tag "latest").

Que tipo de abordagem você usou para atualizar seu serviço com a imagem de janela de encaixe atualizada no Amazon ECS?

Petrus Repo
fonte
Também estamos tentando descobrir isso, pois esperamos usar o ECS para implantar uma variedade de daemons que precisam ser executados continuamente na produção.
parent5446
1
Apenas para confirmar, você disse que reiniciar um serviço ecs reduzirá a versão mais recente de uma imagem? Estive procurando documentação sobre isso e não consigo encontrá-la em lugar nenhum.
mmilleruva
1
Alguma confirmação sobre este?
Lior Ohana
@LiorOhana Infelizmente, é verdade. Veja minha resposta para detalhes.
hamx0r
Publiquei uma nova resposta detalhada abaixo, mas para esclarecer aqui: Seu serviço sempre tentará obter uma cópia nova do seu contêiner do repositório, com base na tag que você definiu. Se uma tarefa é eliminada, quando o serviço a implanta novamente, não há lembrança do que estava no repositório, apenas do que está no repositório.
23418 MrDuk

Respostas:

18

Não tenho certeza se isso é considerado uma pergunta abandonada - deparei com isso enquanto solucionava meu problema e agora adicionava minha solução agora que foi resolvida.

Para atualizar o serviço com o novo contêiner, você precisa:

  1. fazer upload de novo contêiner para o repositório;
  2. acionar atualização de definição de tarefa;
  3. acionar atualização de contêiner;
  4. importante: verifique se as regras de serviço permitem o lançamento de nova versão da tarefa.

Se a tarefa de serviço não for atualizada para a versão mais recente, verifique se há erros na guia "eventos". Por exemplo, talvez o ECS não tenha sido capaz de iniciar uma nova versão do seu serviço: você possui apenas uma instância do ec2 no cluster e a porta do aplicativo já está sendo usada no host. Nesse caso, defina os limites "min health / max health" como "0%, 100%" - dessa forma, o ECS escolherá eliminar o contêiner antigo antes de implantar um novo. Isso também está acontecendo ao longo de alguns minutos - não se apresse se não receber feedback imediato.

Abaixo está um exemplo de script de implantação para atualizar o contêiner em um cluster e serviço pré-configurados. Observe que não há necessidade de especificar versões se você apenas quer dizer "usar as últimas da família".

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
fonte
2
Isso me obriga a ter uma definição de tarefa como um arquivo localmente e, se eu entendi corretamente, esse é o único local onde posso definir variáveis ​​de ambiente. Existe alguma maneira de fazer isso sem ter as variáveis ​​de ambiente localmente? Idealmente, gostaria de emitir um comando para apontar para uma nova tag de imagem do docker sem enviar outras informações sobre a tarefa / serviço / contêiner / etc.
RMAC
1
Os comentários set "min health/max health" limits to "0%, 100%"são dourados. Muito obrigado!
Sivabudh
1
Cuidado aqui, se você definir mincomo 0%, quando alterar a definição de tarefa que seu serviço implanta, estará dando a ele autoridade total para reduzir todas as tarefas ao mesmo tempo para essa implantação.
MrDuk
1

Uso uma parte do script ecs-deploy com minhas melhorias (ele pega imagens de todas as descrições de contêineres e substitui sua parte de tag por $ 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"
Para sempre jovem
fonte
Recomenda-se fornecer as informações úteis dos links em sua resposta, para fornecer rot-link. Você poderia fazer isso, por favor?
BE77Y
1
Atualizado minha resposta
ForeverYoung 7/16
1

Depois de carregar uma nova imagem do Docker, mesmo que ela tenha a mesma tag usada por uma tarefa, é necessário copiar a tarefa mais recente e configurar o serviço para usar essa nova tarefa. Opcionalmente, é possível simplesmente ter duas tarefas duplicadas e configurar o Serviço para trocar entre elas sempre que a Imagem do Docker for atualizada.

Basicamente, para fazer com que um novo Docker Container seja feito pelo ECS, uma atualização do Serviço precisa acioná-lo, e a única maneira de acionar o Serviço é atualizá-lo de alguma forma - como dizer a ele para usar um número de tarefa diferente.

Observe que os contêineres em execução existentes podem não ser interrompidos automaticamente apenas porque o Serviço foi atualizado - você pode precisar olhar para sua lista de Tarefas e pará-los manualmente.

hamx0r
fonte
Na verdade, isso não é verdade - você sempre pode matar uma tarefa manualmente , em vez de confiar no seu serviço para fazê-lo. Quando o serviço detectar que foi morto, ele tentará trazê-lo novamente, forçando uma repetição do mesmo.tag
MrDuk
1

A abordagem que funciona para mim é semelhante à acima. Após criar seu serviço e tarefa e iniciar tudo, edite o Grupo de Auto-Scaling e verifique se min , max e desejado estão definidos como 1 .

O grupo pode ser o padrão; se você não tiver certeza, poderá obtê-lo selecionando a guia Instâncias do ECS no cluster, na lista suspensa Actions , escolha Cluster Resources e clique no link próximo à parte inferior da caixa de diálogo que é aberta.

Quando tudo estiver pronto , sempre que desejar implantar uma imagem de contêiner atualizada, vá para a área Tarefa do cluster e Interrompa a tarefa . Você receberá um aviso, mas, desde que o dimensionamento automático esteja configurado, o serviço iniciará novamente com o último empurrão.

Não há necessidade de criar novas versões do serviço ou da tarefa.

Observe que o serviço / tarefa se atualiza instantaneamente para um minuto ou mais. Se você ficar esperando desesperadamente, basta executar a nova tarefa manualmente. O serviço não é o proprietário, por isso não é o ideal, mas continuará a aparecer um novo se morrer.

K Cartlidge
fonte
1

Sei que esse é um tópico antigo, mas a solução é muito mais fácil do que a maioria das respostas aqui parece ser.

Como atualizar o contêiner em execução em duas etapas:

O abaixo pressupõe que você tenha um serviço executando uma tarefa que faz referência a um contêiner marcado latest(ou qualquer outra tag estática que não seja alterada nas atualizações do contêiner).

  1. Faça o upload do seu novo contêiner para o repositório
  2. Mate manualmente suas tarefas

Se o objetivo é criar uma nova configuração, não precisamos realmente confiar em nosso serviço para isso (e eu diria que não devemos confiar nele). Se você matar sua tarefa, o serviço reconhecerá que não possui as Desired Counttarefas em execução e simplesmente criará uma nova. Isso acionará uma nova solicitação do seu contêiner, com base na mesma tag.

Os serviços ECS são uma rede de segurança de alta disponibilidade, não um substituto para o seu pipeline de CD / CI.


Bônus: se o objetivo é fazer com que um serviço reconheça que um novo contêiner foi enviado (independentemente das tags), precisamos considerar as implicações disso. Realmente queremos um serviço básico controlando nosso pipeline de implantação para nós? Provavelmente não. Idealmente, você enviará seus contêineres com tags diferentes (com base nas versões de lançamento ou algo assim). Nesse caso, a barreira para a implantação é que o serviço precisa ser notificado sobre algo novo - novamente, é uma rede de segurança para o serviço e nada mais.


Como implantar novas tags em três etapas:

  1. Faça o upload do seu novo container:tagpara o repositório
  2. Crie uma nova definição de tarefa referenciando o novo tag
  3. Atualize seu serviço para referenciar a nova definição de tarefa
    • Cuidado aqui! Se você minimum healthydefiniu 0%como algumas outras respostas sugerem, está dando à AWS total autoridade para eliminar todo o serviço para implantar a nova definição de tarefa. Se você preferir uma implantação progressiva / gradual, defina o mínimo para algo >0%.
    • Como alternativa, defina a sua minimum healthypara 100%e seu maximum healthyalgo >100%para permitir o seu serviço para implantar as novas tarefas antes de matar os velhos (minimizando o impacto para os usuários).

A partir desse ponto, seu serviço reconhecerá automaticamente que você especificou uma nova tarefa e trabalhará na implantação com base nos limites minimum/ maximumsaudáveis ​​configurados.

MrDuk
fonte
agradável, obrigado, melhor do que outras respostas
Olegzandr Denman