Skip to content

Instantly share code, notes, and snippets.

@zxkane
Created July 4, 2024 16:28
Show Gist options
  • Save zxkane/4624d699ff664698d94e3b8bf51de3e2 to your computer and use it in GitHub Desktop.
Save zxkane/4624d699ff664698d94e3b8bf51de3e2 to your computer and use it in GitHub Desktop.
Mirror multiple arch images from Docker Hub to AWS Public ECR
#!/bin/bash
set -o errexit # exit on first error
set -o nounset # exit on using unset variables
set -o pipefail # exit on any error in a pipeline
set -x # enable debugging
# Script to mirror multi-arch images from Docker Hub to Amazon ECR Public.
# Usage: ./mirror-multi-arch-repos.sh <source-image>:<tag> <ecr-repo-name>
if [ $# -ne 2 ]; then
echo "Usage: $0 <source-image>:<tag> <ecr-repo-name>"
exit 1
fi
SOURCE_IMAGE_TAG_STR=$1
ECR_REPO_NAME=$2
# Get ECR registry URL
ECR_REGISTRY_URL=$(aws ecr-public describe-registries --region us-east-1 --query 'registries[0].registryUri' --output text)
# Function to extract platform from manifest as a list of json strings
get_platforms() {
docker manifest inspect $SOURCE_IMAGE_TAG_STR | jq -r '.manifests[].platform | select(.architecture!="unknown") | @json'
}
get_suffix() {
local os=$1
local arch=$2
local variant=${3:-""}
prefix="-"
suffix=${os}-${arch}${variant:+$prefix$variant}
echo $suffix
}
# Pull and push images to ECR
pull_and_push_to_ecr() {
# Create ECR repository if it doesn't exist
aws ecr-public create-repository --repository-name $ECR_REPO_NAME --region us-east-1 || true
platforms=( $(get_platforms) )
for platform in "${platforms[@]}"; do
arch=$(echo $platform | jq -r .architecture)
os=$(echo $platform | jq -r .os)
variant=$(echo $platform | jq -r '.variant? // empty')
suffix=$(get_suffix $os $arch $variant)
local source_image_with_platform="${SOURCE_IMAGE_TAG_STR}-${suffix}"
local ecr_image_with_arch="${ECR_REGISTRY_URL}/${source_image_with_platform}"
echo "Pulling $SOURCE_IMAGE_TAG_STR for $suffix"
docker pull --platform $os/$arch${variant:+/$variant} $SOURCE_IMAGE_TAG_STR
echo "Tagging $SOURCE_IMAGE_TAG_STR as $ecr_image_with_arch"
docker tag $SOURCE_IMAGE_TAG_STR $ecr_image_with_arch
echo "Pushing $ecr_image_with_arch to ECR"
docker push $ecr_image_with_arch
done
}
# Create and push manifest list
create_manifest() {
local manifest_list="${ECR_REGISTRY_URL}/${SOURCE_IMAGE_TAG_STR}"
echo "Creating manifest list: $manifest_list"
platforms=( $(get_platforms) )
for platform in "${platforms[@]}"; do
arch=$(echo $platform | jq -r .architecture)
os=$(echo $platform | jq -r .os)
variant=$(echo $platform | jq -r '.variant? // empty')
suffix=$(get_suffix $os $arch $variant)
# Construct the image tag with the suffix
image_tag="${SOURCE_IMAGE_TAG}-${suffix}"
# Add the image to the manifest list
docker manifest create "$manifest_list" "${ECR_REGISTRY_URL}/${SOURCE_IMAGE}:${image_tag}" --amend
docker manifest annotate $manifest_list \
"${ECR_REGISTRY_URL}/${SOURCE_IMAGE}:${image_tag}" \
--os $os --arch $arch ${variant:+--variant $variant}
done
echo "Pushing manifest list to ECR"
docker manifest push $manifest_list
}
# a method to parse the image name and tag from SOURCE_IMAGE_TAG_STR
# e.g. "nginx:latest" will be split into "nginx" and "latest"
SOURCE_IMAGE=$(echo $SOURCE_IMAGE_TAG_STR | cut -d: -f1)
SOURCE_IMAGE_TAG=$(echo $SOURCE_IMAGE_TAG_STR | cut -d: -f2)
# Main execution
echo "Authenticating with ECR"
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws
echo "Pulling multi-architecture images for $SOURCE_IMAGE_TAG_STR, then pushing images to ECR"
pull_and_push_to_ecr
echo "Creating and pushing manifest list"
create_manifest
echo "Mirroring complete for $SOURCE_IMAGE_TAG_STR to ${ECR_REGISTRY_URL}/${ECR_REPO_NAME}"
@zxkane
Copy link
Author

zxkane commented Jul 4, 2024

Usage: ./mirror-multi-arch-repos.sh timberio/vector:0.35.1-debian timberio/vector

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment