Skip to content

Instantly share code, notes, and snippets.

@tsaarni
Last active June 9, 2021 17:39
Show Gist options
  • Save tsaarni/a9a76530f35c301b794bea216cfd8748 to your computer and use it in GitHub Desktop.
Save tsaarni/a9a76530f35c301b794bea216cfd8748 to your computer and use it in GitHub Desktop.
Upload image to registry with uncompressed layers
#!/usr/bin/env python3
import os
import subprocess
import requests
import json
import gzip
import hashlib
SOURCE_IMAGE = 'docker://alpine:latest'
DEST_REGISTRY_URL = 'https://registry.192-168-1-130.nip.io:8443'
DEST_REPO_NAME = 'uncompressed-alpine'
DEST_REPO_TAG = 'latest'
BUF_SIZE = 100000
# unzip compressed layer,
# return hash over unzipped data and uncompressed size
def uncompressed_layer_info(compressed_file):
with gzip.open(compressed_file, 'rb') as f:
buf = f.read(BUF_SIZE)
uncompressed_size = len(buf)
h = hashlib.sha256()
while len(buf) > 0:
h.update(buf)
buf = f.read(BUF_SIZE)
uncompressed_size = uncompressed_size + len(buf)
return 'sha256:' + h.hexdigest(), uncompressed_size
# upload blob to registry
def upload_blob(registry_url, repo, filehandle, digest):
# initiate upload
r = requests.post(
f'{registry_url}/v2/{repo}/blobs/uploads/',
verify=False)
upload_url = r.headers['Location']
# upload file
requests.put(
upload_url,
headers={'Content-Type': 'application/octet-stream'},
params={'digest': digest},
data=filehandle,
verify=False)
# download image
subprocess.call(f'skopeo copy {SOURCE_IMAGE} dir:input', shell=True)
with open('input/manifest.json') as m:
manifest = json.load(m)
# upload uncompressed layers
for layer in manifest['layers']:
layer_filename = os.path.join('input', layer['digest'].split(':')[1])
digest, size = uncompressed_layer_info(layer_filename)
with gzip.open(layer_filename) as f:
upload_blob(DEST_REGISTRY_URL, DEST_REPO_NAME, f, digest)
# update manifest with uncompressed layer info
layer['mediaType'] = 'application/vnd.docker.image.rootfs.diff.tar'
layer['digest'] = digest
layer['size'] = size
# upload image config
digest = manifest['config']['digest']
config_filename = os.path.join('input', digest.split(':')[1])
with open(config_filename) as f:
upload_blob(DEST_REGISTRY_URL, DEST_REPO_NAME, f, digest)
# upload manifest with uncompressed layer references
requests.put(
f'{DEST_REGISTRY_URL}/v2/{DEST_REPO_NAME}/manifests/{DEST_REPO_TAG}',
headers={'Content-Type': 'application/vnd.docker.distribution.manifest.v2+json'},
json=manifest,
verify=False)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment