์ฐ๋ฆฌ๋ 2๊ฐ์ ํ ๋ด์ง, 75๊ฐ์ ๋ฉ์ค์นผ๋ฆฐ ํ๋ธ๋ฆฟ Unix ํ๊ฒฝ, ๋์ปค ์ ์ฅ์, ๊ทธ๋ฆฌ๊ณ ๋์ปค ํด๋ผ์ด์ธํธ ์์ด ๋์ปค ํ ๋ฐ ๋์ปค ํธ์ ๋ช ๋ น์ ๊ตฌํํ๋ ์์ ์ ์ํํ์ต๋๋ค.
UPD :
์ง๋ฌธ: ์ด ๋ชจ๋ ๊ฒ์ ๋ฌด์์ ์ํ ๊ฒ์
๋๊น?
๋ต๋ณ: ์ ํ์ ๋ถํ ํ
์คํธ(bash๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ์คํฌ๋ฆฝํธ๋ ๊ต์ก ๋ชฉ์ ์ผ๋ก ์ ๊ณต๋จ) ์ถ๊ฐ ๋ ์ด์ด๋ฅผ ์ค์ด๊ณ (ํฉ๋ฆฌ์ ์ธ ํ๋ ๋ด์์) ๊ทธ์ ๋ฐ๋ผ ๋ ๋์ ๋ก๋๋ฅผ ์๋ฎฌ๋ ์ดํธํ๊ธฐ ์ํด Docker ํด๋ผ์ด์ธํธ๋ฅผ ์ฌ์ฉํ์ง ์๊ธฐ๋ก ๊ฒฐ์ ํ์ต๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก Docker ํด๋ผ์ด์ธํธ์ ๋ชจ๋ ์์คํ
์ง์ฐ์ด ์ ๊ฑฐ๋์์ต๋๋ค. ์ฐ๋ฆฌ๋ ์ ํ์ ์ง์ ๋น๊ต์ ๊นจ๋ํ ํ์ค์ ๋ฐ์์ต๋๋ค.
์ด ๊ธฐ์ฌ์์๋ GNU ๋ฒ์ ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
๋จผ์ , ์ด ๋ช ๋ น๋ค์ด ๋ฌด์์ ํ๋์ง ์์๋ด ์๋ค.
๊ทธ๋ ๋ค๋ฉด docker pull์ ์ด๋์ ์ฌ์ฉ๋๋์? ์ ๋ฐ๋ฅด๋ฉด
"๋ ์ง์คํธ๋ฆฌ์์ ์ด๋ฏธ์ง ๋๋ ์ ์ฅ์ ๊ฐ์ ธ์ค๊ธฐ".
๊ฑฐ๊ธฐ์๋ ๋ค์ ๋งํฌ๋ ์์ต๋๋ค.
์ฌ๊ธฐ์์ ์ฐ๋ฆฌ๋ ๋์ปค ์ด๋ฏธ์ง๊ฐ ์ด๋ฏธ์ง์ ์ต์ ๋ณ๊ฒฝ ์ฌํญ์ ๋ํ ์ ๋ณด๋ฅผ ํฌํจํ๋ ํน์ ๋ ์ด์ด ์ธํธ๋ผ๋ ๊ฒ์ ์ดํดํ ์ ์์ต๋๋ค. ์ด๋ ๋ถ๋ช
ํ ์ฐ๋ฆฌ์๊ฒ ํ์ํ ๊ฒ์
๋๋ค. ๋ค์์ผ๋ก ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๊ทธ๊ฒ์ ๋ค์๊ณผ ๊ฐ์ด ๋งํฉ๋๋ค :
""์ด๋ฏธ์ง"๋ JSON ๋งค๋ํ์คํธ์ ๊ฐ๋ณ ๋ ์ด์ด ํ์ผ์ ์กฐํฉ์ ๋๋ค. ์ด๋ฏธ์ง๋ฅผ ๊ฐ์ ธ์ค๋ ํ๋ก์ธ์ค๋ ์ด ๋ ๊ตฌ์ฑ ์์๋ฅผ ๊ฒ์ํ๋ ๋ฐ ์ค์ ์ ๋ก๋๋ค."
๋ฐ๋ผ์ ๋ฌธ์์ ๋ฐ๋ฅด๋ฉด ์ฒซ ๋ฒ์งธ ๋จ๊ณ๋ โ์ด๋ฏธ์ง ๋งค๋ํ์คํธ ๊ฐ์ ธ์ค๊ธฐ".
๋ฌผ๋ก ์ฐ๋ฆฌ๋ ๊ทธ๊ฒ์ ์์ง๋ ์์ ๊ฒ์ด์ง๋ง ๊ทธ๊ฒ์ผ๋ก๋ถํฐ ๋ฐ์ดํฐ๊ฐ ํ์ํฉ๋๋ค. ๋ค์์ ์์ฒญ ์์์
๋๋ค. 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"
์ด์ ๋ํ ์๋ต์ผ๋ก ์ฐ๋ฆฌ๋ ํ์ฌ ์๋ช ์ ์ด๋ ํด์์๋ง ๊ด์ฌ์ด ์๋ json์ ๋ฐ์ต๋๋ค. ์ด๋ฅผ ์์ ํ ํ ๊ฐ ํญ๋ชฉ์ ๊ฒํ ํ๊ณ ๋ค์ ์์ฒญ์ ์คํํ ์ ์์ต๋๋ค. "GET /v2/{name}/blobs/{digest}"
"๋ ์ด์ด์ ๋ํ ์ก์ธ์ค๋ ์ ์ฅ์ ์ด๋ฆ์ผ๋ก ์ ํ๋์ง๋ง ๋ ์ง์คํธ๋ฆฌ์์๋ ๋ค์ด์ ์คํธ๋ฅผ ํตํด ๊ณ ์ ํ๊ฒ ์๋ณ๋ฉ๋๋ค."
์ด ๊ฒฝ์ฐ ๋ค์ด์ ์คํธ๋ ์ฐ๋ฆฌ๊ฐ ๋ฐ์ ํด์์ ๋๋ค.
ํด๋ณด์
curl -s -X GET "http://localhost:8081/link/to/docker/registry/v2/centos-11-10/blobs/sha256:f972d139738dfcd1519fd2461815651336ee25a8b54c358834c50af094bb262f" -H "header_if_needed" --output firstLayer
์ฒซ ๋ฒ์งธ ์๋ช ์ ์ผ๋ก ์ต์ข ์ ์ผ๋ก ์ด๋ค ํ์ผ์ ๋ฐ์๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
file firstLayer
์ ๊ฒ๋ค. ๋ ์ผ์ 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๋ถ - ๋์ปค ํธ์
์ด๊ฒ์ ์กฐ๊ธ ๋ ๋ณต์กํ ๊ฒ์ ๋๋ค.
๋ค์ ์์ํ์
๋ฌธ์๋ฅผ ์ฐ๊ตฌํ ํ ๋ค์ด๋ก๋ ํ๋ก์ธ์ค๋ฅผ ์ฌ๋ฌ ๋จ๊ณ๋ก ๋๋ ์ ์์ต๋๋ค.
- ํ๋ก์ธ์ค ์ด๊ธฐํ - "POST /v2/{repoName}/blobs/uploads/"
- ๋ผ์ดํ๋ผ์ธ ์
๋ก๋(๋ชจ๋๋ฆฌ์ ์
๋ก๋๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ฆ, ๊ฐ ๋ผ์ดํ๋ผ์ธ์ ์ ์ฒด์ ์ผ๋ก ๋ณด๋
๋๋ค.) - "PUT /v2/{repoName}/blobs/uploads/{uuid}?digest={digest}
์ฝํ ์ธ ๊ธธ์ด: {๋ ์ด์ด ํฌ๊ธฐ}
์ฝํ ์ธ ์ ํ: ์ ํ๋ฆฌ์ผ์ด์ /์ฅํ ์คํธ๋ฆผ
๋ ์ด์ด ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ'๋ฅผ ์ฐธ์กฐํ์ธ์. - ๋งค๋ํ์คํธ ๋ก๋ ์ค - "PUT /v2/{repoName}/manifests/{reference}".
๊ทธ๋ฌ๋ ๋ฌธ์์๋ ํ ๋จ๊ณ๊ฐ ๋น ์ ธ ์์ผ๋ฉฐ, ์ด ๋จ๊ณ๊ฐ ์์ผ๋ฉด ์๋ฌด ๊ฒ๋ ์๋ํ์ง ์์ต๋๋ค. ๋ชจ๋๋ฆฌ์ ๋ก๋ฉ๊ณผ ๋ถ๋ถ(์ฒญํฌ) ๋ก๋ฉ์ ๊ฒฝ์ฐ ๋ ์ผ์ ๋ก๋ฉํ๊ธฐ ์ ์ PATCH ์์ฒญ์ ์ํํด์ผ ํฉ๋๋ค.
"ํจ์น /v2/{repoName}/blobs/uploads/{uuid}
์ฝํ
์ธ ๊ธธ์ด: {์ฒญํฌ ํฌ๊ธฐ}
์ฝํ
์ธ ์ ํ: ์ ํ๋ฆฌ์ผ์ด์
/์ฅํ
์คํธ๋ฆผ
{๋ ์ด์ด ์ฒญํฌ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ}".
๊ทธ๋ ์ง ์์ผ๋ฉด ์ฒซ ๋ฒ์งธ ์ง์ ์ ๋์ด ์ด๋ํ ์ ์์ต๋๋ค. ์๋ํ๋ฉด... ์์๋๋ ์๋ต ์ฝ๋ 202 ๋์ 4xx๋ฅผ ๋ฐ๊ฒ ๋ฉ๋๋ค.
์ด์ ์๊ณ ๋ฆฌ์ฆ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ์ด๊ธฐํ
- ํจ์น ๋ ์ผ
- ๋๊ฐ ๋ก๋
- ๋งค๋ํ์คํธ ๋ก๋ ์ค
ํฌ์ธํธ 2์ 3์ ๊ฐ๊ฐ ๋ก๋ํด์ผ ํ๋ ๋ผ์ธ ์๋งํผ ๋ฐ๋ณต๋ฉ๋๋ค.
๋จผ์ ์ด๋ฏธ์ง๊ฐ ํ์ํฉ๋๋ค. ๋๋ Archlinux:latest๋ฅผ ์ฌ์ฉํ ๊ฒ์ด๋ค.
docker pull archlinux
์ด์ ์ถ๊ฐ ๋ถ์์ ์ํด ๋ก์ปฌ์ ์ ์ฅํด ๋ณด๊ฒ ์ต๋๋ค.
docker save c24fe13d37b9 -o savedArch
๊ฒฐ๊ณผ ์์นด์ด๋ธ๋ฅผ ํ์ฌ ๋๋ ํ ๋ฆฌ์ ์์ถ ํด์
tar xvf savedArch
๋ณด์๋ค์ํผ, ๊ฐ ์๋ช ์ ์ ๋ณ๋์ ํด๋์ ์์ต๋๋ค. ์ด์ ์ฐ๋ฆฌ๊ฐ ๋ฐ์ ๋งค๋ํ์คํธ์ ๊ตฌ์กฐ๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
cat manifest.json | json_pp
๋ณ๋ก. ๋ก๋ํ๋ ๋ฐ ํ์ํ ๋งค๋ํ์คํธ๊ฐ ๋ฌด์์ธ์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๋ถ๋ช ํ ๊ธฐ์กด ์ ์ธ๋ฌธ์ ์ฐ๋ฆฌ์๊ฒ ์ ํฉํ์ง ์์ผ๋ฏ๋ก ๋ธ๋์ญ๊ณผ ์ฐฝ๋ , ์๋ช ์ ๋ฐ ๊ตฌ์ฑ์ ์ฌ์ฉํ์ฌ ์ฐ๋ฆฌ๋ง์ ์ ์ธ๋ฌธ์ ๋ง๋ค ๊ฒ์ ๋๋ค.
์ฐ๋ฆฌ๋ ํญ์ ์ต์ํ ํ๋์ ๊ตฌ์ฑ ํ์ผ๊ณผ ์ผ๋ จ์ ์๋ช ์ ์ ๊ฐ๊ฒ ๋ฉ๋๋ค. ๊ตฌ์ฑํ ๋ฒ์ 2(์์ฑ ๋น์ ํ์ฌ), mediaType์ ๋ณ๊ฒฝ๋์ง ์์ ์ํ๋ก ์ ์ง๋ฉ๋๋ค.
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
๊ธฐ๋ณธ ๋งค๋ํ์คํธ๋ฅผ ์์ฑํ ํ์๋ ์ ํจํ ๋ฐ์ดํฐ๋ก ์ฑ์์ผ ํฉ๋๋ค. ์ด๋ฅผ ์ํด ๋ ์ผ ๊ฐ์ฒด์ json ํ ํ๋ฆฟ์ ์ฌ์ฉํฉ๋๋ค.
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": ${layersSizes[$i]},
"digest": "sha256:${layersNames[$i]}"
},
๊ฐ ๋ ์ผ์ ๋งค๋ํ์คํธ์ ์ด๋ฅผ ์ถ๊ฐํ๊ฒ ์ต๋๋ค.
๋ค์์ผ๋ก ๊ตฌ์ฑ ํ์ผ์ ํฌ๊ธฐ๋ฅผ ํ์ธํ๊ณ ๋งค๋ํ์คํธ์ ์คํ ์ ์ค์ ๋ฐ์ดํฐ๋ก ๋ฐ๊ฟ์ผ ํฉ๋๋ค.
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
UPD :
๊ทธ ๊ฒฐ๊ณผ ์ฐ๋ฆฌ๋ ๋ฌด์์ ์ป์์ต๋๊น?
์ฒซ์งธ, ๋ถ์์ ์ํ ์ค์ ๋ฐ์ดํฐ์
๋๋ค. ํ
์คํธ๋ blazemeter์์ ์คํ๋๊ณ docker ํด๋ผ์ด์ธํธ ์์ฒญ์ ๋ํ ๋ฐ์ดํฐ๋ ์์ํ HTTP ์์ฒญ๊ณผ ๋ฌ๋ฆฌ ๊ทธ๋ค์ง ์ ์ตํ์ง ์์ต๋๋ค.
๋์งธ, ์ ํ์ ํตํด Docker ์ ๋ก๋๋ฅผ ์ํ ๊ฐ์ ์ฌ์ฉ์ ์๊ฐ ์ฝ 150% ์ฆ๊ฐํ๊ณ ํ๊ท ์๋ต ์๊ฐ์ด 20-25% ๋ ๋นจ๋ผ์ก์ต๋๋ค. Docker ๋ค์ด๋ก๋์ ๊ฒฝ์ฐ ์ฌ์ฉ์ ์๋ 500% ์ฆ๊ฐํ ๋ฐ๋ฉด ํ๊ท ์๋ต ์๊ฐ์ ์ฝ 60% ๊ฐ์ํ์ต๋๋ค.
๊ด์ฌ์ ๊ฐ์ ธ ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.
์ถ์ฒ : habr.com