HTTP сурамдарын колдонуу менен докер кардары жок докер тартуу жана докер түртүү буйруктарын ишке ашыруу

Бизде 2 баштык чөп, 75 мескалиндик планшеттер unix чөйрөсү, докер репозиторийлери жана докердин кардарысыз докер тартуу жана докер түртүү буйруктарын ишке ашыруу милдети бар болчу.

HTTP сурамдарын колдонуу менен докер кардары жок докер тартуу жана докер түртүү буйруктарын ишке ашыруу

UPS:
Суроо: Мунун баары эмне үчүн?
Жооп: Продукцияны жүктөө тестирлөө (bash КОЛДОНБОЙТ, скрипттер билим берүү максатында берилген). Кошумча катмарларды кыскартуу (акылга сыярлык чектерде) жана ошого жараша жогорураак жүктү эмуляциялоо үчүн докер кардарын колдонбоо чечими кабыл алынды. Натыйжада, Docker кардарынын бардык тутумдук кечигүүлөрү алынып салынды. Биз продукт боюнча түздөн-түз салыштырмалуу таза жүгүн алган.
Макалада куралдардын GNU версиялары колдонулган.

Биринчиден, келгиле, бул буйруктар эмне экенин аныктап көрөлү.

Ошентип, docker pull эмне үчүн колдонулат? Ылайык документтер:

"Регистрден сүрөттү же репозиторийди тартыңыз".

Ал жерден биз да шилтеме табабыз сүрөттөрдү, контейнерлерди жана сактоо драйверлерин түшүнүү.

HTTP сурамдарын колдонуу менен докер кардары жок докер тартуу жана докер түртүү буйруктарын ишке ашыруу

Бул жерден биз докер сүрөтү бул сүрөттөгү акыркы өзгөрүүлөр жөнүндө маалыматты камтыган белгилүү катмарлардын жыйындысы экенин түшүнсөк болот, бул бизге керек экени анык. Кийинки биз карайбыз реестр 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 сурамдарын колдонуу менен докер кардары жок докер тартуу жана докер түртүү буйруктарын ишке ашыруу

Жооп катары биз 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

HTTP сурамдарын колдонуу менен докер кардары жок докер тартуу жана докер түртүү буйруктарын ишке ашыруу

Келгиле, биз биринчи өмүр линиясы катары кандай файлды алдык.

file firstLayer

HTTP сурамдарын колдонуу менен докер кардары жок докер тартуу жана докер түртүү буйруктарын ишке ашыруу

ошол. рельс - бул чайыр архив, аларды тиешелүү тартипте ачып, биз сүрөттүн мазмунун алабыз.

Мунун баарын автоматташтыруу үчүн кичинекей баш сценарийин жазалы

#!/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: колдонмо/октет-агым
    Кабат бинардык маалыматтар".
  • Манифест жүктөлүүдө - "PUT /v2/{repoName}/manifests/{reference}".

Бирок документация бир кадамды өткөрүп жиберет, ансыз эч нерсе иштебейт. Монолиттик жүктөө үчүн, ошондой эле жарым-жартылай (бөлүкчөлөр) үчүн рельсти жүктөөдөн мурун, сиз PATCH өтүнүчүн аткарышыңыз керек:

"PATCH /v2/{repoName}/blobs/uploads/{uuid}
Мазмун-узундугу: {бөлүгүнүн өлчөмү}
Content-Type: колдонмо/октет-агым
{Layer Chunk Binary Data}".

Болбосо, биринчи чекиттен ары кете албайсыз, анткени... Күтүлгөн жооп кодунун ордуна 202, сиз 4xx аласыз.

Эми алгоритм төмөнкүдөй көрүнөт:

  • Баштоо
  • Патч темир жол
  • Кол кармагыч жүктөлүүдө
  • Манифест жүктөлүүдө
    2 жана 3-пункттар, саптардын саны канчалык жүктөлүшү керек болсо, ошончо жолу кайталанат.

Биринчиден, бизге кандайдыр бир сүрөт керек. Мен archlinux: акыркы колдоном

docker pull archlinux

HTTP сурамдарын колдонуу менен докер кардары жок докер тартуу жана докер түртүү буйруктарын ишке ашыруу

Эми андан ары талдоо үчүн аны жергиликтүү сактайлы

docker save c24fe13d37b9 -o savedArch

HTTP сурамдарын колдонуу менен докер кардары жок докер тартуу жана докер түртүү буйруктарын ишке ашыруу

Алынган архивди учурдагы каталогго ачыңыз

tar xvf savedArch

HTTP сурамдарын колдонуу менен докер кардары жок докер тартуу жана докер түртүү буйруктарын ишке ашыруу

Көрүнүп тургандай, ар бир жашоо сызыгы өзүнчө папкада. Эми биз алган манифесттин структурасын карап көрөлү

cat manifest.json | json_pp

HTTP сурамдарын колдонуу менен докер кардары жок докер тартуу жана докер түртүү буйруктарын ишке ашыруу

көп эмес. Келгиле, жүктөө үчүн кандай манифест керек экенин карап көрөлү документтер.

HTTP сурамдарын колдонуу менен докер кардары жок докер тартуу жана докер түртүү буйруктарын ишке ашыруу

Албетте, учурдагы манифест бизге туура келбейт, ошондуктан биз блэкджек жана куртизандар, жашоо линиялары жана конфигурациялар менен өзүбүздүн нерселерди жасайбыз.

Бизде ар дайым жок дегенде бир конфигурация файлы жана көптөгөн жашоо линиялары болот. Схема 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

UPS:
Натыйжада биз эмне алдык?
Биринчиден, талдоо үчүн реалдуу маалыматтар, анткени тесттер blazemeterде иштетилет жана докер кардарларынын суроо-талаптары боюнча маалыматтар таза HTTP сурамдарынан айырмаланып, анчалык маалыматтуу эмес.

Экинчиден, өтүү бизге докер жүктөө үчүн виртуалдык колдонуучулардын санын болжол менен 150% га көбөйтүүгө жана орточо жооп берүү убактысын 20-25% тезирээк алууга мүмкүндүк берди. Докер жүктөө үчүн биз колдонуучулардын санын 500% га көбөйтө алдык, ал эми орточо жооп берүү убактысы болжол менен 60% га кыскарды.

Конул бурганын учун рахмат.

Source: www.habr.com

Комментарий кошуу