Zaktualizuj kontener usługi w Amazon ECS

32

Jakie podejście jest zalecane do aktualizacji kontenera usługi działającej w Amazon ECS?

Dokumentacja AWS mówi: „Jeśli zaktualizowałeś obraz Docker swojej aplikacji, możesz utworzyć nową definicję zadania z tym obrazem i wdrożyć go do usługi, jedno zadanie na raz”. To prawie wszystko, co jest obecnie dostępne w dokumentacji (13 kwietnia 2015 r.).

Czy zrozumiałem poprawnie, że jedynym sposobem na aktualizację mojego kontenera aplikacji w Amazon ECS jest utworzenie nowego zadania, a następnie zatrzymanie starego zadania i rozpoczęcie nowego?

Z powodzeniem używam tagu „najnowsze” w Core OS i Fleetctl. Ma to tę zaletę, że nie trzeba zmieniać znacznika obrazu Docker dla nowych aktualizacji, ponieważ przeładowanie usługi zobaczy nowe zmiany i zaktualizuje kontener (przy użyciu tego samego znacznika „najnowsze”).

Jakie metody zastosowałeś do zaktualizowania usługi za pomocą zaktualizowanego obrazu dokera w Amazon ECS?

Petrus Repo
źródło
Próbujemy również to rozgryźć, ponieważ mamy nadzieję, że wykorzystamy ECS do wdrożenia różnych demonów, które muszą działać nieprzerwanie w środowisku produkcyjnym.
rodzic5446,
1
Żeby tylko potwierdzić, powiedziałeś, że ponowne uruchomienie usługi ecs spowoduje usunięcie najnowszej wersji obrazu? Szukałem dokumentacji na ten temat i nigdzie nie mogę jej znaleźć.
mmilleruva
1
Jakieś potwierdzenie tego?
Lior Ohana
@LiorOhana Niestety to prawda. Zobacz moją odpowiedź, aby poznać szczegóły.
hamx0r
Poniżej zamieściłem nową szczegółową odpowiedź, ale w celu wyjaśnienia tutaj: Twoja usługa zawsze będzie próbowała wyciągnąć świeżą kopię Twojego kontenera z repozytorium, w oparciu o ustawiony tag. Jeśli zadanie zostanie zabite, gdy usługa go ponownie wdroży, nie będzie pamiętało tego, co było w repozytorium, tylko to, co jest w repozytorium.
MrDuk

Odpowiedzi:

18

Nie jestem pewien, czy to pytanie jest uważane za porzucone - natknąłem się na to podczas rozwiązywania problemu i dodawania rozwiązania, gdy zostało już rozwiązane.

Aby zaktualizować usługę o nowy kontener, musisz:

  1. załaduj nowy kontener do repozytorium;
  2. wyzwalanie aktualizacji definicji zadania;
  3. uruchom aktualizację kontenera;
  4. ważne: upewnij się, że reguły usługi umożliwiają uruchomienie nowej wersji zadania.

Jeśli zadanie serwisowe nie jest zaktualizowane do najnowszej wersji, sprawdź zakładkę „zdarzenia” pod kątem błędów. Na przykład może ECS nie mógł uruchomić nowej wersji usługi: masz tylko jedną instancję ec2 w klastrze, a port aplikacji jest już używany na hoście. W takim przypadku ustaw „minimalne zdrowie / maksymalne zdrowie” na „0%, 100%” - w ten sposób ECS wybierze zabicie starego kontenera przed wdrożeniem nowego. Dzieje się tak również w ciągu kilku minut - nie spiesz się, jeśli nie widzisz natychmiastowej informacji zwrotnej.

Poniżej znajduje się przykładowy skrypt wdrażania do aktualizacji kontenera we wstępnie skonfigurowanym klastrze i usłudze. Uwaga: nie ma potrzeby określania wersji, jeśli chodzi o „użyj najnowszej z rodziny”.

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
źródło
2
Zmusza mnie to do lokalnego zdefiniowania zadania jako pliku, a jeśli dobrze rozumiem, jest to jedyne miejsce, w którym mogę zdefiniować zmienne środowiskowe. Czy można to zrobić bez lokalnych zmiennych środowiskowych? Idealnie chciałbym wydać polecenie wskazujące nowy znacznik obrazu dokera bez wysyłania żadnych innych informacji o zadaniu / usłudze / kontenerze itp.
rmac
1
Komentarze na temat set "min health/max health" limits to "0%, 100%"są złote. Dziękuję bardzo!
sivabudh
1
Jedna uwaga tutaj, jeśli ustawisz min, aby 0%po zmianie definicji zadanie wykorzystuje swoich usług, jesteś w istocie dając mu pełną władzę obalić wszystkie zadania w tym samym czasie dla tej instalacji.
MrDuk
1

Używam części ze skryptu wdrażania ecs z moimi ulepszeniami (pobiera obrazy z każdego opisu kontenera i zastępuje jego część tagową $ 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"
Wiecznie młodzi
źródło
Zaleca się podanie użytecznych informacji z linków w odpowiedzi, aby zapewnić rot-link. Czy możesz to zrobić, proszę?
BE77Y,
1
Zaktualizowałem moją odpowiedź
ForeverYoung,
1

Po przesłaniu nowego obrazu Docker, nawet jeśli ma on taki sam tag, jak używany przez Zadanie, należy skopiować najnowsze zadanie, a następnie skonfigurować Usługę do korzystania z tego nowego Zadania. Opcjonalnie można po prostu mieć 2 zduplikowane zadania i skonfigurować Usługę tak, aby przełączała się między nimi przy każdej aktualizacji obrazu Docker.

Zasadniczo, aby spowodować utworzenie nowego kontenera Dockera przez ECS, aktualizacja Usługi musi go uruchomić, a jedynym sposobem na wywołanie Usługi jest jego aktualizacja w pewien sposób - na przykład poprzez nakazanie mu użycia inny numer zadania.

Pamiętaj, że istniejące działające kontenery mogą nie zostać automatycznie zatrzymane tylko dlatego, że usługa została zaktualizowana - może być konieczne zajrzenie do listy zadań i zatrzymanie ich ręcznie.

hamx0r
źródło
To w rzeczywistości nie jest prawdą - zawsze możesz ręcznie zabić zadanie zamiast polegać na swojej usłudze. Gdy służba wykryje, że została zabita, spróbuje ją ponownie uruchomić, zmuszając do ponownego uruchomienia tego samegotag
MrDuk
1

Podejście, które działa dla mnie jest podobne do powyższego. Po utworzeniu usługi i zadania oraz rozpoczęciu wszystkiego edytuj grupę automatycznego skalowania i upewnij się, że min , maks i żądane są ustawione na 1 .

Grupa może być domyślna; jeśli nie masz pewności, możesz do niego przejść, wybierając kartę Instancje ECS w klastrze, a następnie z rozwijanego menu Działania wybierz Zasoby klastra i kliknij łącze w dolnej części okna dialogowego, które zostanie otwarte.

Gdy wszystko będzie gotowe , za każdym razem, gdy chcesz wdrożyć zaktualizowany obraz kontenera, przejdź do obszaru Zadanie klastra i Zatrzymaj zadanie . Dostaniesz ostrzeżenie, ale pod warunkiem skonfigurowania automatycznego skalowania usługa zacznie działać ponownie z najnowszym push.

Nie ma potrzeby tworzenia nowych wersji usługi ani zadania.

Pamiętaj, że usługa / zadanie aktualizują się w dowolnym miejscu, od razu do około minuty. Jeśli desperacko czekasz, możesz po prostu ręcznie uruchomić nowe zadanie. Usługa nie będzie jej właścicielem, więc nie jest idealna, ale w razie śmierci nadal będzie działać na nową.

K Cartlidge
źródło
1

Wiem, że to stary wątek, ale rozwiązanie jest o wiele łatwiejsze niż większość odpowiedzi tutaj.

Jak zaktualizować działający kontener w dwóch krokach:

Poniżej założono, że masz usługę uruchamiającą zadanie, które odwołuje się do oznaczonego kontenera latest(lub dowolnego innego statycznego tagu, który nie zmienia się między aktualizacjami kontenera).

  1. Prześlij swój nowy kontener do repozytorium
  2. Ręcznie zabij swoje zadania

Jeśli naszym celem jest udostępnienie nowej wersji w środowisku naturalnym, tak naprawdę nie musimy polegać na naszych usługach (i twierdzę, że nie powinniśmy na tym polegać). Jeśli zabijesz swoje zadanie, usługa rozpozna, że ​​nie ma Desired Counturuchomionych zadań, i po prostu uruchom nowe. Spowoduje to ponowne pobranie kontenera w oparciu o ten sam tag.

Usługi ECS są siecią bezpieczeństwa HA, a nie zamiennikiem twojego rurociągu CD / CI.


Premia: jeśli celem jest, aby usługa rozpoznała, że ​​nowy kontener został wypchnięty (niezależnie od tagów), musimy rozważyć konsekwencje tego. Czy naprawdę chcemy dla nas podstawowej usługi kontrolującej nasz proces wdrażania? Prawdopodobnie nie. Idealnie, będziesz przepychać swoje kontenery różnymi tagami (w zależności od wersji lub czegoś podobnego). W tym przypadku barierą we wdrożeniu jest to, że usługa musi zostać powiadomiona o czymś nowym - znowu jest to sieć bezpieczeństwa dla usługi i nic więcej.


Jak wdrożyć nowe tagi w trzech krokach:

  1. Prześlij swój nowy container:tagdo repozytorium
  2. Utwórz nową definicję zadania odwołującą się do nowej tag
  3. Zaktualizuj usługę, aby odwoływała się do nowej definicji zadania
    • Ostrożnie tutaj! Jeśli minimum healthyustawiłeś 0%tak, jak sugerują inne odpowiedzi, dajesz AWS pełne uprawnienia do zabicia całej usługi w celu wdrożenia nowej definicji zadania. Jeśli wolisz wdrażanie stopniowe / stopniowe, ustaw minimum na coś >0%.
    • Alternatywnie, ustaw minimum healthysię 100%i swoje maximum healthydo czegoś >100%, aby umożliwić usługa wdrożyć nowe zadania przed zabijanie starych (minimalizacja wpływu na użytkowników).

Od tego momentu usługa automatycznie rozpozna, że ​​określono nowe zadanie, i będzie pracować nad jego wdrożeniem na podstawie skonfigurowanych minimum/ maximumzdrowych progów.

MrDuk
źródło
miło, dziękuję, lepsze niż inne odpowiedzi
Olegzandr Denman