Home > Net >  How to update an ecs service with specific tag version?
How to update an ecs service with specific tag version?

Time:01-10

I'm trying to update an ecs fargate service that has multiple tags associated with the given ecr container image that's used by the service's task definition.

The container image in ecr has the following tags: 2023.3.0-latest, test

As you can see, this is just includes a version tag and then an environment tag, which in this case is just, "test".

In the task definition I have the ecr url passed in using the standard format: <baseurl>/<ecrrepo>:test

What I want to do is when there is an update on that specific service associated with the task definition to use the specific image associated with the specific version and environment.

For example, how would I update the service with the specific task definition of another image which was also for test but which has a different version?

So far I've got a number of Jenkins jobs running which have accomplished everything up to the point of filtering on the version and updating the service associated with the specific environment. What I've got working is as follows:

  1. Create repo, upload container to ecr with the specified version, tag with the associated with the specified version, and push the container image to ecr.

  2. Retag the image with the specified environment, in this case, "test"

The third step would be how to update the task with that specific container image associated with the version and environment.

So say, for example, I force update the task associated with the "test" tag, how do I first filter on the specific version of the "test" tag so that ecs knows which version of "test" to use?

CodePudding user response:

A couple important things:

  • Task definitions are the only place where you can define what image should be used by containers in a task.
  • Task definition revisions are immutable -- they cannot be changed after they are created.
  • Your task definitions should generally ONLY specify images with unique image tags that never change. Otherwise, your tasks will have indeterministic and inconsistent behavior.
  • To update the image your service tasks use, you must create a new task definition revision and update the service to use the new revision.
  • You probably only want to move your environment tag on the image after updating the service, not before.

Your basic steps should look something like this:

  1. Build the image(s) and push the image(s) to ECR with a unique tag
  2. Create a new task definition revision that specifies the unique tag for the appropriate container(s)
  3. Update the service to use the new revision
  4. (optionally) wait for service stabilization
  5. Upon successful update, retag the environment

A script to do all this might look something like this:

# 1. Build the image(s) and push the image(s) to ECR with a unique tag
unique_tag="$BUILD_TAG" # or whatever you want that is unique
new_image="<ecr repo>:$unique_tag"
service_arn="<service ARN>"

env_name="test" # or whatever
cache_image="<ecr repo>:$env_name"

# leverage docker cache from the currently active image in this environment, if it exists
docker pull $cache_image || echo "no cache"
docker build --cache-from "$cache_image" -t <ECR repo>:$unique_tag .
docer push <ECR repo>:$unique-tag .

# 2. Create a new task definition revision

# here we assume you don't store the task definition JSON in the repo, which means we need to get it from API call
# by default, this gets the latest ACTIVE revision, which is usually what you want.
existing_taskdef="$(aws ecs describe-task-definition --task-definition=<your-taskdef-family-name>)"

# create new taskdef using jq to replace the image key in the first container (we assume only one container `.containerDefinitions[0]` is defined in this example)
# describe-task-definition returns some keys that can't be used with register-task-defintiion, so we delete those, too
new_task_definition="$(jq --arg IMAGE "$new_image" '.taskDefinition | .containerDefinitions[0].image = $IMAGE | del(.taskDefinitionArn) | del(.revision) | del(.status) | del(.requiresAttributes) | del(.compatibilities)' <<< "$existing_taskdef")"

# register the new revision
new_revision_arn="$(aws ecs register-task-definition --cli-input-json "$new_taskdefinition" --output text --query 'taskDefinition.taskDefinitionArn')"


# 3. Update the service to use the new revision

aws ecs update-service --service="$service_arn" --task-definition="$new_revision_arn"

# 4. wait for deployment stabilization (omitted for brevity)

# 5 retag the environment

# in subsequent workflows, the newly built image will be used for the cache
docker tag "$new_image" "<ecr repo>:${env_name}"
docker push "<ecr repo>:${env_name}"

CodePudding user response:

Found a working solution. Again the use case was if you have multiple versions of an image in ecr that you're wanting to deploy via ecs fargate, and you dont want to create separate task definitions for each, but keep the image set to "test", and just update the version each time.

Contrary to some opinions, this can be done. When you retag the version you're wanting with "test" (i.e., 2023.1.0 or 2023.2.0) ecr updates that tag to the version specified and removes the tag from the previous version specified. In other words, if you refresh ecr you'll see the "test" tag, or whatever other tag you specified, switched to that version (NOTE: I've hardcoded the version below for simplicity's sake).

1. Push the tagged image to ECR

docker load < containername:2023.1.0-latest.tar.gz

SERVICE_NAME="ecsServiceName"
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
ECR_URL="$ACCOUNT_ID.dkr.ecr.<region>.amazonaws.com/SERVICE_NAME:2023.1.0-latest"
    
aws ecr create-repository --repository-name ${SERVICE_NAME:?} --region <region> || true

docker tag containername:2023.1.0-latest $ECR_URL
 
$(aws ecr get-login --region <region> --no-include-email --registry-ids $ACCOUNT_ID)
 
docker push $ECR_URL
    
2. Retag the image with env tag

MY_MANIFEST=$(aws ecr batch-get-image --repository-name $SERVICE_NAME --image-ids imageTag=2023.1.0-latest --region <region> --query images[].imageManifest --output text)

aws ecr put-image --repository-name $SERVICE_NAME --image-tag test --image-manifest "$MY_MANIFEST" --region <region>

3. Update the service with the task definition

aws ecs update-service --cluster ecsClusterName --service $SERVICE_NAME --task-definition ecsTaskDefinitionName --force-new-deployment --region <region>
  • Related