HTTP хүсэлтийг ашиглан докер клиентгүйгээр docker pull болон docker push командуудыг хэрэгжүүлж байна

Бидэнд 2 уут өвс, 75 ширхэг мескалин таблет Unix орчин, докерын хадгалах газар, докерын үйлчлүүлэгчгүйгээр docker pull болон docker push командуудыг хэрэгжүүлэх даалгавар байсан.

HTTP хүсэлтийг ашиглан докер клиентгүйгээр docker pull болон docker push командуудыг хэрэгжүүлж байна

UPD:
Асуулт: Энэ бүхэн юуны төлөө вэ?
Хариулт: Бүтээгдэхүүнийг ачаалах туршилт (bash ашиглахгүй, скриптийг боловсролын зорилгоор өгсөн болно). Нэмэлт давхаргыг (боломжийн хязгаарт багтаан) багасгахын тулд докер клиентийг ашиглахгүй байхаар шийдсэн бөгөөд үүний дагуу илүү их ачааллыг дуурайв. Үүний үр дүнд Docker үйлчлүүлэгчийн бүх системийн саатал арилсан. Бид бүтээгдэхүүн дээр шууд харьцангуй цэвэр ачааллыг хүлээн авсан.
Уг нийтлэлд хэрэгслүүдийн GNU хувилбаруудыг ашигласан.

Эхлээд эдгээр командууд юу болохыг олж мэдье.

Тэгэхээр docker pull-ийг юунд ашигладаг вэ? дагуу баримт бичиг:

"Бүртгэлээс зураг эсвэл хадгалах газрыг татах".

Тэнд бид бас холбоосыг олдог зураг, контейнер, хадгалах драйверуудыг ойлгох.

HTTP хүсэлтийг ашиглан докер клиентгүйгээр docker pull болон docker push командуудыг хэрэгжүүлж байна

Эндээс бид докерын дүрс гэдэг нь зургийн хамгийн сүүлийн үеийн өөрчлөлтүүдийн талаарх мэдээллийг агуулсан тодорхой давхаргын багц гэдгийг ойлгож болох бөгөөд энэ нь бидэнд хэрэгтэй байгаа нь ойлгомжтой. Дараа нь бид харна бүртгэлийн API.

Үүнд дараахь зүйлийг хэлж байна.

""Зураг" нь 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"

HTTP хүсэлтийг ашиглан докер клиентгүйгээр docker pull болон docker push командуудыг хэрэгжүүлж байна

Хариуд нь бид 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

HTTP хүсэлтийг ашиглан докер клиентгүйгээр docker pull болон docker push командуудыг хэрэгжүүлж байна

Эцэст нь бид ямар төрлийн файлыг анхны аврах шугам болгон хүлээн авсныг харцгаая.

file firstLayer

HTTP хүсэлтийг ашиглан докер клиентгүйгээр docker pull болон docker push командуудыг хэрэгжүүлж байна

тэдгээр. Амьдралын шугамууд нь давирхайн архив бөгөөд тэдгээрийг зохих дарааллаар задлах замаар бид зургийн агуулгыг авах болно.

Энэ бүгдийг автоматжуулж болохуйц жижиг 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}
    Агуулгын урт: {давхаргын хэмжээ}
    Content-Type: application/octet-stream
    Давхаргын хоёртын өгөгдөл".
  • Манифестыг ачаалж байна - "PUT /v2/{repoName}/manifests/{reference}".

Гэхдээ баримт бичиг нь нэг алхам алддаг бөгөөд үүнгүйгээр юу ч ажиллахгүй. Цул ачааны хувьд, түүнчлэн хэсэгчилсэн (хэсэгчилсэн) хувьд төмөр замыг ачаалахын өмнө та PATCH хүсэлтийг гүйцэтгэх ёстой.

"PATCH /v2/{repoName}/blobs/uploads/{uuid}
Агуулгын урт: {хэсэгний хэмжээ}
Content-Type: application/octet-stream
{Layer Chunk Binary Data}".

Тэгэхгүй бол та эхний цэгээс цааш явах боломжгүй, учир нь... Хүлээгдэж буй хариу код 202-ын оронд та 4xx хүлээн авах болно.

Одоо алгоритм дараах байдалтай байна.

  • Эхлүүлэх
  • Нүхэн төмөр зам
  • Бариулыг ачаалж байна
  • Манифестыг ачаалж байна
    2 ба 3-р цэгүүд нь мөрийн тоог ачаалах шаардлагатай олон удаа давтагдана.

Нэгдүгээрт, бидэнд ямар ч зураг хэрэгтэй. Би archlinux:latest ашиглах болно

docker pull archlinux

HTTP хүсэлтийг ашиглан докер клиентгүйгээр docker pull болон docker push командуудыг хэрэгжүүлж байна

Одоо цаашдын дүн шинжилгээ хийхийн тулд үүнийг дотооддоо хадгалъя

docker save c24fe13d37b9 -o savedArch

HTTP хүсэлтийг ашиглан докер клиентгүйгээр docker pull болон docker push командуудыг хэрэгжүүлж байна

Үүссэн архивыг одоогийн лавлах руу задлаарай

tar xvf savedArch

HTTP хүсэлтийг ашиглан докер клиентгүйгээр docker pull болон docker push командуудыг хэрэгжүүлж байна

Таны харж байгаагаар амьдралын шугам бүр тусдаа хавтсанд байна. Одоо хүлээн авсан манифестын бүтцийг харцгаая

cat manifest.json | json_pp

HTTP хүсэлтийг ашиглан докер клиентгүйгээр docker pull болон docker push командуудыг хэрэгжүүлж байна

Их биш. Үүний дагуу ямар манифест ачаалах шаардлагатайг харцгаая баримт бичиг.

HTTP хүсэлтийг ашиглан докер клиентгүйгээр docker pull болон docker push командуудыг хэрэгжүүлж байна

Мэдээжийн хэрэг, одоо байгаа тунхаг нь бидэнд тохирохгүй байгаа тул бид блэк, уяач, амьдралын шугам, тохиргоог ашиглан өөрсдөө хийх болно.

Бид үргэлж дор хаяж нэг тохиргооны файл, олон тооны амьдралын шугамтай байх болно. Схемийн хувилбар 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

UPD:
Үүний үр дүнд бид юу авсан бэ?
Нэгдүгээрт, туршилтыг blazemeter дээр явуулдаг тул докерын үйлчлүүлэгчийн хүсэлтийн өгөгдөл нь цэвэр HTTP хүсэлтээс ялгаатай нь тийм ч мэдээлэлгүй байдаг тул дүн шинжилгээ хийх бодит өгөгдөл юм.

Хоёрдугаарт, шилжилт нь бидэнд докероор байршуулах виртуал хэрэглэгчдийн тоог 150%-иар нэмэгдүүлж, хариу өгөх дундаж хугацааг 20-25%-иар хурдан авах боломжийг олгосон. Докер татан авалтын хувьд бид хэрэглэгчдийн тоог 500%-иар нэмэгдүүлж чадсан бол хариу өгөх дундаж хугацаа 60%-иар буурсан байна.

Анхаарал тавьсан та бүхэнд баярлалаа.

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх