Created
February 10, 2025 22:40
-
-
Save zAbuQasem/284234e86440bf5bcb973e8bb6cb324d to your computer and use it in GitHub Desktop.
Download layers of Multi-Platform container images.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Author: zAbuQasem | |
# GitHub: https://github.com/zAbuQasem | |
# Script extract only `latest` tag image layers from a the registry, check line 142 to change the tag | |
## You can get tag from the registry by running the following command | |
### curl -s http://localhost:5000/v2/your-image-name/tags/list | |
# Define colors | |
RED='\033[0;31m' | |
GREEN='\033[0;32m' | |
YELLOW='\033[1;33m' | |
BLUE='\033[0;34m' | |
MAGENTA='\033[0;35m' | |
CYAN='\033[0;36m' | |
BOLD='\033[1m' | |
NC='\033[0m' # No Color | |
# Print colored messages | |
info() { echo -e "${BLUE}[*]${NC} $1"; } | |
success() { echo -e "${GREEN}[+]${NC} $1"; } | |
warning() { echo -e "${YELLOW}[!]${NC} $1"; } | |
error() { echo -e "${RED}[-]${NC} $1" >&2; } | |
detail() { echo -e "${CYAN} →${NC} $1"; } | |
# Function to list available images | |
list_images() { | |
local registry_url="$1" | |
info "Fetching available images from registry..." | |
# Fetch catalog | |
catalog_response=$(curl $CURL_OPTS -s "${registry_url}/v2/_catalog") | |
if [ $? -ne 0 ] || [ -z "$catalog_response" ]; then | |
error "Failed to fetch image catalog from ${registry_url}" | |
exit 1 | |
fi | |
# Extract image names | |
images=($(echo "$catalog_response" | jq -r '.repositories[]')) | |
if [ ${#images[@]} -eq 0 ]; then | |
error "No images found in registry" | |
exit 1 | |
fi | |
echo -e "\n${BOLD}Available images:${NC}" | |
for i in "${!images[@]}"; do | |
echo -e "${CYAN}[$i]${NC} ${images[$i]}" | |
done | |
# Prompt for selection | |
while true; do | |
printf "\n${YELLOW}Select image index (0-$((${#images[@]}-1))):${NC} " # Fixed prompt | |
read -r selection | |
if [[ "$selection" =~ ^[0-9]+$ ]] && [ "$selection" -lt "${#images[@]}" ]; then | |
selected_image="${images[$selection]}" | |
echo -e "${GREEN}Selected: ${selected_image}${NC}" | |
echo "$selected_image" # Return the image name directly | |
export image_name="$selected_image" # Export the image name for later use | |
return | |
else | |
warning "Invalid selection. Please try again." | |
fi | |
done | |
} | |
# Function to display usage | |
usage() { | |
echo -e "${BOLD}Usage:${NC} $0 -r <registry-url> [-i <image-name>] [-a <architecture>] [--http-proxy] [--https-proxy]" | |
echo -e "${BOLD}Options:${NC}" | |
echo " -r Registry URL (required)" | |
echo " -i Image name (optional, will list available images if not provided)" | |
echo " -a Architecture (optional, default: amd64)" | |
echo " --http-proxy Enable HTTP proxy" | |
echo " --https-proxy Enable HTTPS proxy" | |
echo | |
echo -e "${BOLD}Example:${NC}" | |
echo " $0 -r http://localhost:5000 -a arm64 --http-proxy" | |
exit 1 | |
} | |
# Initialize variables | |
registry_url="" | |
image_name="" | |
arch="amd64" | |
USE_HTTP_PROXY=0 | |
USE_HTTPS_PROXY=0 | |
# Parse command line arguments | |
while [[ $# -gt 0 ]]; do | |
case $1 in | |
-i) image_name="$2"; shift 2;; | |
-r) registry_url="$2"; shift 2;; | |
-a) arch="$2"; shift 2;; | |
-h) usage; shift;; | |
--http-proxy) USE_HTTP_PROXY=1; shift;; | |
--https-proxy) USE_HTTPS_PROXY=1; shift;; | |
*) echo "Unknown option: $1"; usage;; | |
esac | |
done | |
# Validate registry URL | |
if [ -z "$registry_url" ]; then | |
error "Registry URL is required." | |
usage | |
fi | |
# Validate architecture | |
if [[ ! "$arch" =~ ^(amd64|arm64|arm)$ ]]; then | |
error "Unsupported architecture: $arch. Supported architectures: amd64, arm64, arm." | |
exit 1 | |
fi | |
# Configure proxy settings for curl | |
CURL_OPTS="-s" | |
if [ "$USE_HTTP_PROXY" -eq 1 ]; then | |
if [ -z "$HTTP_PROXY" ]; then | |
error "HTTP_PROXY environment variable is not set." | |
exit 1 | |
fi | |
CURL_OPTS="$CURL_OPTS --proxy $HTTP_PROXY" | |
fi | |
if [ "$USE_HTTPS_PROXY" -eq 1 ]; then | |
if [ -z "$HTTPS_PROXY" ]; then | |
error "HTTPS_PROXY environment variable is not set." | |
exit 1 | |
fi | |
CURL_OPTS="$CURL_OPTS --proxy-insecure --proxy $HTTPS_PROXY" | |
fi | |
# If no image name provided, list available images and prompt for selection | |
if [ -z "$image_name" ]; then | |
list_images "$registry_url" | |
fi | |
# Create a folder for the image | |
image_folder="${image_name//\//_}" # Replace slashes with underscores | |
mkdir -p "$image_folder" | |
# Fetch the image index (manifest list) | |
index_url="${registry_url}/v2/${image_name}/manifests/latest" | |
info "Fetching image index from: ${MAGENTA}${index_url}${NC}" | |
index_response=$(curl $CURL_OPTS -H "Accept: application/vnd.oci.image.index.v1+json" "$index_url") | |
if [ $? -ne 0 ] || [ -z "$index_response" ]; then | |
error "Failed to fetch image index." | |
exit 1 | |
fi | |
# Extract the manifest digest for specified architecture | |
manifest_digest=$(echo "$index_response" | jq -r --arg ARCH "$arch" '.manifests[] | select(.platform.architecture == $ARCH and .platform.os == "linux") | .digest') | |
if [ -z "$manifest_digest" ]; then | |
error "No ${arch} image found in the manifest list." | |
exit 1 | |
fi | |
success "Found ${arch} manifest digest: ${MAGENTA}${manifest_digest}${NC}" | |
# Fetch the manifest | |
manifest_url="${registry_url}/v2/${image_name}/manifests/${manifest_digest}" | |
info "Fetching ${arch} manifest from: ${MAGENTA}${manifest_url}${NC}" | |
manifest_response=$(curl $CURL_OPTS -H "Accept: application/vnd.oci.image.manifest.v1+json" "$manifest_url") | |
if [ $? -ne 0 ] || [ -z "$manifest_response" ]; then | |
error "Failed to fetch ${arch} manifest." | |
exit 1 | |
fi | |
# Extract layer digests | |
digests=$(echo "$manifest_response" | jq -r '.layers[].digest') | |
if [ -z "$digests" ]; then | |
error "No layers found in the ${arch} manifest." | |
exit 1 | |
fi | |
# Download each layer | |
echo -e "\n${BOLD}Downloading layers:${NC}" | |
for digest in $digests; do | |
url="${registry_url}/v2/${image_name}/blobs/${digest}" | |
filename="${digest//:/_}.tar.gz" | |
filepath="${image_folder}/${filename}" | |
info "Processing layer: ${MAGENTA}${digest}${NC}" | |
detail "URL: ${url}" | |
if ! curl $CURL_OPTS -f -o "$filepath" "$url"; then | |
error "Failed to download layer: ${digest}" | |
exit 1 | |
fi | |
success "Saved as: ${filepath}" | |
echo -e "${CYAN}----------------------------------------${NC}" | |
done | |
success "All layers for ${BOLD}${arch}${NC} image downloaded successfully into folder: ${MAGENTA}${image_folder}${NC}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A Bash script to interact with OCI/Docker registries. It allows you to:
amd64
,arm64
).Use Cases:
Example Usage
1. Basic Usage: List Images & Download Layers
# List images interactively and download layers for selected image ./DockerRegistryGrabber-Multi-Platform.sh -r http://localhost:5000
Output:
2. Specify Image and Architecture
# Directly download layers for the "nginx" image (ARM64) ./DockerRegistryGrabber-Multi-Platform.sh -r http://localhost:5000 -i nginx -a arm64
Output:
3. Use Proxies
Output: