Gweithredu gorchmynion tynnu docwr a gwthio docwyr heb gleient docwr gan ddefnyddio ceisiadau HTTP

Cawsom 2 fag o laswellt, 75 o dabledi mescaline amgylchedd unix, ystorfa docwr a'r dasg o weithredu'r gorchmynion tynnu docwr a gwthio tocwr heb gleient docwr.

Gweithredu gorchmynion tynnu docwr a gwthio docwyr heb gleient docwr gan ddefnyddio ceisiadau HTTP

DIWEDDARIAD:
Cwestiwn: Beth yw pwrpas hyn i gyd?
Ateb: Profi llwyth o'r cynnyrch (NID defnyddio bash, darperir y sgriptiau at ddibenion addysgol). Penderfynwyd peidio â defnyddio'r cleient docwr i leihau haenau ychwanegol (o fewn terfynau rhesymol) ac, yn unol â hynny, efelychu llwyth uwch. O ganlyniad, dilëwyd holl oedi system y cleient Docker. Cawsom lwyth cymharol lân yn uniongyrchol ar y cynnyrch.
Defnyddiodd yr erthygl fersiynau GNU o offer.

Yn gyntaf, gadewch i ni ddarganfod beth mae'r gorchmynion hyn yn ei wneud.

Felly ar gyfer beth mae tociwr yn cael ei ddefnyddio? Yn ôl dogfennaeth:

msgstr "Tynnu delwedd neu gadwrfa o gofrestrfa".

Yma hefyd rydym yn dod o hyd i ddolen i deall delweddau, cynwysyddion, a gyrwyr storio.

Gweithredu gorchmynion tynnu docwr a gwthio docwyr heb gleient docwr gan ddefnyddio ceisiadau HTTP

O'r fan hon, gallwn ddeall bod delwedd docwr yn set o haenau penodol sy'n cynnwys gwybodaeth am y newidiadau diweddaraf yn y ddelwedd, sef yr hyn sydd ei angen arnom yn amlwg. Nesaf edrychwn ar API cofrestrfa.

Mae'n dweud y canlynol:

"Mae "delwedd" yn gyfuniad o faniffest JSON a ffeiliau haen unigol. Mae'r broses o dynnu delwedd > yn canolbwyntio ar adfer y ddwy gydran hyn."

Felly y cam cyntaf yn ôl y ddogfennaeth yw “Tynnu Maniffest Delwedd".

Wrth gwrs, ni fyddwn yn ei saethu, ond mae angen y data ohono. Mae'r canlynol yn gais enghreifftiol: GET /v2/{name}/manifests/{reference}

msgstr "Mae'r enw a'r paramedr cyfeirnod yn adnabod y ddelwedd ac yn ofynnol. Gall y cyfeirnod gynnwys tag neu grynodeb."

Mae ein storfa docwyr yn cael ei defnyddio'n lleol, gadewch i ni geisio gweithredu'r cais:

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

Gweithredu gorchmynion tynnu docwr a gwthio docwyr heb gleient docwr gan ddefnyddio ceisiadau HTTP

Mewn ymateb, rydym yn derbyn json a dim ond y llinellau achub sydd gennym ar hyn o bryd, neu yn hytrach eu hashes. Ar ôl eu derbyn, gallwn fynd trwy bob un a gweithredu'r cais canlynol: "GET /v2/{name}/blobs/{digest}"

“Bydd mynediad i haen yn cael ei osod yn ôl enw’r gadwrfa ond fe’i nodir yn unigryw yn y gofrestr trwy grynodeb.”

dreulio yn yr achos hwn yw'r hash a gawsom.

Yn ceisio

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

Gweithredu gorchmynion tynnu docwr a gwthio docwyr heb gleient docwr gan ddefnyddio ceisiadau HTTP

Gadewch i ni weld pa fath o ffeil a gawsom o'r diwedd fel y achubiaeth gyntaf.

file firstLayer

Gweithredu gorchmynion tynnu docwr a gwthio docwyr heb gleient docwr gan ddefnyddio ceisiadau HTTP

y rhai. archifau tar yw rheiliau, gan eu dadbacio yn y drefn briodol byddwn yn cael cynnwys y ddelwedd.

Gadewch i ni ysgrifennu sgript bash fach fel y gellir awtomeiddio hyn i gyd

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

Nawr gallwn ei redeg gyda'r paramedrau dymunol a chael cynnwys y ddelwedd ofynnol

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

Rhan 2 - gwthio docwr

Bydd hyn ychydig yn fwy cymhleth.

Gadewch i ni ddechrau eto gyda dogfennaeth. Felly mae angen i ni lawrlwytho pob arweinydd, casglu'r maniffest cyfatebol a'i lawrlwytho hefyd. Mae'n ymddangos yn syml.

Ar ôl astudio'r ddogfennaeth, gallwn rannu'r broses lawrlwytho yn sawl cam:

  • Cychwyn proses - "POST /v2/{repoName}/blobs/uploads/"
  • Wrthi'n uwchlwytho llinell achub (byddwn yn defnyddio uwchlwythiad monolithig, h.y. byddwn yn anfon pob achubiaeth yn ei gyfanrwydd) - "PUT /v2/{repoName}/blobs/uploads/{uuid}?digest={digest}
    Hyd y Cynnwys: {maint yr haen}
    Math o Gynnwys: cymhwysiad / ffrwd octet
    Data Deuaidd Haen".
  • Wrthi'n llwytho'r maniffest - "PUT /v2/{repoName}/manifests/{reference}".

Ond mae'r ddogfennaeth yn methu un cam, na fydd dim yn gweithio hebddo. Ar gyfer llwytho monolithig, yn ogystal ag ar gyfer rhannol (talpio), cyn llwytho'r rheilen, rhaid i chi wneud cais PATCH:

"PATCH /v2/{repoName}/blobs/uploads/{uuid}
Hyd y Cynnwys: {maint y talp}
Math o Gynnwys: cymhwysiad / ffrwd octet
{Haen Chunk Data Deuaidd}".

Fel arall, ni fyddwch yn gallu symud y tu hwnt i'r pwynt cyntaf, oherwydd ... Yn lle'r cod ymateb disgwyliedig 202, byddwch yn derbyn 4xx.

Nawr mae'r algorithm yn edrych fel:

  • Cychwyn
  • Rheilffordd clwt
  • Llwytho'r canllaw
  • Wrthi'n llwytho'r maniffest
    Bydd pwyntiau 2 a 3, yn y drefn honno, yn cael eu hailadrodd gymaint o weithiau ag y mae angen llwytho nifer y llinellau.

Yn gyntaf, mae angen unrhyw ddelwedd arnom. Byddaf yn defnyddio archlinux: diweddaraf

docker pull archlinux

Gweithredu gorchmynion tynnu docwr a gwthio docwyr heb gleient docwr gan ddefnyddio ceisiadau HTTP

Nawr gadewch i ni ei arbed yn lleol i'w ddadansoddi ymhellach

docker save c24fe13d37b9 -o savedArch

Gweithredu gorchmynion tynnu docwr a gwthio docwyr heb gleient docwr gan ddefnyddio ceisiadau HTTP

Dadbacio'r archif canlyniadol i'r cyfeiriadur cyfredol

tar xvf savedArch

Gweithredu gorchmynion tynnu docwr a gwthio docwyr heb gleient docwr gan ddefnyddio ceisiadau HTTP

Fel y gallwch weld, mae pob achubiaeth mewn ffolder ar wahân. Nawr, gadewch i ni edrych ar strwythur y maniffest a gawsom

cat manifest.json | json_pp

Gweithredu gorchmynion tynnu docwr a gwthio docwyr heb gleient docwr gan ddefnyddio ceisiadau HTTP

Dim llawer. Gawn ni weld pa faniffest sydd ei angen i lwytho, yn ôl dogfennaeth.

Gweithredu gorchmynion tynnu docwr a gwthio docwyr heb gleient docwr gan ddefnyddio ceisiadau HTTP

Yn amlwg, nid yw’r maniffesto presennol yn addas i ni, felly byddwn yn gwneud ein maniffesto ein hunain gyda blackjack a chwrteisi, llinellau achub a chyfluniadau.

Bydd gennym bob amser o leiaf un ffeil ffurfweddu ac amrywiaeth o linellau achub. Fersiwn 2 o'r cynllun (yn gyfredol ar adeg ysgrifennu), ni fydd y math o gyfryngau yn cael ei newid:

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

Ar ôl creu'r maniffest sylfaenol, mae angen i chi ei lenwi â data dilys. I wneud hyn, rydym yn defnyddio templed json y gwrthrych rheilffordd:

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

Byddwn yn ei ychwanegu at y maniffest ar gyfer pob rheilffordd.

Nesaf, mae angen inni ddarganfod maint y ffeil ffurfweddu a disodli'r bonion yn y maniffest â data go iawn

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

Nawr gallwch chi gychwyn y broses lawrlwytho ac arbed uuid i chi'ch hun, a ddylai gyd-fynd â phob cais dilynol.

Mae'r sgript gyflawn yn edrych rhywbeth fel hyn:

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

gallwn ddefnyddio sgript parod:

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

DIWEDDARIAD:
Beth gawson ni o ganlyniad?
Yn gyntaf, data go iawn i'w ddadansoddi, gan fod y profion yn cael eu rhedeg mewn blazemeter ac nid yw'r data ar geisiadau cleientiaid docwyr yn addysgiadol iawn, yn wahanol i geisiadau HTTP pur.

Yn ail, roedd y cyfnod pontio yn caniatáu inni gynyddu nifer y defnyddwyr rhithwir ar gyfer lanlwytho docwyr tua 150% a chael amser ymateb avg 20-25% yn gyflymach. Ar gyfer lawrlwytho docwyr, rydym wedi llwyddo i gynyddu nifer y defnyddwyr 500%, tra bod amser ymateb avg wedi gostwng tua 60%.

Diolch i chi am eich sylw.

Ffynhonnell: hab.com

Ychwanegu sylw