Bizda 2 qop o't, 75 ta meskalin planshetlari unix muhiti, docker ombori va docker mijozisiz docker pull va docker push buyruqlarini amalga oshirish vazifasi bor edi.
UPS:
Savol: Bularning barchasi nima uchun?
Javob: Mahsulotni yuklash testi (bash-dan foydalanmang, skriptlar o'quv maqsadlarida taqdim etiladi). Qo'shimcha qatlamlarni (oqilona chegaralar ichida) kamaytirish va shunga mos ravishda yuqori yukni taqlid qilish uchun docker mijozidan foydalanmaslikka qaror qilindi. Natijada, Docker mijozining barcha tizim kechikishlari olib tashlandi. Biz to'g'ridan-to'g'ri mahsulotga nisbatan toza yuk oldik.
Maqolada vositalarning GNU versiyalari ishlatilgan.
Birinchidan, bu buyruqlar nima qilishini aniqlaymiz.
Xo'sh, docker pull nima uchun ishlatiladi? Ga binoan
"Ro'yxatga olish kitobidan rasm yoki omborni tortib oling".
U erda biz havolani ham topamiz
Bu erdan tushunishimiz mumkinki, docker tasviri - bu tasvirdagi so'nggi o'zgarishlar haqidagi ma'lumotlarni o'z ichiga olgan ma'lum qatlamlar to'plami, bu bizga kerak bo'lgan narsadir. Keyinchalik ko'rib chiqamiz
Unda quyidagilar aytiladi:
"Tasvir" JSON manifest va individual qatlam fayllari birikmasidir. > Rasmni tortib olish jarayoni ushbu ikki komponentni olish atrofida markazlashadi."
Shunday qilib, hujjatlarga muvofiq birinchi qadam "Tasvir manifestini tortib olish".
Albatta, biz uni o'qqa tutmaymiz, lekin bizga undan ma'lumotlar kerak. Quyida so'rov namunasi keltirilgan: GET /v2/{name}/manifests/{reference}
"Ism va mos yozuvlar parametri rasmni aniqlaydi va talab qilinadi. Ma'lumotnoma teg yoki dayjestni o'z ichiga olishi mumkin."
Bizning docker omborimiz mahalliy sifatida joylashtirilgan, keling, so'rovni bajarishga harakat qilaylik:
curl -s -X GET "http://localhost:8081/link/to/docker/registry/v2/centos-11-10/manifests/1.1.1" -H "header_if_needed"
Bunga javoban biz json-ni olamiz, undan biz hozirda faqat hayot chiziqlari, aniqrog'i ularning xeshlari bilan qiziqamiz. Ularni qabul qilib, biz har birini ko'rib chiqishimiz va quyidagi so'rovni bajarishimiz mumkin: "GET /v2/{name}/blobs/{digest}"
"Qatlamga kirish repozitariy nomi bilan ochiladi, ammo registrda dayjest orqali noyob tarzda aniqlanadi."
bu holda digest - biz olgan xesh.
Urinish
curl -s -X GET "http://localhost:8081/link/to/docker/registry/v2/centos-11-10/blobs/sha256:f972d139738dfcd1519fd2461815651336ee25a8b54c358834c50af094bb262f" -H "header_if_needed" --output firstLayer
Keling, birinchi hayot chizig'i sifatida nihoyat qanday faylni olganimizni ko'rib chiqaylik.
file firstLayer
bular. relslar tar arxivlari bo'lib, ularni tegishli tartibda ochib, biz rasmning mazmunini olamiz.
Keling, bularning barchasini avtomatlashtirish uchun kichik bash skriptini yozaylik
#!/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
Endi biz uni kerakli parametrlar bilan ishga tushirishimiz va kerakli tasvirning mazmunini olishimiz mumkin
./script.sh dirName βhttp://localhost:8081/link/to/docker/registryβ myAwesomeImage 1.0
2-qism - docker push
Bu biroz murakkabroq bo'ladi.
Keling, yana boshlaylik
Hujjatlarni o'rganib chiqqandan so'ng, yuklab olish jarayonini bir necha bosqichlarga bo'lishimiz mumkin:
- Jarayonni ishga tushirish - "POST /v2/{repoName}/blobs/uploads/"
- Hayot chizig'ini yuklash (biz monolit yuklashdan foydalanamiz, ya'ni har bir hayot chizig'ini to'liq yuboramiz) - "PUT /v2/{repoName}/blobs/uploads/{uuid}?digest={digest}
Kontent uzunligi: {qatlam hajmi}
Kontent turi: dastur/oktet-oqim
Ikkilik ma'lumotlar qatlami". - Manifest yuklanmoqda - "PUT /v2/{repoName}/manifests/{reference}".
Ammo hujjatlar bir qadamni o'tkazib yuboradi, ularsiz hech narsa ishlamaydi. Monolit yuklash uchun, shuningdek qisman (parchalangan) uchun relsni yuklashdan oldin siz PATCH so'rovini bajarishingiz kerak:
"PATCH /v2/{repoName}/blobs/uploads/{uuid}
Kontent uzunligi: {bo'lak hajmi}
Kontent turi: dastur/oktet-oqim
{Layer Chunk Binary Data}".
Aks holda, siz birinchi nuqtadan nariga o'ta olmaysiz, chunki... Kutilgan javob kodi 202 o'rniga siz 4xx olasiz.
Endi algoritm quyidagicha ko'rinadi:
- Boshlash
- Yamoqli temir yo'l
- Tutqich yuklanmoqda
- Manifest yuklanmoqda
2 va 3-bandlar, navbati bilan, qancha qatorlarni yuklash kerak bo'lsa, shuncha takrorlanadi.
Birinchidan, bizga har qanday rasm kerak. Men archlinuxdan foydalanaman: eng yangi
docker pull archlinux
Endi keyingi tahlil qilish uchun uni mahalliy sifatida saqlaymiz
docker save c24fe13d37b9 -o savedArch
Olingan arxivni joriy katalogga oching
tar xvf savedArch
Ko'rib turganingizdek, har bir hayot chizig'i alohida papkada. Endi biz olgan manifestning tuzilishini ko'rib chiqamiz
cat manifest.json | json_pp
Unchalik emas. Keling, ko'ra, qanday manifestni yuklash kerakligini ko'rib chiqaylik
Shubhasiz, mavjud manifest bizga mos kelmaydi, shuning uchun biz blackjack va courtesans, lifelines va configs yordamida o'zimizni yaratamiz.
Bizda har doim kamida bitta konfiguratsiya fayli va hayot liniyalari qatori bo'ladi. Sxemaning 2-versiyasi (yozilish vaqtidagi), mediaType o'zgarishsiz qoladi:
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
Asosiy manifestni yaratgandan so'ng, uni haqiqiy ma'lumotlar bilan to'ldirishingiz kerak. Buning uchun biz rail ob'ektining json shablonidan foydalanamiz:
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": ${layersSizes[$i]},
"digest": "sha256:${layersNames[$i]}"
},
Biz uni har bir rels uchun manifestga qo'shamiz.
Keyinchalik, konfiguratsiya faylining hajmini bilib olishimiz va manifestdagi stublarni haqiqiy ma'lumotlar bilan almashtirishimiz kerak.
sed -i "s/config_size/$configSize/g; s/config_hash/$configName/g" $manifestFile
Endi siz yuklab olish jarayonini boshlashingiz va o'zingizga uuid-ni saqlashingiz mumkin, bu keyingi barcha so'rovlarga hamroh bo'lishi kerak.
To'liq skript quyidagicha ko'rinadi:
#!/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
Biz tayyor skriptdan foydalanishimiz mumkin:
./uploadImage.sh "~/path/to/saved/image" "http://localhost:8081/link/to/docker/registry" myRepoName 1.0
UPS:
Natijada nimaga erishdik?
Birinchidan, tahlil uchun haqiqiy ma'lumotlar, chunki testlar blazemeterda o'tkaziladi va docker mijoz so'rovlari bo'yicha ma'lumotlar sof HTTP so'rovlaridan farqli o'laroq unchalik ma'lumotli emas.
Ikkinchidan, o'tish bizga docker yuklash uchun virtual foydalanuvchilar sonini taxminan 150% ga oshirish va o'rtacha javob vaqtini 20-25% tezroq olish imkonini berdi. Docker yuklab olish uchun biz foydalanuvchilar sonini 500% ga oshirishga muvaffaq bo'ldik, o'rtacha javob vaqti esa taxminan 60% ga kamaydi.
E'tiboringiz uchun rahmat.
Manba: www.habr.com