हमारे पास घास के 2 बैग, 75 मेस्कलीन टैबलेट यूनिक्स पर्यावरण, एक डॉकर रिपोजिटरी और डॉकर क्लाइंट के बिना डॉकर पुल और डॉकर पुश कमांड को लागू करने का कार्य था।
युपीडी:
प्रश्न: यह सब किस लिए है?
उत्तर: उत्पाद का लोड परीक्षण (बैश का उपयोग नहीं, स्क्रिप्ट शैक्षिक उद्देश्यों के लिए प्रदान की जाती है)। अतिरिक्त परतों को कम करने (उचित सीमा के भीतर) और तदनुसार, उच्च भार का अनुकरण करने के लिए डॉकर क्लाइंट का उपयोग नहीं करने का निर्णय लिया गया। परिणामस्वरूप, डॉकर क्लाइंट के सभी सिस्टम विलंब हटा दिए गए। हमें सीधे उत्पाद पर अपेक्षाकृत साफ़ लोड प्राप्त हुआ।
आलेख में टूल के 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 अनुरोध करना होगा:
"पैच /v2/{repoName}/blobs/uploads/{uuid}
सामग्री-लंबाई: {खंड का आकार}
सामग्री-प्रकार: एप्लिकेशन/ऑक्टेट-स्ट्रीम
{लेयर चंक बाइनरी डेटा}"।
अन्यथा, आप पहले बिंदु से आगे नहीं बढ़ पाएंगे, क्योंकि... अपेक्षित प्रतिक्रिया कोड 202 के बजाय, आपको 4xx प्राप्त होगा।
अब एल्गोरिथ्म इस प्रकार दिखता है:
- प्रारंभ
- पैच रेल
- रेलिंग लोड हो रही है
- मेनिफेस्ट लोड हो रहा है
क्रमशः बिंदु 2 और 3 को उतनी बार दोहराया जाएगा जितनी लाइनों को लोड करने की आवश्यकता होगी।
सबसे पहले, हमें किसी छवि की आवश्यकता है। मैं आर्चलिनक्स:नवीनतम का उपयोग करूंगा
docker pull archlinux
आइए अब इसे आगे के विश्लेषण के लिए स्थानीय रूप से सहेजें
docker save c24fe13d37b9 -o savedArch
परिणामी संग्रह को वर्तमान निर्देशिका में अनपैक करें
tar xvf savedArch
जैसा कि आप देख सकते हैं, प्रत्येक जीवन रेखा एक अलग फ़ोल्डर में है। आइए अब हमें प्राप्त मेनिफेस्ट की संरचना पर नजर डालें
cat manifest.json | json_pp
ज्यादा नहीं। आइए देखें कि किस मेनिफेस्ट को लोड करने की आवश्यकता है
जाहिर है, मौजूदा घोषणापत्र हमारे अनुकूल नहीं है, इसलिए हम ब्लैकजैक और वेश्याओं, जीवनरेखाओं और कॉन्फ़िगरेशन के साथ अपना स्वयं का घोषणापत्र बनाएंगे।
हमारे पास हमेशा कम से कम एक कॉन्फ़िगरेशन फ़ाइल और जीवनरेखाओं की एक श्रृंखला होगी। योजना संस्करण 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
मूल मेनिफेस्ट बनाने के बाद, आपको इसे वैध डेटा से भरना होगा। ऐसा करने के लिए, हम रेल ऑब्जेक्ट के 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
अब आप डाउनलोड प्रक्रिया शुरू कर सकते हैं और अपने लिए एक यूयूआईडी सहेज सकते हैं, जो बाद के सभी अनुरोधों के साथ होनी चाहिए।
पूरी स्क्रिप्ट कुछ इस तरह दिखती है:
#!/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