เรามีหญ้า 2 ถุง สภาพแวดล้อมยูนิกซ์แท็บเล็ตมอมเมา 75 เม็ด พื้นที่เก็บข้อมูลนักเทียบท่า และงานในการใช้คำสั่งดึงนักเทียบท่าและคำสั่งกดนักเทียบท่าโดยไม่ต้องใช้ไคลเอ็นต์นักเทียบท่า
ยูพีเอส:
คำถาม: ทั้งหมดนี้เพื่ออะไร?
คำตอบ: การทดสอบโหลดของผลิตภัณฑ์ (ไม่ได้ใช้ bash สคริปต์มีไว้เพื่อการศึกษา) มีการตัดสินใจว่าจะไม่ใช้ไคลเอ็นต์นักเทียบท่าเพื่อลดเลเยอร์เพิ่มเติม (ภายในขอบเขตที่เหมาะสม) และด้วยเหตุนี้จึงจำลองโหลดที่สูงกว่า ด้วยเหตุนี้ ความล่าช้าของระบบทั้งหมดของไคลเอ็นต์ Docker จึงถูกลบออก เราได้รับปริมาณงานที่ค่อนข้างสะอาดบนผลิตภัณฑ์โดยตรง
บทความนี้ใช้เครื่องมือเวอร์ชัน GNU
ก่อนอื่น เรามาดูกันว่าคำสั่งเหล่านี้ทำอะไร
ดังนั้น docker pull ใช้ทำอะไร? ตาม
"ดึงรูปภาพหรือพื้นที่เก็บข้อมูลจากรีจิสตรี"
ที่นั่นเรายังพบลิงค์ไปยัง
จากจุดนี้ เราสามารถเข้าใจได้ว่า Docker Image คือชุดของเลเยอร์บางเลเยอร์ที่มีข้อมูลเกี่ยวกับการเปลี่ยนแปลงล่าสุดในรูปภาพ ซึ่งเห็นได้ชัดว่าเป็นสิ่งที่เราต้องการ ต่อไปเรามาดูกัน
มันบอกว่าต่อไปนี้:
""รูปภาพ" คือการรวมกันของไฟล์ Manifest 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
เหล่านั้น. rails เป็นไฟล์เก็บถาวร tar การแกะออกตามลำดับที่เหมาะสมเราจะได้รับเนื้อหาของรูปภาพ
มาเขียนสคริปต์ทุบตีเล็กๆ เพื่อให้ทั้งหมดนี้สามารถทำงานอัตโนมัติได้
#!/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/"
- การอัปโหลด lifeline (เราจะใช้การอัปโหลดแบบเสาหิน กล่าวคือ เราส่ง lifeline แต่ละอันอย่างครบถ้วน) - "PUT /v2/{repoName}/blobs/uploads/{uuid}?digest={digest}
ความยาวเนื้อหา: {ขนาดของเลเยอร์}
ประเภทเนื้อหา: application/octet-stream
ข้อมูลไบนารีชั้น" - กำลังโหลดรายการ - "PUT /v2/{repoName}/manifests/{reference}"
แต่เอกสารประกอบขาดขั้นตอนเดียวโดยที่ไม่มีอะไรทำงาน สำหรับการโหลดแบบเสาหิน เช่นเดียวกับบางส่วน (เป็นก้อน) ก่อนที่จะโหลดราง คุณต้องดำเนินการคำขอ PATCH:
"PATCH /v2/{repoName}/blobs/uploads/{uuid}
ความยาวเนื้อหา: {ขนาดของชิ้น}
ประเภทเนื้อหา: application/octet-stream
{ข้อมูลไบนารีของเลเยอร์ก้อน}"
ไม่เช่นนั้นจะไม่สามารถก้าวข้ามจุดแรกได้เพราะ... แทนที่จะเป็นรหัสตอบกลับที่คาดไว้ 202 คุณจะได้รับ 4xx
ตอนนี้อัลกอริทึมดูเหมือนว่า:
- การเริ่มต้น
- รางแพทช์
- กำลังโหลดราวจับ
- กำลังโหลดรายการ
จุดที่ 2 และ 3 ตามลำดับ จะถูกทำซ้ำหลาย ๆ ครั้งตามจำนวนบรรทัดที่ต้องโหลด
ก่อนอื่น เราต้องการรูปภาพใดๆ ฉันจะใช้archlinux:latest
docker pull archlinux
ตอนนี้เรามาบันทึกไว้ในเครื่องเพื่อการวิเคราะห์เพิ่มเติม
docker save c24fe13d37b9 -o savedArch
คลายไฟล์เก็บถาวรผลลัพธ์ลงในไดเร็กทอรีปัจจุบัน
tar xvf savedArch
อย่างที่คุณเห็น เส้นชีวิตแต่ละอันอยู่ในโฟลเดอร์แยกกัน ตอนนี้เรามาดูโครงสร้างของ manifest ที่เราได้รับกัน
cat manifest.json | json_pp
ไม่มาก. เรามาดูกันว่ารายการใดที่จำเป็นในการโหลดตาม
แน่นอนว่าแถลงการณ์ที่มีอยู่ไม่เหมาะกับเรา ดังนั้นเราจะสร้างแบล็คแจ็คและโสเภณี เส้นชีวิต และการกำหนดค่าของตัวเองขึ้นมาเอง
เราจะมีไฟล์กำหนดค่าอย่างน้อยหนึ่งไฟล์และอาร์เรย์ของเส้นชีวิตเสมอ Scheme เวอร์ชัน 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 ของอ็อบเจ็กต์ Rail:
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": ${layersSizes[$i]},
"digest": "sha256:${layersNames[$i]}"
},
เราจะเพิ่มลงในรายการสำหรับแต่ละราง
ต่อไป เราจำเป็นต้องค้นหาขนาดของไฟล์กำหนดค่าและแทนที่ stubs ในรายการด้วยข้อมูลจริง
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
ยูพีเอส:
เราได้รับผลอะไร?
ประการแรก ข้อมูลจริงสำหรับการวิเคราะห์ เนื่องจากการทดสอบดำเนินการใน blazemeter และข้อมูลในคำขอไคลเอ็นต์นักเทียบท่านั้นไม่ได้ให้ข้อมูลมากนัก ต่างจากคำขอ HTTP ล้วนๆ
ประการที่สอง การเปลี่ยนแปลงทำให้เราสามารถเพิ่มจำนวนผู้ใช้เสมือนสำหรับการอัปโหลดนักเทียบท่าได้ประมาณ 150% และรับเวลาตอบสนองโดยเฉลี่ยเร็วขึ้น 20-25% สำหรับการดาวน์โหลดนักเทียบท่า เราจัดการเพื่อเพิ่มจำนวนผู้ใช้ได้ 500% ในขณะที่เวลาตอบสนองโดยเฉลี่ยลดลงประมาณ 60%
ขอบคุณสำหรับความสนใจของคุณ
ที่มา: will.com