Volt 2 zsák fű, 75 mescaline tablet unix környezet, egy docker repository és a docker pull és docker push parancsok megvalósítása docker kliens nélkül.
UPS:
Kérdés: Minek ez az egész?
Válasz: A termék terhelési tesztelése (NEM használ bash-t, a szkriptek oktatási célokat szolgálnak). Úgy döntöttek, hogy nem használják a docker klienst további rétegek csökkentésére (ésszerű határokon belül), és ennek megfelelően nagyobb terhelés emulálására. Ennek eredményeként a Docker-ügyfél minden rendszerkésleltetése megszűnt. Közvetlenül a termékre viszonylag tiszta terhelést kaptunk.
A cikk az eszközök GNU verzióit használta.
Először is nézzük meg, mit csinálnak ezek a parancsok.
Tehát mire használják a docker pull-t? Alapján
"Húzz le egy képet vagy egy adattárat a rendszerleíró adatbázisból".
Ott találunk egy linket is
Innen érthetjük meg, hogy a docker kép bizonyos rétegek halmaza, amelyek a kép legfrissebb változásairól tartalmaznak információkat, amire nyilvánvalóan szükségünk van. Következő megnézzük
A következőt írja:
"A „kép” egy JSON-jegyzékfájl és az egyes rétegfájlok kombinációja. A kép előhívásának folyamata e két összetevő lekérésére irányul."
Tehát az első lépés a dokumentáció szerint "Kép Manifest húzása".
Természetesen nem fogjuk lelőni, de szükségünk van az adatokra. A következő példa egy kérés: GET /v2/{name}/manifests/{reference}
"A név és a referenciaparaméter azonosítja a képet, és kötelező. A hivatkozás tartalmazhat címkét vagy kivonatot."
Docker tárolónk helyben van telepítve, próbáljuk meg végrehajtani a kérést:
curl -s -X GET "http://localhost:8081/link/to/docker/registry/v2/centos-11-10/manifests/1.1.1" -H "header_if_needed"
Válaszul json-t kapunk, amelyből jelenleg csak az életvonalak, vagy inkább azok hash-ei érdekelnek bennünket. Miután megkaptuk őket, mindegyiket végignézhetjük, és végrehajthatjuk a következő kérést: "GET /v2/{name}/blobs/{digest}"
"A réteghez való hozzáférést a lerakat neve korlátozza, de a rendszerleíró adatbázisban egyedileg azonosítja a kivonat."
digest ebben az esetben az a hash, amit kaptunk.
Megpróbálja
curl -s -X GET "http://localhost:8081/link/to/docker/registry/v2/centos-11-10/blobs/sha256:f972d139738dfcd1519fd2461815651336ee25a8b54c358834c50af094bb262f" -H "header_if_needed" --output firstLayer
Lássuk, milyen fájlt kaptunk végre első mentőövként.
file firstLayer
azok. sínek tar archívumok, ezeket megfelelő sorrendben kicsomagolva megkapjuk a kép tartalmát.
Írjunk egy kis bash szkriptet, hogy mindez automatizálható legyen
#!/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
Most már futtathatjuk a kívánt paraméterekkel, és megkapjuk a kívánt kép tartalmát
./script.sh dirName “http://localhost:8081/link/to/docker/registry” myAwesomeImage 1.0
2. rész - Docker push
Ez egy kicsit bonyolultabb lesz.
Kezdjük újra azzal
A dokumentáció tanulmányozása után a letöltési folyamatot több lépésre oszthatjuk:
- Folyamat inicializálása - "POST /v2/{repoName}/blobs/uploads/"
- Mentőkötél feltöltése (monolit feltöltést fogunk használni, azaz minden mentőövet teljes egészében elküldünk) - "PUT /v2/{repoName}/blobs/uploads/{uuid}?digest={digest}
Tartalom hossza: {réteg mérete}
Tartalomtípus: alkalmazás/oktett-folyam
Réteg bináris adat". - A jegyzék betöltése – „PUT /v2/{repoName}/manifests/{reference}”.
De a dokumentációból hiányzik egy lépés, amely nélkül semmi sem fog működni. Monolitikus, valamint részleges (darabolt) terhelés esetén a sín terhelése előtt egy PATCH kérést kell végrehajtania:
"PATCH /v2/{repoName}/blobs/uploads/{uuid}
Tartalom hossza: {size of chunk}
Tartalomtípus: alkalmazás/oktett-folyam
{Layer Chunk Binary Data}".
Ellenkező esetben nem fog tudni túllépni az első ponton, mert... A várt 202-es válaszkód helyett 4xx-et fog kapni.
Az algoritmus most így néz ki:
- Inicializálás
- Patch sín
- A kapaszkodó terhelése
- A jegyzék betöltése
A 2. és 3. pont annyiszor ismétlődik, ahány sort be kell tölteni.
Először is szükségünk van bármilyen képre. Az archlinux:latest programot fogom használni
docker pull archlinux
Most mentsük el helyben további elemzés céljából
docker save c24fe13d37b9 -o savedArch
Csomagolja ki a kapott archívumot az aktuális könyvtárba
tar xvf savedArch
Amint látja, minden mentőkötél külön mappában van. Most nézzük meg a kapott manifeszt felépítését
cat manifest.json | json_pp
Nem sok. Lássuk, milyen manifest szükséges a betöltéshez, szerint
Nyilvánvaló, hogy a meglévő kiáltvány nem felel meg nekünk, ezért blackjack-kel és kurtizánokkal, mentőkötélekkel és konfigokkal elkészítjük a magunkét.
Mindig lesz legalább egy konfigurációs fájlunk és egy sor életvonalunk. A séma 2-es verziója (jelenleg az írás idején), a mediaType változatlan marad:
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
Az alapjegyzék létrehozása után ki kell töltenie érvényes adatokkal. Ehhez a rail objektum json sablonját használjuk:
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": ${layersSizes[$i]},
"digest": "sha256:${layersNames[$i]}"
},
Minden sínhez hozzáadjuk a manifesthez.
Ezután meg kell találnunk a konfigurációs fájl méretét, és a jegyzékben lévő csonkokat valós adatokra kell cserélnünk.
sed -i "s/config_size/$configSize/g; s/config_hash/$configName/g" $manifestFile
Most már elindíthatja a letöltési folyamatot, és menthet magának egy uuid-t, amely minden további kérést kísér.
A teljes szkript valahogy így néz ki:
#!/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
használhatunk egy kész szkriptet:
./uploadImage.sh "~/path/to/saved/image" "http://localhost:8081/link/to/docker/registry" myRepoName 1.0
UPS:
Mit kaptunk ennek eredményeként?
Először is valós adatok az elemzéshez, mivel a tesztek blazemeterben futnak, és a docker kliens kérések adatai nem túl informatívak, ellentétben a tiszta HTTP kérésekkel.
Másodszor, az átállás lehetővé tette számunkra, hogy körülbelül 150%-kal növeljük a docker feltöltéshez szükséges virtuális felhasználók számát, és 20-25%-kal gyorsabban tudtuk elérni az átlagos válaszidőt. A docker letöltésnél 500%-kal sikerült növelnünk a felhasználók számát, miközben az átlagos válaszidő körülbelül 60%-kal csökkent.
Köszönöm a figyelmet.
Forrás: will.com