αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆ docker pull αž“αž·αž„ docker push αžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž—αŸ’αž‰αŸ€αžœ docker αžŠαŸ„αž™αž”αŸ’αžšαžΎαžŸαŸ†αžŽαžΎ HTTP

αž™αžΎαž„αž˜αžΆαž“αžŸαŸ’αž˜αŸ… 2 αž”αžΆαžœ 75 αž‚αŸ’αžšαžΆαž”αŸ‹ mescaline unix αž”αžšαž·αžŸαŸ’αžαžΆαž“ αžƒαŸ’αž›αžΆαŸ†αž„ docker αž“αž·αž„αž—αžΆαžšαž€αž·αž…αŸ’αž…αž’αž“αž»αžœαžαŸ’αžαž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆ docker pull αž“αž·αž„ docker push αžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž—αŸ’αž‰αŸ€αžœ docker αŸ”

αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆ docker pull αž“αž·αž„ docker push αžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž—αŸ’αž‰αŸ€αžœ docker αžŠαŸ„αž™αž”αŸ’αžšαžΎαžŸαŸ†αžŽαžΎ HTTP

UPSαŸ–
αžŸαŸ†αžŽαž½αžšαŸ– αžαžΎαž‘αžΆαŸ†αž„αž’αžŸαŸ‹αž“αŸαŸ‡αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αŸ’αžœαžΈ?
αž…αž˜αŸ’αž›αžΎαž™αŸ– αž•αŸ’αž‘αž»αž€αž€αžΆαžšαž’αŸ’αžœαžΎαžαŸαžŸαŸ’αžαž•αž›αž·αžαž•αž› (αž˜αž·αž“αž”αŸ’αžšαžΎαž”αžΆαžŸαž‘αŸ αžŸαŸ’αž‚αŸ’αžšαžΈαž”αžαŸ’αžšαžΌαžœαž”αžΆαž“αž•αŸ’αžαž›αŸ‹αž‡αžΌαž“αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž‚αŸ„αž›αž”αŸ†αžŽαž„αž’αž”αŸ‹αžšαŸ†)αŸ” αžœαžΆαžαŸ’αžšαžΌαžœαž”αžΆαž“αžŸαž˜αŸ’αžšαŸαž…αž…αž·αžαŸ’αžαž˜αž·αž“αž”αŸ’αžšαžΎαž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž—αŸ’αž‰αŸ€αžœ docker αžŠαžΎαž˜αŸ’αž”αžΈαž€αžΆαžαŸ‹αž”αž“αŸ’αžαž™αžŸαŸ’αžšαž‘αžΆαž”αŸ‹αž”αž“αŸ’αžαŸ‚αž˜ (αž€αŸ’αž“αž»αž„αžŠαŸ‚αž“αž€αŸ†αžŽαžαŸ‹αžŸαž˜αž αŸαžαž»αž•αž›) αž αžΎαž™αžαžΆαž˜αž“αŸ„αŸ‡ αž’αŸ’αžœαžΎαžαŸ’αžšαžΆαž”αŸ‹αžαžΆαž˜αž€αžΆαžšαž•αŸ’αž‘αž»αž€αžαŸ’αž–αžŸαŸ‹αž‡αžΆαž„αž“αŸαŸ‡αŸ” αž‡αžΆαž›αž‘αŸ’αž’αž•αž› αž€αžΆαžšαž–αž“αŸ’αž™αžΆαžšαž–αŸαž›αž”αŸ’αžšαž–αŸαž“αŸ’αž’αž‘αžΆαŸ†αž„αž’αžŸαŸ‹αžšαž”αžŸαŸ‹αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž—αŸ’αž‰αŸ€αžœ Docker αžαŸ’αžšαžΌαžœαž”αžΆαž“αžŠαž€αž…αŸαž‰αŸ” αž™αžΎαž„αž”αžΆαž“αž‘αž‘αž½αž›αž”αž“αŸ’αž‘αž»αž€αžŸαŸ’αž’αžΆαžαžŠαŸ„αž™αž•αŸ’αž‘αžΆαž›αŸ‹αž“αŸ…αž›αžΎαž•αž›αž·αžαž•αž›αŸ”
αž’αžαŸ’αžαž”αž‘αž”αžΆαž“αž”αŸ’αžšαžΎαž€αŸ†αžŽαŸ‚ GNU αž“αŸƒαž§αž”αž€αžšαžŽαŸαŸ”

αž‡αžΆαžŠαŸ†αž”αžΌαž„ αž…αžΌαžšαž™αžΎαž„αžŸαŸ’αžœαŸ‚αž„αž™αž›αŸ‹αžαžΆαžαžΎαž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆαž‘αžΆαŸ†αž„αž“αŸαŸ‡αž’αŸ’αžœαžΎαž’αŸ’αžœαžΈαŸ”

αžŠαžΌαž…αŸ’αž“αŸαŸ‡αžαžΎ docker pull αž”αŸ’αžšαžΎαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αŸ’αžœαžΈ? αž™αŸ„αž„β€‹αž‘αŸ…β€‹αžαžΆαž˜ αž―αž€αžŸαžΆαžš:

"αž‘αžΆαž‰αžšαžΌαž”αž—αžΆαž– αž¬αžƒαŸ’αž›αžΆαŸ†αž„αž–αžΈαž”αž‰αŸ’αž‡αžΈαžˆαŸ’αž˜αŸ„αŸ‡"αŸ”

αž“αŸ…αž‘αžΈαž“αŸ„αŸ‡αž™αžΎαž„αž€αŸαžšαž€αžƒαžΎαž‰αžαŸ†αžŽαž—αŸ’αž‡αžΆαž”αŸ‹αž‘αŸ… αž™αž›αŸ‹αž’αŸ†αž–αžΈαžšαžΌαž”αž—αžΆαž– αž’αž»αž„ αž“αž·αž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž”αž‰αŸ’αž‡αžΆαž•αŸ’αž‘αž»αž€.

αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆ docker pull αž“αž·αž„ docker push αžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž—αŸ’αž‰αŸ€αžœ docker αžŠαŸ„αž™αž”αŸ’αžšαžΎαžŸαŸ†αžŽαžΎ HTTP

αž–αžΈαž‘αžΈαž“αŸαŸ‡ αž™αžΎαž„αž’αžΆαž…αž™αž›αŸ‹αž”αžΆαž“αžαžΆ αžšαžΌαž”αž—αžΆαž– docker αž‚αžΊαž‡αžΆαžŸαŸ†αžŽαž»αŸ†αž“αŸƒαžŸαŸ’αžšαž‘αžΆαž”αŸ‹αž˜αž½αž™αž…αŸ†αž“αž½αž“αžŠαŸ‚αž›αž˜αžΆαž“αž–αŸαžαŸŒαž˜αžΆαž“αž’αŸ†αž–αžΈαž€αžΆαžšαž•αŸ’αž›αžΆαžŸαŸ‹αž”αŸ’αžαžΌαžšαž…αž»αž„αž€αŸ’αžšαŸ„αž™αž”αŸ†αž•αž»αžαž“αŸ…αž€αŸ’αž“αž»αž„αžšαžΌαž”αž—αžΆαž– αžŠαŸ‚αž›αž…αŸ’αž”αžΆαžŸαŸ‹αž‡αžΆαž’αŸ’αžœαžΈαžŠαŸ‚αž›αž™αžΎαž„αžαŸ’αžšαžΌαžœαž€αžΆαžšαŸ” αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž™αžΎαž„αž˜αžΎαž› API αž…αž»αŸ‡αž”αž‰αŸ’αž‡αžΈ.

αžœαžΆαž“αž·αž™αžΆαž™αžŠαžΌαž…αžαžΆαž„αž€αŸ’αžšαŸ„αž˜αŸˆ

"αžšαžΌαž”αž—αžΆαž–" αž‚αžΊαž‡αžΆαž€αžΆαžšαžšαž½αž˜αž”αž‰αŸ’αž…αžΌαž›αž‚αŸ’αž“αžΆαž“αŸƒ JSON manifest αž“αž·αž„αž―αž€αžŸαžΆαžšαžŸαŸ’αžšαž‘αžΆαž”αŸ‹αž“αžΈαž˜αž½αž™αŸ—αŸ” αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž“αŸƒαž€αžΆαžšαž‘αžΆαž‰ > αžšαžΌαž”αž—αžΆαž–αž•αŸ’αžαŸ„αžαž‡αž»αŸ†αžœαž·αž‰αž€αžΆαžšαž‘αžΆαž‰αž™αž€αžŸαž˜αžΆαžŸαž’αžΆαžαž»αž‘αžΆαŸ†αž„αž–αžΈαžšαž“αŸαŸ‡αŸ”"

αžŠαžΌαž…αŸ’αž“αŸαŸ‡αž‡αŸ†αž αžΆαž“αžŠαŸ†αž”αžΌαž„αž™αŸ„αž„αž‘αŸ…αžαžΆαž˜αž―αž€αžŸαžΆαžšαž‚αžΊ "αž€αžΆαžšαž‘αžΆαž‰αž€αžΆαžšαž”αž„αŸ’αž αžΆαž‰αžšαžΌαž”αž—αžΆαž–"αŸ”

αž‡αžΆαž€αžΆαžšαž–αž·αžαžŽαžΆαžŸαŸ‹ αž™αžΎαž„αž“αžΉαž„αž˜αž·αž“αž”αžΆαž‰αŸ‹αžœαžΆαž‘αŸ αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž™αžΎαž„αžαŸ’αžšαžΌαžœαž€αžΆαžšαž‘αž·αž“αŸ’αž“αž“αŸαž™αž–αžΈαžœαžΆαŸ” αžαžΆαž„β€‹αž€αŸ’αžšαŸ„αž˜β€‹αž“αŸαŸ‡β€‹αž‚αžΊβ€‹αž‡αžΆβ€‹αžŸαŸ†αžŽαžΎβ€‹αž§αž‘αžΆαž αžšαžŽαŸαŸ– GET /v2/{name}/manifests/{reference}

"αžˆαŸ’αž˜αŸ„αŸ‡ αž“αž·αž„αž”αŸ‰αžΆαžšαŸ‰αžΆαž˜αŸ‰αŸ‚αžαŸ’αžšαž™αŸ„αž„αž€αŸ†αžŽαžαŸ‹αž’αžαŸ’αžαžŸαž‰αŸ’αž‰αžΆαžŽαžšαžΌαž”αž—αžΆαž– αž αžΎαž™αžαŸ’αžšαžΌαžœαž”αžΆαž“αž‘αžΆαž˜αž‘αžΆαžšαŸ” αž―αž€αžŸαžΆαžšαž™αŸ„αž„αž’αžΆαž…αžšαž½αž˜αž”αž‰αŸ’αž…αžΌαž›αžŸαŸ’αž›αžΆαž€ αž¬αžŸαž„αŸ’αžαŸαž”αŸ”"

αžƒαŸ’αž›αžΆαŸ†αž„ docker αžšαž”αžŸαŸ‹αž™αžΎαž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αžŠαžΆαž€αŸ‹αž–αž„αŸ’αžšαžΆαž™αž€αŸ’αž“αž»αž„αžŸαŸ’αžšαž»αž€ αžŸαžΌαž˜αž–αŸ’αž™αžΆαž™αžΆαž˜αž’αž“αž»αžœαžαŸ’αžαžŸαŸ†αžŽαžΎαŸ–

curl -s -X GET "http://localhost:8081/link/to/docker/registry/v2/centos-11-10/manifests/1.1.1" -H "header_if_needed"

αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆ docker pull αž“αž·αž„ docker push αžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž—αŸ’αž‰αŸ€αžœ docker αžŠαŸ„αž™αž”αŸ’αžšαžΎαžŸαŸ†αžŽαžΎ HTTP

αž‡αžΆαž€αžΆαžšαž†αŸ’αž›αžΎαž™αžαž” αž™αžΎαž„αž‘αž‘αž½αž›αž”αžΆαž“ json αžŠαŸ‚αž›αž”αž…αŸ’αž…αž»αž”αŸ’αž”αž“αŸ’αž“αž™αžΎαž„αž…αžΆαž”αŸ‹αž’αžΆαžšαž˜αŸ’αž˜αžŽαŸαžαŸ‚αž›αžΎαžαŸ’αžŸαŸ‚αž‡αžΈαžœαž·αž αž¬αž‡αžΆαžŸαž‰αŸ’αž‰αžΆαžšαž”αžŸαŸ‹αž–αž½αž€αžœαžΆαŸ” αžŠαŸ„αž™αž”αžΆαž“αž‘αž‘αž½αž›αž–αž½αž€αžœαžΆ αž™αžΎαž„αž’αžΆαž…αž†αŸ’αž›αž„αž€αžΆαžαŸ‹αžŸαŸ†αžŽαžΎαž“αžΈαž˜αž½αž™αŸ— αž“αž·αž„αž’αž“αž»αžœαžαŸ’αžαžŸαŸ†αžŽαžΎαžŠαžΌαž…αžαžΆαž„αž€αŸ’αžšαŸ„αž˜αŸ– "GET /v2/{name}/blobs/{digest}"

"αž€αžΆαžšαž…αžΌαž›αž‘αŸ…αž€αžΆαž“αŸ‹αžŸαŸ’αžšαž‘αžΆαž”αŸ‹αž˜αž½αž™αž“αžΉαž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αž·αž‘αžŠαŸ„αž™αžˆαŸ’αž˜αŸ„αŸ‡αž“αŸƒαžƒαŸ’αž›αžΆαŸ†αž„ αž”αŸ‰αž»αž“αŸ’αžαŸ‚αžαŸ’αžšαžΌαžœαž”αžΆαž“αž€αŸ†αžŽαžαŸ‹αž’αžαŸ’αžαžŸαž‰αŸ’αž‰αžΆαžŽαžαŸ‚αž˜αž½αž™αž‚αžαŸ‹αž“αŸ…αž€αŸ’αž“αž»αž„αž”αž‰αŸ’αž‡αžΈαžˆαŸ’αž˜αŸ„αŸ‡αžŠαŸ„αž™αž€αžΆαžšαžŸαž„αŸ’αžαŸαž”αŸ”"

digest αž€αŸ’αž“αž»αž„αž€αžšαžŽαžΈαž“αŸαŸ‡αž‚αžΊαž‡αžΆ hash αžŠαŸ‚αž›αž™αžΎαž„αž”αžΆαž“αž‘αž‘αž½αž›αŸ”

αž€αŸ†αž–αž»αž„αž–αŸ’αž™αžΆαž™αžΆαž˜

curl -s -X GET "http://localhost:8081/link/to/docker/registry/v2/centos-11-10/blobs/sha256:f972d139738dfcd1519fd2461815651336ee25a8b54c358834c50af094bb262f" -H "header_if_needed" --output firstLayer

αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆ docker pull αž“αž·αž„ docker push αžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž—αŸ’αž‰αŸ€αžœ docker αžŠαŸ„αž™αž”αŸ’αžšαžΎαžŸαŸ†αžŽαžΎ HTTP

αžŸαžΌαž˜αž˜αžΎαž›αžαžΆαžαžΎαž―αž€αžŸαžΆαžšαž”αŸ’αžšαž—αŸαž‘αžŽαžΆαžŠαŸ‚αž›αž‘αžΈαž”αŸ†αž•αž»αžαž™αžΎαž„αž”αžΆαž“αž‘αž‘αž½αž›αž‡αžΆαžαŸ’αžŸαŸ‚αž‡αžΈαžœαž·αžαžŠαŸ†αž”αžΌαž„αŸ”

file firstLayer

αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆ docker pull αž“αž·αž„ docker push αžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž—αŸ’αž‰αŸ€αžœ docker αžŠαŸ„αž™αž”αŸ’αžšαžΎαžŸαŸ†αžŽαžΎ HTTP

αž‘αžΆαŸ†αž„αž“αŸ„αŸ‡αŸ” αž•αŸ’αž›αžΌαžœαžšαžαž—αŸ’αž›αžΎαž„αž‚αžΊαž‡αžΆαž”αžŽαŸ’αžŽαžŸαžΆαžš tar αžŠαŸ„αž™αž–αž“αŸ’αž›αžΆαž–αž½αž€αžœαžΆαžαžΆαž˜αž›αŸ†αžŠαžΆαž”αŸ‹αžŸαž˜αžŸαŸ’αžšαž”αž™αžΎαž„αž“αžΉαž„αž‘αž‘αž½αž›αž”αžΆαž“αž˜αžΆαžαž·αž€αžΆαž“αŸƒαžšαžΌαž”αž—αžΆαž–αŸ”

αž…αžΌαžšαž™αžΎαž„αžŸαžšαžŸαŸαžšαžŸαŸ’αž‚αŸ’αžšαžΈαž” bash αžαžΌαž…αž˜αž½αž™αžŠαžΎαž˜αŸ’αž”αžΈαž±αŸ’αž™αž’αŸ’αžœαžΈαŸ—αž‘αžΆαŸ†αž„αž’αžŸαŸ‹αž“αŸαŸ‡αž’αžΆαž…αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžŠαŸ„αž™αžŸαŸ’αžœαŸαž™αž”αŸ’αžšαžœαžαŸ’αžαž·

#!/bin/bash -eu

downloadDir=$1
# url as http://localhost:8081/link/to/docker/registry
url=$2
imageName=$3
tag=$4

# array of layers
layers=($(curl -s -X GET "$url/v2/$imageName/manifests/$tag" | grep -oP '(?<=blobSum" : ").+(?=")'))

# download each layer from array
for layer in "${layers[@]}"; do
    echo "Downloading ${layer}"
    curl -v -X GET "$url/v2/$imageName/blobs/$layer" --output "$downloadDir/$layer.tar"
done

# find all layers, untar them and remove source .tar files
cd "$downloadDir" && find . -name "sha256:*" -exec tar xvf {} ;
rm sha256:*.tar
exit 0

αž₯αž‘αžΌαžœαž“αŸαŸ‡αž™αžΎαž„αž’αžΆαž…αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžœαžΆαž‡αžΆαž˜αž½αž™αž“αžΉαž„αž”αŸ‰αžΆαžšαŸ‰αžΆαž˜αŸ‰αŸ‚αžαŸ’αžšαžŠαŸ‚αž›αž…αž„αŸ‹αž”αžΆαž“αž αžΎαž™αž‘αž‘αž½αž›αž”αžΆαž“αž˜αžΆαžαž·αž€αžΆαž“αŸƒαžšαžΌαž”αž—αžΆαž–αžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž€αžΆαžš

./script.sh dirName β€œhttp://localhost:8081/link/to/docker/registry” myAwesomeImage 1.0

αž•αŸ’αž“αŸ‚αž€αž‘αžΈ 2 - αž€αžΆαžšαžšαž»αž‰ docker

αž“αŸαŸ‡αž“αžΉαž„αž˜αžΆαž“αž—αžΆαž–αžŸαŸ’αž˜αž»αž‚αžŸαŸ’αž˜αžΆαž‰αž”αž“αŸ’αžαž·αž…αŸ”

αžαŸ„αŸ‡αž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜αž˜αŸ’αžαž„αž‘αŸ€αžαž‡αžΆαž˜αž½αž™ αž―αž€αžŸαžΆαžš. αžŠαžΌαž…αŸ’αž“αŸαŸ‡αž™αžΎαž„αžαŸ’αžšαžΌαžœαž‘αžΆαž‰αž™αž€αž’αŸ’αž“αž€αžŠαžΉαž€αž“αžΆαŸ†αž“αžΈαž˜αž½αž™αŸ— αž”αŸ’αžšαž˜αžΌαž› manifest αžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž‚αŸ’αž“αžΆ αž αžΎαž™αž‘αžΆαž‰αž™αž€αžœαžΆαž•αž„αžŠαŸ‚αžšαŸ” αžœαžΆαž αžΆαž€αŸ‹αžŠαžΌαž…αž‡αžΆαžŸαžΆαž˜αž‰αŸ’αž‰αŸ”

αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž–αžΈαžŸαž·αž€αŸ’αžŸαžΆαž―αž€αžŸαžΆαžšαžšαž½αž… αž™αžΎαž„αž’αžΆαž…αž”αŸ‚αž„αž…αŸ‚αž€αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž‘αžΆαž‰αž™αž€αž‡αžΆαž‡αŸ†αž αžΆαž“αž‡αžΆαž…αŸ’αžšαžΎαž“αŸ–

  • αž€αžΆαžšαž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜αžŠαŸ†αžŽαžΎαžšαž€αžΆαžš - "POST /v2/{repoName}/blobs/uploads/"
  • αž€αžΆαžšαž”αž„αŸ’αž αŸ„αŸ‡αžαŸ’αžŸαŸ‚αž”αž“αŸ’αž‘αžΆαžαŸ‹αž‡αžΈαžœαž·αž (αž™αžΎαž„αž“αžΉαž„αž”αŸ’αžšαžΎαž€αžΆαžšαž”αž„αŸ’αž αŸ„αŸ‡ monolithic αž–αŸ„αž›αž‚αžΊ αž™αžΎαž„αž•αŸ’αž‰αžΎαžαŸ’αžŸαŸ‚αž‡αžΈαžœαž·αžαž“αžΈαž˜αž½αž™αŸ—αž‘αžΆαŸ†αž„αžŸαŸ’αžšαž»αž„) - "PUT /v2/{repoName}/blobs/uploads/{uuid}?digest={digest}
    αž”αŸ’αžšαžœαŸ‚αž„αžαŸ’αž›αžΉαž˜αžŸαžΆαžšαŸ– {αž‘αŸ†αž αŸ†αžŸαŸ’αžšαž‘αžΆαž”αŸ‹}
    αž”αŸ’αžšαž—αŸαž‘αž˜αžΆαžαž·αž€αžΆαŸ– αž€αž˜αŸ’αž˜αžœαž·αž’αžΈ/octet-stream
    αžŸαŸ’αžšαž‘αžΆαž”αŸ‹αž‘αž·αž“αŸ’αž“αž“αŸαž™αž‚αŸ„αž›αž–αžΈαžš"αŸ”
  • αž€αŸ†αž–αž»αž„αž•αŸ’αž‘αž»αž€ manifest - "PUT /v2/{repoName}/manifests/{reference}"αŸ”

αž”αŸ‰αž»αž“αŸ’αžαŸ‚β€‹αž―αž€αžŸαžΆαžšβ€‹αž“αŸαŸ‡β€‹αžαž€αžαžΆαž“β€‹αž˜αž½αž™β€‹αž‡αŸ†αž αžΆαž“ αžŠαŸ„αž™β€‹αž‚αŸ’αž˜αžΆαž“β€‹αž’αŸ’αžœαžΈβ€‹αž“αžΉαž„β€‹αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšβ€‹αž‘αžΎαž™αŸ” αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž•αŸ’αž‘αž»αž€ monolithic αž€αŸαžŠαžΌαž…αž‡αžΆαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž•αŸ’αž“αŸ‚αž€αžαŸ’αž›αŸ‡ (αž€αŸ†αžŽαžΆαžαŸ‹) αž˜αž»αž“αž–αŸαž›αž•αŸ’αž‘αž»αž€αž•αŸ’αž›αžΌαžœαžŠαŸ‚αž€ αž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαžαŸ‚αž’αž“αž»αžœαžαŸ’αžαžŸαŸ†αžŽαžΎ PATCHαŸ–

"PATCH /v2/{repoName}/blobs/uploads/{uuid}
αž”αŸ’αžšαžœαŸ‚αž„αžαŸ’αž›αžΉαž˜αžŸαžΆαžšαŸ– {αž‘αŸ†αž αŸ†αž€αŸ†αžŽαžΆαžαŸ‹}
αž”αŸ’αžšαž—αŸαž‘αž˜αžΆαžαž·αž€αžΆαŸ– αž€αž˜αŸ’αž˜αžœαž·αž’αžΈ/octet-stream
{Layer Chunk Binary Data}"αŸ”

αž”αžΎαž˜αž·αž“αžŠαžΌαž…αŸ’αž“αŸαŸ‡αž‘αŸ αž’αŸ’αž“αž€αž“αžΉαž„αž˜αž·αž“αž’αžΆαž…αž αž½αžŸαž–αžΈαž…αŸ†αžŽαž»αž…αž‘αžΈαž˜αž½αž™αž”αžΆαž“αž‘αŸ αž–αŸ’αžšαŸ„αŸ‡... αž‡αŸ†αž“αž½αžŸαž±αŸ’αž™αž›αŸαžαž€αžΌαžŠαž†αŸ’αž›αžΎαž™αžαž”αžŠαŸ‚αž›αžšαŸ†αž–αžΉαž„αž‘αž»αž€ 202 αž’αŸ’αž“αž€αž“αžΉαž„αž‘αž‘αž½αž›αž”αžΆαž“ 4xx αŸ”

αž₯αž‘αžΌαžœαž“αŸαŸ‡αž€αŸ’αž”αž½αž“αžŠαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αž˜αžΎαž›αž‘αŸ…αžŠαžΌαž…αž“αŸαŸ‡:

  • αž€αžΆαžšαž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜
  • αž•αŸ’αž›αžΌαžœαžŠαŸ‚αž€αž”αŸ†αžŽαŸ‡
  • αž€αŸ†αž–αž»αž„αž•αŸ’αž‘αž»αž€αžŠαŸƒ
  • αž€αŸ†αž–αž»αž„αž•αŸ’αž‘αž»αž€ manifest
    αž…αŸ†αž“αž»αž…αž‘αžΈ 2 αž“αž·αž„αž‘αžΈ 3 αž“αžΉαž„αžαŸ’αžšαžΌαžœαž’αŸ’αžœαžΎαž˜αŸ’αžαž„αž‘αŸ€αžαž…αŸ’αžšαžΎαž“αžŠαž„αžαžΆαž˜αž…αŸ†αž“αž½αž“αž”αž“αŸ’αž‘αžΆαžαŸ‹αžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž•αŸ’αž‘αž»αž€αŸ”

αžŠαŸ†αž”αžΌαž„αž™αžΎαž„αžαŸ’αžšαžΌαžœαž€αžΆαžšαžšαžΌαž”αž—αžΆαž–αžŽαžΆαž˜αž½αž™αŸ” αžαŸ’αž‰αž»αŸ†αž“αžΉαž„αž”αŸ’αžšαžΎ archlinux:latest

docker pull archlinux

αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆ docker pull αž“αž·αž„ docker push αžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž—αŸ’αž‰αŸ€αžœ docker αžŠαŸ„αž™αž”αŸ’αžšαžΎαžŸαŸ†αžŽαžΎ HTTP

αž₯αž‘αžΌαžœαž“αŸαŸ‡αžŸαžΌαž˜αžšαž€αŸ’αžŸαžΆαž‘αž»αž€αžœαžΆαž“αŸ…αž€αŸ’αž“αž»αž„αž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαžœαž·αž—αžΆαž‚αž”αž“αŸ’αžαŸ‚αž˜

docker save c24fe13d37b9 -o savedArch

αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆ docker pull αž“αž·αž„ docker push αžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž—αŸ’αž‰αŸ€αžœ docker αžŠαŸ„αž™αž”αŸ’αžšαžΎαžŸαŸ†αžŽαžΎ HTTP

αž–αž“αŸ’αž›αžΆαž”αŸαžŽαŸ’αžŽαžŸαžΆαžšαž›αž‘αŸ’αž’αž•αž›αž‘αŸ…αž€αŸ’αž“αž»αž„αžαžαž”αž…αŸ’αž…αž»αž”αŸ’αž”αž“αŸ’αž“

tar xvf savedArch

αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆ docker pull αž“αž·αž„ docker push αžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž—αŸ’αž‰αŸ€αžœ docker αžŠαŸ„αž™αž”αŸ’αžšαžΎαžŸαŸ†αžŽαžΎ HTTP

αžŠαžΌαž…αžŠαŸ‚αž›αž’αŸ’αž“αž€αž’αžΆαž…αžƒαžΎαž‰αžαŸ’αžŸαŸ‚αž‡αžΈαžœαž·αžαž“αžΈαž˜αž½αž™αŸ—αžŸαŸ’αžαž·αžαž“αŸ…αž€αŸ’αž“αž»αž„αžαžαžŠαžΆαž…αŸ‹αžŠαŸ„αž™αž‘αŸ‚αž€αž˜αž½αž™αŸ” αž₯αž‘αžΌαžœαž“αŸαŸ‡αžŸαžΌαž˜αž˜αžΎαž›αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αž“αŸƒ manifest αžŠαŸ‚αž›αž™αžΎαž„αž”αžΆαž“αž‘αž‘αž½αž›

cat manifest.json | json_pp

αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆ docker pull αž“αž·αž„ docker push αžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž—αŸ’αž‰αŸ€αžœ docker αžŠαŸ„αž™αž”αŸ’αžšαžΎαžŸαŸ†αžŽαžΎ HTTP

αž˜αž·αž“β€‹αž…αŸ’αžšαžΎαž“αŸ” αžαŸ„αŸ‡αž˜αžΎαž›αž’αŸ’αžœαžΈαžŠαŸ‚αž› manifest αžαŸ’αžšαžΌαžœαž€αžΆαžšαžŠαžΎαž˜αŸ’αž”αžΈαž•αŸ’αž‘αž»αž€ αž“αŸαŸ‡αž”αžΎαž™αŸ„αž„αžαžΆαž˜ αž―αž€αžŸαžΆαžš.

αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆ docker pull αž“αž·αž„ docker push αžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž—αŸ’αž‰αŸ€αžœ docker αžŠαŸ„αž™αž”αŸ’αžšαžΎαžŸαŸ†αžŽαžΎ HTTP

αž‡αžΆαž€αŸ‹αžŸαŸ’αžαŸ‚αž„ αž€αžΆαžšαž”αž„αŸ’αž αžΆαž‰αžŠαŸ‚αž›αž˜αžΆαž“αžŸαŸ’αžšαžΆαž”αŸ‹αž˜αž·αž“αžŸαž˜αž“αžΉαž„αž™αžΎαž„αž‘αŸ αžŠαžΌαž…αŸ’αž“αŸαŸ‡αž™αžΎαž„αž“αžΉαž„αž”αž„αŸ’αž€αžΎαžαžŠαŸ„αž™αžαŸ’αž›αž½αž“αž―αž„αž‡αžΆαž˜αž½αž™αž“αžΉαž„ blackjack αž“αž·αž„ courtesans, lifelines αž“αž·αž„ configs αŸ”

αž™αžΎαž„αžαŸ‚αž„αžαŸ‚αž˜αžΆαž“αž―αž€αžŸαžΆαžšαž€αŸ†αžŽαžαŸ‹αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αž™αŸ‰αžΆαž„αž αŸ„αž…αžŽαžΆαžŸαŸ‹αž˜αž½αž™ αž“αž·αž„αž’αžΆαžšαŸαž“αŸƒαžαŸ’αžŸαŸ‚αž‡αžΈαžœαž·αžαŸ” αž‚αŸ’αžšαŸ„αž„αž€αžΆαžšαžŽαŸαž€αŸ†αžŽαŸ‚ 2 (αž”αž…αŸ’αž…αž»αž”αŸ’αž”αž“αŸ’αž“αž“αŸ…αž–αŸαž›αžŸαžšαžŸαŸαžš) αž”αŸ’αžšαž—αŸαž‘αž˜αŸαžŒαŸ€αž“αžΉαž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αž‘αž»αž€αž…αŸ„αž›αž˜αž·αž“αž•αŸ’αž›αžΆαžŸαŸ‹αž”αŸ’αžαžΌαžšαŸ–

echo β€˜{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
   "config": {
      "mediaType": "application/vnd.docker.container.image.v1+json",
      "size": config_size,
      "digest": "config_hash"
   },
   "layers": [
      ’ > manifest.json

αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž–αžΈαž”αž„αŸ’αž€αžΎαž manifest αž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“ αž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαž”αŸ†αž–αŸαž‰αžœαžΆαž‡αžΆαž˜αž½αž™αž“αžΉαž„αž‘αž·αž“αŸ’αž“αž“αŸαž™αžαŸ’αžšαžΉαž˜αžαŸ’αžšαžΌαžœαŸ” αžŠαžΎαž˜αŸ’αž”αžΈαž’αŸ’αžœαžΎαžŠαžΌαž…αž“αŸαŸ‡αž™αžΎαž„αž”αŸ’αžšαžΎαž‚αŸ†αžšαžΌ json αž“αŸƒαžœαžαŸ’αžαž»αž•αŸ’αž›αžΌαžœαžŠαŸ‚αž€αŸ–

{
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": ${layersSizes[$i]},
         "digest": "sha256:${layersNames[$i]}"
      },

αž™αžΎαž„αž“αžΉαž„αž”αž“αŸ’αžαŸ‚αž˜αžœαžΆαž‘αŸ… manifest αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž•αŸ’αž›αžΌαžœαžšαžαž—αŸ’αž›αžΎαž„αž“αžΈαž˜αž½αž™αŸ—αŸ”

αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž˜αž€ αž™αžΎαž„αžαŸ’αžšαžΌαžœαžŸαŸ’αžœαŸ‚αž„αžšαž€αž‘αŸ†αž αŸ†αž“αŸƒαž―αž€αžŸαžΆαžšαž€αŸ†αžŽαžαŸ‹αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’ αž αžΎαž™αž‡αŸ†αž“αž½αžŸ stubs αž€αŸ’αž“αž»αž„ manifest αž‡αžΆαž˜αž½αž™αž‘αž·αž“αŸ’αž“αž“αŸαž™αž–αž·αž

sed -i "s/config_size/$configSize/g; s/config_hash/$configName/g" $manifestFile

αž₯αž‘αžΌαžœαž“αŸαŸ‡αž’αŸ’αž“αž€αž’αžΆαž…αž•αŸ’αžαž½αž…αž•αŸ’αžαžΎαž˜αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž‘αžΆαž‰αž™αž€ αž“αž·αž„αžšαž€αŸ’αžŸαžΆαž‘αž»αž€αžαŸ’αž›αž½αž“αž’αŸ’αž“αž€αž“αžΌαžœ uuid αžŠαŸ‚αž›αž‚αž½αžšαž’αž˜αž‡αžΆαž˜αž½αž™αžŸαŸ†αžŽαžΎαž‡αžΆαž”αž“αŸ’αžαž”αž“αŸ’αž‘αžΆαž”αŸ‹αž‘αžΆαŸ†αž„αž’αžŸαŸ‹αŸ”

αžŸαŸ’αž‚αŸ’αžšαžΈαž”αž–αŸαž‰αž›αŸαž‰αž˜αžΎαž›αž‘αŸ…αžŠαžΌαž…αž“αŸαŸ‡αŸ–

#!/bin/bash -eux

imageDir=$1
# url as http://localhost:8081/link/to/docker/registry
url=$2
repoName=$3
tag=$4
manifestFile=$(readlink -f ${imageDir}/manifestCopy)
configFile=$(readlink -f $(find $imageDir -name "*.json" ! -name "manifest.json"))

# calc layers sha 256 sum, rename them accordingly, and add info about each to manifest file
function prepareLayersForUpload() {
  info_file=$imageDir/info
  # lets calculate layers sha256 and use it as layers names further
  layersNames=($(find $imageDir -name "layer.tar" -exec shasum -a 256 {} ; | cut -d" " -f1))

  # rename layers according to shasums. !!!Set required amount of fields for cut command!!!
  # this part definitely can be done easier but i didn't found another way, sry
  find $imageDir -name "layer.tar" -exec bash -c 'mv {} "$(echo {} | cut -d"/" -f1,2)/$(shasum -a 256 {} | cut -d" " -f1)"' ;

  layersSizes=($(find $imageDir -name "*.tar" -exec ls -l {} ; | awk '{print $5}'))

  for i in "${!layersNames[@]}"; do
    echo "{
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": ${layersSizes[$i]},
         "digest": "sha256:${layersNames[$i]}"
      }," >> $manifestFile
  done
  # remove last ','
  truncate -s-2 $manifestFile
  # add closing brakets to keep json consistent
  printf "nt]n}" >> $manifestFile
}

# calc config sha 256 sum and add info about it to manifest
function setConfigProps() {
  configSize=$(ls -l $configFile | awk '{print $5}')
  configName=$(basename $configFile | cut -d"." -f1)

  sed -i "s/config_size/$configSize/g; s/config_hash/$configName/g" $manifestFile
}

#prepare manifest file
prepareLayersForUpload
setConfigProps
cat $manifestFile

# initiate upload and get uuid
uuid=$(curl -s -X POST -I "$url/v2/$repoName/blobs/uploads/" | grep -oP "(?<=Docker-Upload-Uuid: ).+")

# patch layers
# in data-binary we're getting absolute path to layer file
for l in "${!layersNames[@]}"; do
  pathToLayer=$(find $imageDir -name ${layersNames[$l]} -exec readlink -f {} ;)
    curl -v -X PATCH "$url/v2/$repoName/blobs/uploads/$uuid" 
  -H "Content-Length: ${layersSizes[$i]}" 
  -H "Content-Type: application/octet-stream" 
  --data-binary "@$pathToLayer"

# put layer
  curl -v -X PUT "$url/v2/$repoName/blobs/uploads/$uuid?digest=sha256:${layersNames[$i]}" 
  -H 'Content-Type: application/octet-stream' 
  -H "Content-Length: ${layersSizes[$i]}" 
  --data-binary "@$pathToLayer"
done

# patch and put config after all layers
curl -v -X PATCH "$url/v2/$repoName/blobs/uploads/$uuid" 
  -H "Content-Length: $configSize" 
  -H "Content-Type: application/octet-stream" 
  --data-binary "@$configFile"

  curl -v -X PUT "$url/v2/$repoName/blobs/uploads/$uuid?digest=sha256:$configName" 
  -H 'Content-Type: application/octet-stream' 
  -H "Content-Length: $configSize" 
  --data-binary "@$configFile"

# put manifest
curl -v -X PUT "$url/v2/$repoName/manifests/$tag" 
  -H 'Content-Type: application/vnd.docker.distribution.manifest.v2+json' 
  --data-binary "@$manifestFile"

exit 0

αž™αžΎαž„αž’αžΆαž…αž”αŸ’αžšαžΎαžŸαŸ’αž‚αŸ’αžšαžΈαž”αžŠαŸ‚αž›αžαŸ’αžšαŸ€αž˜αžšαž½αž…αž‡αžΆαžŸαŸ’αžšαŸαž…αŸ–

./uploadImage.sh "~/path/to/saved/image" "http://localhost:8081/link/to/docker/registry" myRepoName 1.0

UPSαŸ–
αžαžΎαž™αžΎαž„αž‘αž‘αž½αž›αž”αžΆαž“αž›αž‘αŸ’αž’αž•αž›αž’αŸ’αžœαžΈ?
αž‘αžΈαž˜αž½αž™ αž‘αž·αž“αŸ’αž“αž“αŸαž™αž–αž·αžαž”αŸ’αžšαžΆαž€αžŠαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαžœαž·αž—αžΆαž‚ αž…αžΆαž”αŸ‹αžαžΆαŸ†αž„αž–αžΈαž€αžΆαžšαž’αŸ’αžœαžΎαžαŸαžŸαŸ’αžαžαŸ’αžšαžΌαžœαž”αžΆαž“αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž“αŸ…αž€αŸ’αž“αž»αž„ blazemeter αž αžΎαž™αž‘αž·αž“αŸ’αž“αž“αŸαž™αž“αŸ…αž›αžΎαžŸαŸ†αžŽαžΎαžšαž”αžŸαŸ‹αž’αžαž·αžαž·αž‡αž“ docker αž‚αžΊαž˜αž·αž“αž˜αžΆαž“αž–αŸαžαŸŒαž˜αžΆαž“αž…αŸ’αžšαžΎαž“αž‘αŸ αž˜αž·αž“αžŠαžΌαž…αžŸαŸ†αžŽαžΎ HTTP αžŸαž»αž‘αŸ’αž’αž“αŸ„αŸ‡αž‘αŸαŸ”

αž‘αžΈαž–αžΈαžš αž€αžΆαžšαž•αŸ’αž›αžΆαžŸαŸ‹αž”αŸ’αžαžΌαžšαž”αžΆαž“αž’αž“αž»αž‰αŸ’αž‰αžΆαžαž±αŸ’αž™αž™αžΎαž„αž”αž„αŸ’αž€αžΎαž“αž…αŸ†αž“αž½αž“αž’αŸ’αž“αž€αž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αž“αž·αž˜αŸ’αž˜αž·αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž”αž„αŸ’αž αŸ„αŸ‡ docker αž”αŸ’αžšαž αŸ‚αž› 150% αž“αž·αž„αž‘αž‘αž½αž›αž”αžΆαž“αž–αŸαž›αžœαŸαž›αžΆαž†αŸ’αž›αžΎαž™αžαž”αž‡αžΆαž˜αž’αŸ’αž™αž˜ 20-25% αž›αžΏαž“αž‡αžΆαž„αž˜αž»αž“αŸ” αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž‘αžΆαž‰αž™αž€ docker αž™αžΎαž„αž”αžΆαž“αž‚αŸ’αžšαž”αŸ‹αž‚αŸ’αžšαž„αžŠαžΎαž˜αŸ’αž”αžΈαž”αž„αŸ’αž€αžΎαž“αž…αŸ†αž“αž½αž“αž’αŸ’αž“αž€αž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹ 500% αžαžŽαŸˆαžŠαŸ‚αž›αž–αŸαž›αžœαŸαž›αžΆαž†αŸ’αž›αžΎαž™αžαž”αž‡αžΆαž˜αž’αŸ’αž™αž˜αž”αžΆαž“αžαž™αž…αž»αŸ‡αž”αŸ’αžšαž αŸ‚αž› 60%αŸ”

αžŸαžΌαž˜αž’αžšαž‚αž»αžŽαž…αŸ†αž–αŸ„αŸ‡αž€αžΆαžšαž™αž€αž…αž·αžαŸ’αžαž‘αž»αž€αžŠαžΆαž€αŸ‹αžšαž”αžŸαŸ‹αž’αŸ’αž“αž€αŸ”

αž”αŸ’αžšαž—αž–: www.habr.com

αž”αž“αŸ’αžαŸ‚αž˜αž˜αžαž·αž™αŸ„αž”αž›αŸ‹