containers-roadmap icon indicating copy to clipboard operation
containers-roadmap copied to clipboard

[ECR] [Replication]: trigger replication when regions are updated

Open RLThomaz opened this issue 5 years ago • 5 comments

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
  • Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment

Tell us about your request What do you want us to build? A trigger that starts replication for newly added regions for "Cross-Region replication".

Which service(s) is this request for? ECR

Tell us about the problem you're trying to solve. What are you trying to do, and why is it hard? I need that replications start automatically to a region that was just added to the Cross-Region Replication of a registry. Currently, I believe the API is expecting the Cross-Region Replication to be activated (and regions set) prior to the creation and pushing of an image. However, if a new region is added to the same registry, the replication will only occur (for a single repository) if a new image/tag is pushed to a repository. If this cannot be solved, it will impact the deployment of services to new regions.

Are you currently working around this issue?

Original:

~~Currently, the best (easiest) workaround I found is to delete the image (tag) and immediately push it back into the repository. This won't require any actual upload to happen (as the layers will still exist) and will trigger the replication of only the image/tag pushed.~~

Edit 1:

I found a much better way of triggering the replication (it only works for single image tags): Using the API or SDK of your preference perform a batch-get-image to thoroughly describe all image/tags you want to trigger replication. For each image tag, take the imageManifest from the batch-get-image response and use put-image to update the image tag using the same manifest. This shall trigger the replication as if a new image has just been pushed.

Edit 2:

Actually, the previous approach was pretty hacky as the imageManifest needs to be changed (it's a string) somehow - adding or removing a linebreak was enough to trigger everything. The less hacky approach is to delete the image tag before attempting to update it. I'm pretty sure this is still hacky and might bite me back in the future - that's why this request is important.

Additional context It would be nice to have this feature even before the ability to select repositories or images by tag/regex.

RLThomaz avatar Feb 02 '21 05:02 RLThomaz

It would be similarly useful to also trigger when new destination accounts are added to the configuration.

Robrowski avatar Feb 19 '21 19:02 Robrowski

Here is an extract of the scripts I end up doing

--- to copy ----

aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $ECR_REGISTRY
IMAGE_TAGS=$(aws ecr list-images --repository-name $ECR_REPO --query 'imageIds[].imageTag' --output text)
for image_tag in $IMAGE_TAGS
do
    MANIFEST=$(aws ecr batch-get-image --repository-name $ECR_REPO  --image-id imageTag=$image_tag  --query 'images[].imageManifest' --output text)
    new_tag=$image_tag".temp"
    echo "copying image $ECR_REPO:$image_tag"
    aws ecr put-image --repository-name $ECR_REPO --image-tag $new_tag --image-manifest "$MANIFEST"  >/dev/null 2>&1
    aws ecr batch-delete-image --repository-name $ECR_REPO  --image-ids imageTag=$image_tag  >/dev/null 2>&1
    aws ecr put-image --repository-name $ECR_REPO --image-tag $image_tag --image-manifest "$MANIFEST" >/dev/null 2>&1
    aws ecr batch-delete-image --repository-name $ECR_REPO --image-ids imageTag=$new_tag  >/dev/null 2>&1
done

Unfortunately, the tag deletion are not propagated, so I add to delete the ".temp" tag on the destination repo

aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $ECR_REGISTRY

IMAGE_TAGS=$(aws ecr list-images --repository-name $ECR_REPO --query 'imageIds[].imageTag' --output text)

for image_tag in $IMAGE_TAGS
do
    if [[ $image_tag == *.temp ]]
    then
        echo "Deleting image $ECR_REPO:$image_tag"
	MANIFEST=$(aws ecr batch-get-image --repository-name $ECR_REPO  --image-id imageTag=$image_tag  --query 'images[].imageManifest' --output text)
	aws ecr batch-delete-image --repository-name $ECR_REPO  --image-ids imageTag=$image_tag  >/dev/null 2>&1
    fi 
done

jguionnet avatar May 06 '21 21:05 jguionnet

Based on previous comment, I writed a python code that do the same thing, but for all repositories on your account.

#!/usr/bin/env python3

import boto3
session = boto3.Session(profile_name='YOUR_AWS_PROFILE_NAME_HERE',region_name='YOUR_SOURCE_REGION_HERE')
ecr = session.client('ecr')

registryId="YOUR_AWS_ACCOUNT_ID_HERE"

repositories_list = ecr.describe_repositories(
    registryId=registryId,
    maxResults=1000
)

for repository in repositories_list['repositories']:
    repositoryName=repository['repositoryName']
    imagesList = ecr.list_images(
        registryId=registryId,
        repositoryName=repositoryName,
        maxResults=1000,
        filter={
            'tagStatus': 'TAGGED'
        }
    )
    for image in imagesList['imageIds']:
        imageTag=image['imageTag']
        imageData = ecr.batch_get_image(
            registryId=registryId,
            repositoryName=repositoryName,
            imageIds=[
                {
                    'imageTag': imageTag
                },
            ],
        )
        print("reuploading: ",repositoryName,":",imageTag, end=" ")
        for image in imageData['images']:
            tempTag=imageTag+"-temp"
            imageManifest=image['imageManifest']
            ecr.put_image(
                registryId=registryId,
                repositoryName=repositoryName,
                imageManifest=imageManifest,
                imageTag=tempTag
            )
            ecr.batch_delete_image(
                registryId=registryId,
                repositoryName=repositoryName,  
                imageIds=[
                    {
                    'imageTag': imageTag
                    },
                ]
            )
            ecr.put_image(
                registryId=registryId,
                repositoryName=repositoryName,
                imageManifest=imageManifest,
                imageTag=imageTag
            )
            ecr.batch_delete_image(
                registryId=registryId,
                repositoryName=repositoryName,  
                imageIds=[
                    {
                    'imageTag': tempTag
                    },
                ]
            )
            print("OK")

and for delete the temp images replicated on destination region

#!/usr/bin/env python3

import boto3
session = boto3.Session(profile_name='YOUR_AWS_PROFILE_NAME_HERE',region_name='YOUR_DESTINATION_REGION_HERE')
ecr = session.client('ecr')

registryId="YOUR_AWS_ACCOUNT_ID_HERE"

repositories_list = ecr.describe_repositories(
    registryId=registryId,
    maxResults=1000
)

for repository in repositories_list['repositories']:
    repositoryName=repository['repositoryName']
    imagesList = ecr.list_images(
        registryId=registryId,
        repositoryName=repositoryName,
        maxResults=1000,
        filter={
            'tagStatus': 'TAGGED'
        }
    )
    for image in imagesList['imageIds']:
        imageTag=image['imageTag']
        imageData = ecr.batch_get_image(
            registryId=registryId,
            repositoryName=repositoryName,
            imageIds=[
                {
                    'imageTag': imageTag
                },
            ],
        )
        if imageTag.endswith('-temp'):
            print("deleting: {0}:{1}".format(repositoryName,imageTag), end=" ... ")
            ecr.batch_delete_image(
                registryId=registryId,
                repositoryName=repositoryName,  
                imageIds=[
                    {
                    'imageTag': imageTag
                    },
                ]
            )
            print("OK")

rsmartins78 avatar Aug 19 '21 20:08 rsmartins78

This works if Repository Type - "image" but what about the repositories where Repository Type ---"Helm Chart"

ghost avatar Sep 11 '22 09:09 ghost

Will this also work for Cross Account as well, where other region we are replication is not the Primary region.

Is it needed to enable CAR in other accounts? but that will be unwanted configuration to have CAR also enabled in the regions we need.

ghost avatar Sep 11 '22 09:09 ghost

Would be nice to have the same functionality as in S3 where we can launch a batch operation when a replication rule is added.

nisalupendra avatar May 23 '23 13:05 nisalupendra

There is also a proposal for ECR to ECR pull-through cache, which could replace full replication. I think it would also address the issue described in this ticket - already existing images in region A would be cached in region B on demand. Also that way you would not replicate images that are maybe no longer needed (saving $$$ on transfer and storage in the new region). If you think it would help - vote: https://github.com/aws/containers-roadmap/issues/2208

wosiu avatar Nov 20 '23 23:11 wosiu