Docker pull un docker push komandu ieviešana bez docker klienta, izmantojot HTTP pieprasījumus

Mums bija 2 maisi ar zāli, 75 mescaline tablešu unix vide, docker repozitorijs un uzdevums ieviest docker pull un docker push komandas bez docker klienta.

Docker pull un docker push komandu ieviešana bez docker klienta, izmantojot HTTP pieprasījumus

UPD:
Jautājums: priekš kam tas viss?
Atbilde: Produkta slodzes pārbaude (NEizmantojot bash, skripti ir paredzēti izglītojošiem nolūkiem). Tika nolemts neizmantot docker klientu, lai samazinātu papildu slāņus (saprātīgās robežās) un attiecīgi emulētu lielāku slodzi. Tā rezultātā tika noņemtas visas Docker klienta sistēmas aizkaves. Mēs saņēmām salīdzinoši tīru slodzi tieši uz produktu.
Rakstā tika izmantotas rīku GNU versijas.

Vispirms izdomāsim, ko dara šīs komandas.

Tātad, kam izmanto docker pull? Saskaņā ar dokumentācija:

"Izvelciet attēlu vai repozitoriju no reģistra".

Tur atrodam arī saiti uz izprast attēlus, konteinerus un krātuves draiverus.

Docker pull un docker push komandu ieviešana bez docker klienta, izmantojot HTTP pieprasījumus

No šejienes mēs varam saprast, ka docker attēls ir noteiktu slāņu kopums, kas satur informāciju par jaunākajām attēla izmaiņām, kas, protams, ir tas, kas mums ir nepieciešams. Tālāk mēs skatāmies reģistra API.

Tajā teikts sekojošais:

""Attēls" ir JSON manifesta un atsevišķu slāņa failu kombinācija. Attēla izvilkšanas process ir vērsts uz šo divu komponentu izgūšanu."

Tātad pirmais solis saskaņā ar dokumentāciju ir "Attēla manifesta vilkšana".

Protams, mēs to neuzņemsim, bet mums ir nepieciešami dati no tā. Šis ir pieprasījuma piemērs: GET /v2/{name}/manifests/{reference}

"Nosaukums un atsauces parametrs identificē attēlu un ir obligāti. Atsauce var ietvert atzīmi vai īssavilkumu."

Mūsu docker repozitorijs ir izvietots lokāli, mēģināsim izpildīt pieprasījumu:

curl -s -X GET "http://localhost:8081/link/to/docker/registry/v2/centos-11-10/manifests/1.1.1" -H "header_if_needed"

Docker pull un docker push komandu ieviešana bez docker klienta, izmantojot HTTP pieprasījumus

Atbildot uz to, mēs saņemam json, no kura mūs pašlaik interesē tikai dzīvības līnijas vai drīzāk to hash. Pēc to saņemšanas mēs varam izskatīt katru no tiem un izpildīt šādu pieprasījumu: "GET /v2/{name}/blobs/{digest}"

“Piekļuve slānim tiks nodrošināta ar repozitorija nosaukumu, taču tā tiek unikāli identificēta reģistrā pēc īssavilkuma.”

sagremot šajā gadījumā ir hash, ko mēs saņēmām.

Mēģina

curl -s -X GET "http://localhost:8081/link/to/docker/registry/v2/centos-11-10/blobs/sha256:f972d139738dfcd1519fd2461815651336ee25a8b54c358834c50af094bb262f" -H "header_if_needed" --output firstLayer

Docker pull un docker push komandu ieviešana bez docker klienta, izmantojot HTTP pieprasījumus

Paskatīsimies, kādu failu beidzot saņēmām kā pirmo glābšanas riņķi.

file firstLayer

Docker pull un docker push komandu ieviešana bez docker klienta, izmantojot HTTP pieprasījumus

tie. sliedes ir darvas arhīvi, tos izsaiņojot atbilstošā secībā saņemsim attēla saturu.

Uzrakstīsim nelielu bash skriptu, lai to visu varētu automatizēt

#!/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

Tagad varam to palaist ar vēlamajiem parametriem un iegūt vajadzīgā attēla saturu

./script.sh dirName “http://localhost:8081/link/to/docker/registry” myAwesomeImage 1.0

2. daļa - dokera stumšana

Tas būs nedaudz sarežģītāk.

Sāksim vēlreiz ar dokumentācija. Tāpēc mums ir jālejupielādē katrs vadītājs, jāsavāc atbilstošais manifests un arī tas jālejupielādē. Šķiet vienkārši.

Pēc dokumentācijas izpētes lejupielādes procesu varam sadalīt vairākos posmos:

  • Procesa inicializācija — "POST /v2/{repoName}/blobs/uploads/"
  • Glābšanas līnijas augšupielāde (mēs izmantosim monolītu augšupielādi, t.i., mēs nosūtīsim katru glābšanas līniju pilnībā) - "PUT /v2/{repoName}/blobs/uploads/{uuid}?digest={digest}
    Satura garums: {slāņa izmērs}
    Satura veids: lietojumprogramma/okteta straume
    Slāņa binārie dati".
  • Notiek manifesta ielāde — "PUT /v2/{repoName}/manifests/{reference}".

Bet dokumentācija izlaiž vienu soli, bez kura nekas nedarbosies. Monolītai iekraušanai, kā arī daļējai (gabalos) pirms sliedes iekraušanas ir jāveic PATCH pieprasījums:

PATCH /v2/{repoName}/blobs/uploads/{uuid}
Satura garums: {size of chunk}
Satura veids: lietojumprogramma/okteta straume
{Layer Chunk Binary Data}".

Citādi tālāk par pirmo punktu nevarēsi tikt, jo... Paredzētā atbildes koda 202 vietā jūs saņemsiet 4xx.

Tagad algoritms izskatās šādi:

  • Inicializācija
  • Patch sliede
  • Margas iekraušana
  • Notiek manifesta ielāde
    Attiecīgi 2. un 3. punkts tiks atkārtots tik reižu, cik rindu nepieciešams ielādēt.

Pirmkārt, mums ir nepieciešams jebkurš attēls. Es izmantošu archlinux:latest

docker pull archlinux

Docker pull un docker push komandu ieviešana bez docker klienta, izmantojot HTTP pieprasījumus

Tagad saglabāsim to lokāli turpmākai analīzei

docker save c24fe13d37b9 -o savedArch

Docker pull un docker push komandu ieviešana bez docker klienta, izmantojot HTTP pieprasījumus

Izsaiņojiet iegūto arhīvu pašreizējā direktorijā

tar xvf savedArch

Docker pull un docker push komandu ieviešana bez docker klienta, izmantojot HTTP pieprasījumus

Kā redzat, katrs glābšanas riņķis atrodas atsevišķā mapē. Tagad apskatīsim saņemtā manifesta struktūru

cat manifest.json | json_pp

Docker pull un docker push komandu ieviešana bez docker klienta, izmantojot HTTP pieprasījumus

Nedaudz. Apskatīsim, kāds manifests ir nepieciešams, lai ielādētu, saskaņā ar dokumentācija.

Docker pull un docker push komandu ieviešana bez docker klienta, izmantojot HTTP pieprasījumus

Acīmredzot esošais manifests mums nav piemērots, tāpēc mēs izveidosim savu, izmantojot blekdžeku un kurtizānes, glābšanas līnijas un konfigurācijas.

Mums vienmēr būs vismaz viens konfigurācijas fails un dzīvības līniju masīvs. Shēmas versija 2 (pašreizējā rakstīšanas laikā), mediaType tiks atstāta nemainīga:

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

Pēc pamata manifesta izveides tas jāaizpilda ar derīgiem datiem. Lai to izdarītu, mēs izmantojam dzelzceļa objekta json veidni:

{
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": ${layersSizes[$i]},
         "digest": "sha256:${layersNames[$i]}"
      },

Mēs to pievienosim katras sliedes manifestam.

Tālāk mums ir jānoskaidro konfigurācijas faila lielums un jāaizstāj manifestā esošie elementi ar reāliem datiem

sed -i "s/config_size/$configSize/g; s/config_hash/$configName/g" $manifestFile

Tagad varat sākt lejupielādes procesu un saglabāt sev uuid, kas jāpievieno visiem turpmākajiem pieprasījumiem.

Pilns skripts izskatās apmēram šādi:

#!/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

mēs varam izmantot gatavu skriptu:

./uploadImage.sh "~/path/to/saved/image" "http://localhost:8081/link/to/docker/registry" myRepoName 1.0

UPD:
Ko mēs rezultātā ieguvām?
Pirmkārt, reāli dati analīzei, jo testi tiek palaisti blazemeter un dati par docker klientu pieprasījumiem nav īpaši informatīvi, atšķirībā no tīrajiem HTTP pieprasījumiem.

Otrkārt, pāreja ļāva mums palielināt virtuālo lietotāju skaitu docker augšupielādei par aptuveni 150% un iegūt vidējo reakcijas laiku par 20–25% ātrāk. Docker lejupielādei mums izdevās palielināt lietotāju skaitu par 500%, savukārt vidējais reakcijas laiks samazinājās par aptuveni 60%.

Paldies par uzmanību.

Avots: www.habr.com

Pievieno komentāru