Implementeer docker pull en docker push-opdragte sonder 'n docker-kliënt wat HTTP-versoeke gebruik

Ons het 2 sakke gras, 75 meskaline tablette Unix-omgewing, 'n docker-bewaarplek en die taak gehad om die docker pull en docker push-opdragte sonder 'n docker-kliënt te implementeer.

Implementeer docker pull en docker push-opdragte sonder 'n docker-kliënt wat HTTP-versoeke gebruik

UPS:
Vraag: Waarvoor is dit alles?
Antwoord: Ladingstoetsing van die produk (NIE bash gebruik nie, die skrifte word vir opvoedkundige doeleindes verskaf). Daar is besluit om nie die docker-kliënt te gebruik om bykomende lae (binne redelike perke) te verminder nie en gevolglik 'n hoër las na te boots. As gevolg hiervan is alle stelselvertragings van die Docker-kliënt verwyder. Ons het 'n relatief skoon vrag direk op die produk ontvang.
Die artikel het GNU-weergawes van gereedskap gebruik.

Laat ons eers uitvind wat hierdie opdragte doen.

So waarvoor word docker pull gebruik? Volgens dokumentasie:

"Trek 'n prent of 'n bewaarplek uit 'n register".

Daar vind ons ook 'n skakel na beelde, houers en stoorbestuurders verstaan.

Implementeer docker pull en docker push-opdragte sonder 'n docker-kliënt wat HTTP-versoeke gebruik

Van hier af kan ons verstaan ​​dat 'n docker-beeld 'n stel sekere lae is wat inligting bevat oor die jongste veranderinge in die beeld, wat natuurlik is wat ons nodig het. Volgende kyk ons ​​na register API.

Dit sê die volgende:

"'n "Beeld" is 'n kombinasie van 'n JSON-manifes en individuele laaglêers. Die proses om 'n > prent te trek, sentreer rondom die herwinning van hierdie twee komponente."

So die eerste stap volgens die dokumentasie is "Trek 'n beeldmanifes".

Natuurlik sal ons dit nie skiet nie, maar ons het die data daaruit nodig. Die volgende is 'n voorbeeldversoek: GET /v2/{name}/manifests/{reference}

"Die naam en verwysingsparameter identifiseer die prent en word vereis. Die verwysing kan 'n merker of samevatting insluit."

Ons docker-bewaarplek is plaaslik ontplooi, kom ons probeer om die versoek uit te voer:

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

Implementeer docker pull en docker push-opdragte sonder 'n docker-kliënt wat HTTP-versoeke gebruik

In reaksie ontvang ons json waaruit ons tans net belangstel in die lewenslyne, of eerder hul hashes. Nadat ons dit ontvang het, kan ons deur elkeen gaan en die volgende versoek uitvoer: "GET /v2/{name}/blobs/{digest}"

"Toegang tot 'n laag sal deur die naam van die bewaarplek omhein word, maar word uniek in die register geïdentifiseer deur opsomming."

verteer in hierdie geval is die hash wat ons ontvang het.

Probeer

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

Implementeer docker pull en docker push-opdragte sonder 'n docker-kliënt wat HTTP-versoeke gebruik

Kom ons kyk watter soort lêer ons uiteindelik as die eerste reddingsboei ontvang het.

file firstLayer

Implementeer docker pull en docker push-opdragte sonder 'n docker-kliënt wat HTTP-versoeke gebruik

dié. relings is teer argiewe, uitpak hulle in die toepaslike volgorde sal ons die inhoud van die beeld kry.

Kom ons skryf 'n klein bash script sodat dit alles geoutomatiseer kan word

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

Nou kan ons dit met die verlangde parameters uitvoer en die inhoud van die vereiste beeld kry

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

Deel 2 - docker push

Dit sal 'n bietjie meer ingewikkeld wees.

Kom ons begin weer met dokumentasie. Ons moet dus elke leier aflaai, die ooreenstemmende manifes versamel en dit ook aflaai. Dit lyk eenvoudig.

Nadat ons die dokumentasie bestudeer het, kan ons die aflaaiproses in verskeie stappe verdeel:

  • Proses inisialisering - "POS /v2/{repoName}/blobs/uploads/"
  • Oplaai van 'n reddingsboei (ons sal 'n monolitiese oplaai gebruik, dit wil sê ons stuur elke reddingsboei in sy geheel) - "PUT /v2/{repoName}/blobs/uploads/{uuid}?digest={digest}
    Inhoud-lengte: {grootte van laag}
    Inhoud-tipe: toepassing/oktetstroom
    Laag Binêre Data".
  • Laai tans die manifes - "PUT /v2/{repoName}/manifests/{reference}".

Maar die dokumentasie mis een stap, waarsonder niks sal werk nie. Vir monolitiese laai, sowel as vir gedeeltelike (gebroke), voordat die spoor laai, moet jy 'n PATCH-versoek uitvoer:

"PATCH /v2/{repoName}/blobs/uploads/{uuid}
Inhoud-lengte: {grootte van stuk}
Inhoud-tipe: toepassing/oktetstroom
{Laagstuk Binêre Data}".

Andersins sal jy nie verder as die eerste punt kan beweeg nie, want... In plaas van die verwagte antwoordkode 202, sal jy 4xx ontvang.

Nou lyk die algoritme soos volg:

  • Inisialisering
  • Patch rail
  • Laai die leuning
  • Laai tans die manifes
    Punte 2 en 3, onderskeidelik, sal soveel keer herhaal word as wat die aantal reëls gelaai moet word.

Eerstens het ons enige beeld nodig. Ek sal archlinux: nuutste gebruik

docker pull archlinux

Implementeer docker pull en docker push-opdragte sonder 'n docker-kliënt wat HTTP-versoeke gebruik

Kom ons stoor dit nou plaaslik vir verdere ontleding

docker save c24fe13d37b9 -o savedArch

Implementeer docker pull en docker push-opdragte sonder 'n docker-kliënt wat HTTP-versoeke gebruik

Pak die resulterende argief uit in die huidige gids

tar xvf savedArch

Implementeer docker pull en docker push-opdragte sonder 'n docker-kliënt wat HTTP-versoeke gebruik

Soos u kan sien, is elke lewenslyn in 'n aparte vouer. Kom ons kyk nou na die struktuur van die manifes wat ons ontvang het

cat manifest.json | json_pp

Implementeer docker pull en docker push-opdragte sonder 'n docker-kliënt wat HTTP-versoeke gebruik

Nie veel nie. Kom ons kyk watter manifes nodig is om te laai, volgens dokumentasie.

Implementeer docker pull en docker push-opdragte sonder 'n docker-kliënt wat HTTP-versoeke gebruik

Dit is duidelik dat die bestaande manifes nie by ons pas nie, so ons sal ons eie maak met blackjack en courtisane, lewenslyne en konfigurasies.

Ons sal altyd ten minste een konfigurasielêer en 'n verskeidenheid lewenslyne hê. Skema weergawe 2 (huidig ​​ten tyde van skryf), mediatipe sal onveranderd gelaat word:

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

Nadat u die basiese manifes geskep het, moet u dit met geldige data vul. Om dit te doen, gebruik ons ​​die json-sjabloon van die spoorvoorwerp:

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

Ons sal dit by die manifes vir elke spoor voeg.

Vervolgens moet ons die grootte van die konfigurasielêer uitvind en die stompe in die manifes vervang met regte data

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

Nou kan jy die aflaaiproses begin en vir jouself 'n uuid stoor, wat alle daaropvolgende versoeke moet vergesel.

Die volledige skrif lyk so:

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

ons kan 'n klaargemaakte skrif gebruik:

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

UPS:
Wat het ons as gevolg daarvan gekry?
Eerstens, werklike data vir ontleding, aangesien die toetse in blazemeter uitgevoer word en die data oor docker-kliëntversoeke nie baie insiggewend is nie, anders as suiwer HTTP-versoeke.

Tweedens het die oorgang ons in staat gestel om die aantal virtuele gebruikers vir docker-oplaai met ongeveer 150% te verhoog en gemiddelde reaksietyd 20-25% vinniger te kry. Vir docker-aflaai het ons daarin geslaag om die aantal gebruikers met 500% te verhoog, terwyl die gemiddelde reaksietyd met ongeveer 60% afgeneem het.

Dankie vir jou aandag.

Bron: will.com

Voeg 'n opmerking