Skip to content

Instantly share code, notes, and snippets.

@zAbuQasem
Created February 10, 2025 22:40
Show Gist options
  • Save zAbuQasem/284234e86440bf5bcb973e8bb6cb324d to your computer and use it in GitHub Desktop.
Save zAbuQasem/284234e86440bf5bcb973e8bb6cb324d to your computer and use it in GitHub Desktop.
Download layers of Multi-Platform container images.
#!/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}"
@zAbuQasem
Copy link
Author

A Bash script to interact with OCI/Docker registries. It allows you to:

  • List available images in a registry.
  • Download specific image layers for a given architecture (e.g., amd64, arm64).
  • Handle proxies (HTTP/HTTPS).
  • Save layers to a folder for offline use or analysis.

Use Cases:

  • Inspect image layers without pulling the entire image.
  • Debug registry connectivity issues.
  • Download specific architectures (e.g., for ARM devices).

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:

[*] Fetching available images from registry...
Available images:
[0] alpine
[1] nginx
[2] redis

Select image index (0-2): 1
[+] Selected: nginx
[+] Found amd64 manifest digest: sha256:abc123...
[*] Downloading layers...
[+] Saved as: nginx/sha256_abc123.tar.gz

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:

[+] Found arm64 manifest digest: sha256:def456...
[*] Downloading layers...
[+] Saved as: nginx/sha256_def456.tar.gz

3. Use Proxies

# Download via HTTP proxy (ensure HTTP_PROXY is set)
HTTP_PROXY="http://proxy.example.com:8080" \
./DockerRegistryGrabber-Multi-Platform.sh -r http://registry.internal:5000 -i alpine --http-proxy

Output:

[*] Fetching image index...
[+] Found amd64 manifest digest: sha256:ghi789...
[*] Downloading layers via proxy...

  1. Dependencies:
    sudo apt-get install curl jq

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