ہمارے پاس گھاس کے 2 تھیلے، 75 میسکلین گولیاں یونکس ماحول، ایک ڈوکر ریپوزٹری اور ڈوکر کلائنٹ کے بغیر ڈوکر پل اور ڈوکر پش کمانڈز کو نافذ کرنے کا کام تھا۔
یوپیڈی:
سوال: یہ سب کس لیے ہے؟
جواب: پروڈکٹ کی لوڈ ٹیسٹنگ (بش کا استعمال نہیں، اسکرپٹ تعلیمی مقاصد کے لیے فراہم کیے گئے ہیں)۔ یہ فیصلہ کیا گیا کہ ڈوکر کلائنٹ کو اضافی تہوں کو کم کرنے کے لیے استعمال نہ کیا جائے (مناسب حد کے اندر) اور اس کے مطابق، زیادہ بوجھ کی تقلید کریں۔ نتیجے کے طور پر، Docker کلائنٹ کی تمام نظام کی تاخیر کو ہٹا دیا گیا تھا. ہمیں براہ راست پروڈکٹ پر نسبتاً صاف بوجھ ملا۔
مضمون میں ٹولز کے GNU ورژن استعمال کیے گئے ہیں۔
پہلے، آئیے یہ معلوم کریں کہ یہ کمانڈز کیا کرتی ہیں۔
تو ڈوکر پل کس کے لیے استعمال ہوتا ہے؟ کے مطابق
"رجسٹری سے ایک تصویر یا ذخیرہ کھینچیں"۔
وہاں ہمیں ایک لنک بھی ملتا ہے۔
یہاں سے ہم سمجھ سکتے ہیں کہ ڈوکر امیج کچھ خاص تہوں کا ایک مجموعہ ہے جس میں تصویر میں تازہ ترین تبدیلیوں کے بارے میں معلومات ہوتی ہیں، جو ظاہر ہے کہ ہمیں ضرورت ہے۔ آگے ہم دیکھتے ہیں۔
یہ مندرجہ ذیل کہتا ہے:
"ایک "تصویر" 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}"
"ایک پرت تک رسائی کو ذخیرے کے نام سے گیٹ کیا جائے گا لیکن ڈائجسٹ کے ذریعہ رجسٹری میں منفرد طور پر شناخت کیا جاتا ہے۔"
اس معاملے میں ڈائجسٹ ہیش ہے جو ہمیں موصول ہوئی ہے۔
کوشش کرتے ہیں
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
وہ ریل ٹار آرکائیوز ہیں، ان کو مناسب ترتیب میں کھولنے سے ہمیں تصویر کا مواد مل جائے گا۔
چلو ایک چھوٹا سا باش اسکرپٹ لکھتے ہیں تاکہ یہ سب خودکار ہو سکے۔
#!/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}
مواد کی لمبائی: {ٹکڑے کا سائز}
مواد کی قسم: ایپلیکیشن/آکٹیٹ اسٹریم
{پرت چنک بائنری ڈیٹا}"۔
بصورت دیگر، آپ پہلے نقطہ سے آگے نہیں بڑھ پائیں گے، کیونکہ... متوقع جوابی کوڈ 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
یوپیڈی:
اس کے نتیجے میں ہمیں کیا ملا؟
سب سے پہلے، تجزیہ کے لیے حقیقی ڈیٹا، چونکہ ٹیسٹ بلیز میٹر میں چلائے جاتے ہیں اور ڈوکر کلائنٹ کی درخواستوں کا ڈیٹا خالص HTTP درخواستوں کے برعکس زیادہ معلوماتی نہیں ہوتا ہے۔
دوم، منتقلی نے ہمیں ڈاکر اپ لوڈ کے لیے ورچوئل صارفین کی تعداد میں تقریباً 150% اضافہ کرنے اور اوسط رسپانس ٹائم 20-25% تیزی سے حاصل کرنے کی اجازت دی۔ ڈاکر ڈاؤن لوڈ کے لیے، ہم صارفین کی تعداد میں 500% اضافہ کرنے میں کامیاب رہے، جبکہ اوسط جوابی وقت میں تقریباً 60% کی کمی واقع ہوئی۔
آپ کی توجہ کے لئے آپ کا شکریہ.
ماخذ: www.habr.com