Մենք ունեինք 2 պարկ խոտ, 75 մեսկալինային պլանշետ unix միջավայր, դոկերի պահեստ և առաջադրանք՝ իրականացնելու docker pull և docker push հրամանները առանց docker հաճախորդի:
UPS:
Հարց. Ինչի՞ համար է այս ամենը:
Պատասխան՝ արտադրանքի բեռնվածության փորձարկում (ՉԻ օգտագործելով bash, սկրիպտները տրամադրվում են կրթական նպատակներով): Որոշվեց չօգտագործել docker հաճախորդը լրացուցիչ շերտերը նվազեցնելու համար (ողջամիտ սահմաններում) և, համապատասխանաբար, ավելի բարձր բեռը ընդօրինակելու համար: Արդյունքում, Docker հաճախորդի համակարգի բոլոր ուշացումները հեռացվեցին: Մենք ստացանք համեմատաբար մաքուր բեռ անմիջապես արտադրանքի վրա:
Հոդվածում օգտագործվել են գործիքների GNU տարբերակները։
Նախ, եկեք պարզենք, թե ինչ են անում այս հրամանները:
Այսպիսով, ինչի՞ համար է օգտագործվում docker pull-ը: Համաձայն
«Հանեք պատկեր կամ պահեստ ռեեստրից»:
Այնտեղ մենք նաև հղում ենք գտնում
Այստեղից մենք կարող ենք հասկանալ, որ դոկերի պատկերը որոշակի շերտերի մի շարք է, որոնք պարունակում են տեղեկատվություն պատկերի վերջին փոփոխությունների մասին, ինչը ակնհայտորեն այն է, ինչ մեզ անհրաժեշտ է: Հաջորդը մենք նայում ենք
Այն ասում է հետևյալը.
«Պատկերը» JSON մանիֆեստի և առանձին շերտի ֆայլերի համակցություն է: Պատկերը քաշելու գործընթացը կենտրոնանում է այս երկու բաղադրիչների առբերման շուրջ:
Այսպիսով, առաջին քայլը, ըստ փաստաթղթերի, «Պատկերի մանիֆեստի քաշում".
Իհարկե, մենք չենք նկարահանի այն, բայց մեզ անհրաժեշտ են դրա տվյալները: Հետևյալը խնդրանքի օրինակ է. GET /v2/{name}/manifests/{reference}
«Անունը և հղման պարամետրը նույնականացնում են պատկերը և պարտադիր են: Հղումը կարող է ներառել պիտակ կամ ամփոփում»:
Մեր դոկերի պահեստը տեղակայված է տեղում, եկեք փորձենք կատարել հարցումը.
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}»:
«Շերտի մուտքը կփակվի պահեստի անունով, բայց գրանցամատյանում եզակիորեն ճանաչվում է ըստ ամփոփման»:
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
դրանք. ռելսերը խեժի արխիվներ են, դրանք բացելով համապատասխան հերթականությամբ՝ կստանանք պատկերի բովանդակությունը:
Եկեք մի փոքրիկ 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 հարցում.
«PATCH /v2/{repoName}/blobs/uploads/{uuid}
Բովանդակություն-երկարություն՝ {չափի կտոր}
Բովանդակություն-տեսակ՝ հավելված/օկտետ հոսք
{Layer Chunk Binary Data}»:
Հակառակ դեպքում առաջին կետից այն կողմ չեք կարողանա անցնել, քանի որ... Ակնկալվող պատասխանի 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
UPS:
Ի՞նչ ստացանք արդյունքում։
Նախ, իրական տվյալներ վերլուծության համար, քանի որ թեստերն իրականացվում են blazemeter-ով, և docker հաճախորդի հարցումների տվյալները այնքան էլ տեղեկատվական չեն, ի տարբերություն մաքուր HTTP հարցումների:
Երկրորդ, անցումը թույլ տվեց մեզ մոտ 150%-ով ավելացնել դոկերի վերբեռնման համար վիրտուալ օգտատերերի թիվը և 20-25%-ով ավելի արագ ստանալ արձագանքման միջին ժամանակը: Docker-ի ներբեռնման համար մեզ հաջողվեց ավելացնել օգտատերերի թիվը 500%-ով, մինչդեռ միջին արձագանքման ժամանակը նվազել է մոտ 60%-ով։
Շնորհակալություն ուշադրության համար:
Source: www.habr.com