私は現在、プロジェクトを再構築し、新しいdockerイメージを作成し、新しいイメージをAmazon ecrリポジトリにプッシュし、既存のタスク定義の新しいリビジョンを最新のdockerイメージで作成し、更新する簡単なCIをセットアップしようとしていますタスク定義の新しいリビジョンでサービスを実行し、最後に古いリビジョンを実行している既存のタスクを停止し、新しいリビジョンを実行しているタスクを開始します。
タスクの新しいリビジョンを開始する以外は、すべて正常に機能しています。
Bashスクリプトから、私が呼び出す最後のコマンドは次のとおりです。
aws ecs update-service --cluster "$CLUSTER" --service "$SERVICE" --task-definition "$TASK_DEFINITION":"$REVISION"
これにより、次のイベントエラーが発生します。
(service rj-api-service) was unable to place a task because no container instance met all of its requirements. The closest matching (container-instance bbbc23d5-1a09-45e7-b344-e68cc408e683) is already using a port required by your task.
これは、私が交換するコンテナが新しいコンテナとまったく同じで、同じポートで実行されるため、アプリケーションの最新バージョンが含まれているだけなので、理にかなっています。
私はupdate-service
コマンドは、既存のタスクを停止し、新しいタスクを開始しますが、新しいタスクを最初に開始し、成功すると古いタスクを停止するように見えます。
これを処理するためのベストプラクティスは何ですか?最初に古いタスクを停止する必要がありますか?最初にスクリプトでサービスを削除し、更新するたびにサービス全体を再作成する必要がありますか?
現在、実行中のタスクのインスタンスは1つしか必要ありませんが、複数のインスタンスに自動スケーリングできるようにする必要がある場合は、自分をボックスに入れたくありません。これに対処する最良の方法に関する提案はありますか?
取得しているメッセージは、ECSが青緑展開を試みているためです。サービスのダウンタイムを回避するために、現在のタスクを停止せずに新しいタスクリビジョンを割り当てようとしていることを意味します。最新のタスクの準備が整うと(定常状態)、古いタスクが最終的に削除されます。
このタイプのデプロイメントの問題は、2つのタスク(古いものと新しいもの)を維持するために、クラスターに十分な空きリソースが必要であるということです。 1)一定期間。たとえば、2 GBのメモリと2つのCPUを使用してタスクを展開する場合、新しいタスクリビジョンでサービスを更新するには、クラスターにその量の空きリソースが必要です。
次の2つのオプションがあります。
オプション番号2を実行するには、次の値を設定するだけです。
例
つまり、目的のタスクを100%だけ実行し(これ以上はしない)、新しいバージョン(正常なサービスの0%)を展開するときにダウンタイムを発生させます。
この例では、希望するタスクは1つだけであると仮定していますが、最小健全率および最大パーセントの値は、必要なタスクをいくつでも実行できます。
それが役に立てば幸い!他に疑問がある場合はお知らせください。
ビルド環境でシェルスクリプトを使用して、次の手順でタスクの新しいリビジョンを開始できます。
tasks definition json template をビルド環境のファイルに保存します(たとえば、テンプレートファイルはweb-server.json
およびタスク定義ファミリはweb-server
)。
ファイルディレクトリを現在のディレクトリとして使用し、タスク定義の登録を実行します(存在しない場合は最初の実行に発生します)
aws ecs register-task-definition --cli-input-json file://web-server.json
実行中のタスクID(TASK_ID)をシェルスクリプトの変数に取得します。
TASK_ID=`aws ecs list-tasks --cluster default --desired-status RUNNING --family web-server | egrep "task" | tr "/" " " | tr "[" " " | awk '{print $2}' | sed 's/"$//'`
シェルスクリプトの変数のタスクリビジョン(TASK_REVISION)を取得します。
TASK_REVISION=`aws ecs describe-task-definition --task-definition web-server | egrep "revision" | tr "/" " " | awk '{print $2}' | sed 's/"$//'`
実行中の現在のタスクを停止します
aws ecs stop-task --cluster default --task ${TASK_ID}
新しいタスクをすぐに開始する
aws ecs update-service --cluster default --service web-server --task-definition web-server:${TASK_REVISION} --desired-count 1
ベストプラクティスとして、2つのタスク(サービス内で実行されている2つのタスク)の最小カウントを維持し、次のスクリプト(複数のコンテナーの上記のステップの拡張)を使用してローリング更新(一度に1つのタスクを更新)を実行できますダウンタイム(最初のコンテナの更新後は十分な時間を確保してください。たとえば、新しいリクエストを受け入れる準備ができるように30スリープします)。
cd /<directory-containing-web-server.json>
aws ecs register-task-definition --cli-input-json file://web-server.json
OLD_TASK_ID=`aws ecs list-tasks --cluster default --desired-status RUNNING --family web-server | egrep "task" | tr "/" " " | tr "[" " " | awk '{print $2}' | sed 's/"$//'`
TASK_REVISION=`aws ecs describe-task-definition --task-definition web-server | egrep "revision" | tr "/" " " | awk '{print $2}' | sed 's/"$//'`
aws ecs stop-task --cluster default --task ${OLD_TASK_ID}
OLD_TASK_ID=`aws ecs list-tasks --cluster default --desired-status RUNNING --family web-server | egrep "task" | tr "/" " " | tr "[" " " | awk '{print $2}' | sed 's/"$//'`
aws ecs update-service --cluster default --service web-server --task-definition web-server:${TASK_REVISION} --desired-count 1
sleep 30
aws ecs stop-task --task ${OLD_TASK_ID}
aws ecs update-service --cluster default --service web-server --task-definition web-server:${TASK_REVISION} --desired-count 2
注:タスク定義ファミリー、インスタンスの希望数、およびタスク定義テンプレートを適宜構成する必要があります。
サービスで実行されている「タスク」のタスク定義を更新するにはタスクを削除して、新しいタスクを開始する必要があります。
このようにして、タスクのタスク定義を更新する問題を解決します
私は次のコードを書きました:
# Register a new Task definition
aws ecs register-task-definition --family testing-cluster --cli-input-json file://scripts/taskdefinition/testingtaskdef.json --region $AWS_REGION
# Update Service in the Cluster
aws ecs update-service --cluster $CLUSTER_NAME --service $SERVICE --task-definition testing-cluster --desired-count 1 --region $AWS_REGION
DECRIBED_SERVICE=$(aws ecs describe-services --region $AWS_REGION --cluster $CLUSTER_NAME --services $SERVICE);
CURRENT_DESIRED_COUNT=$(echo $DECRIBED_SERVICE | jq --raw-output ".services[0].desiredCount")
# - echo $CURRENT_DESIRED_COUNT
CURRENT_TASK_REVISION=$(echo $DECRIBED_SERVICE | jq -r ".services[0].taskDefinition")
echo "Current Task definition in Service" + $CURRENT_TASK_REVISION
CURRENT_RUNNING_TASK=$(echo $DECRIBED_SERVICE | jq -r ".services[0].runningCount")
echo $CURRENT_RUNNING_TASK
CURRENT_STALE_TASK=$(echo $DECRIBED_SERVICE | jq -r ".services[0].deployments | .[] | select(.taskDefinition != \"$CURRENT_TASK_REVISION\") | .taskDefinition")
echo "Task defn apart from current service Taskdefn" + $CURRENT_STALE_TASK
# - echo $CURRENT_STALE_TASK
tasks=$(aws ecs --region $AWS_REGION list-tasks --cluster $CLUSTER_NAME | jq -r '.taskArns | map(.[40:]) | reduce .[] as $item (""; . + $item + " ")')
echo "Tasks are as follows"
echo $tasks
TASKS=$(aws ecs --region $AWS_REGION describe-tasks --cluster $CLUSTER_NAME --task $tasks);
# - echo $TASKS
OLDER_TASK=$(echo $TASKS | jq -r ".tasks[] | select(.taskDefinitionArn!= \"$CURRENT_TASK_REVISION\") | .taskArn | split(\"/\") | .[1] ")
echo "Older Task running " + $OLDER_TASK
for old_task in $OLDER_TASK; do
aws ecs --region us-east-1 stop-task --cluster $CLUSTER_NAME --task $old_task
done
# Run new tasks with the updated new Task-definition
aws ecs --region $AWS_REGION run-task --cluster $CLUSTER_NAME --task-definition $CURRENT_TASK_REVISION
使用-> AWS CLI
OLD_TASK_IDを取得
aws ecs list-tasks --cluster ${ecsClusterName} --desired-status RUNNING --family ${nameTaskDefinition} | egrep "task/" | sed -E "s/.*task\/(.*)\"/\1/"
タスクを停止
aws ecs stop-task --cluster ${ecsClusterName} --task ${OLD_TASK_ID}
ECSサービスを更新する
aws ecs update-service --cluster ${ecsClusterName} --service ${nameService} --task-definition ${nameTaskDefinition}:${version} --desired-count 1 --force-new-deployment
だから今、これが機能している。
新しいタスク定義でaws ecs update service
を呼び出した後、aws ecs list-tasks
を呼び出し、サービスの実行中の各タスクで「aws stop task」を実行します。サービスの必要なカウントは1であるため、タスクのバックアップをすぐに開始しようとし、新しいサービス定義を使用します。
これはあまりきれいではありませんが、今のところ十分に機能しているようです。