Kami mempunyai 2 beg rumput, 75 tablet mescaline persekitaran unix, repositori docker dan tugas melaksanakan perintah tarik docker dan push docker tanpa klien docker.
UPD:
Soalan: Untuk apa semua ini?
Jawapan: Muatkan ujian produk (TIDAK menggunakan bash, skrip disediakan untuk tujuan pendidikan). Diputuskan untuk tidak menggunakan klien docker untuk mengurangkan lapisan tambahan (dalam had yang munasabah) dan, dengan itu, meniru beban yang lebih tinggi. Akibatnya, semua kelewatan sistem klien Docker telah dialih keluar. Kami menerima beban yang agak bersih secara langsung pada produk.
Artikel itu menggunakan alat versi GNU.
Mula-mula, mari kita fikirkan apa yang dilakukan oleh arahan ini.
Jadi untuk apa tarikan buruh pelabuhan digunakan? mengikut
"Tarik imej atau repositori daripada pendaftaran".
Di sana kami juga mencari pautan ke
Dari sini kita dapat memahami bahawa imej docker ialah satu set lapisan tertentu yang mengandungi maklumat tentang perubahan terkini dalam imej, yang jelas adalah apa yang kita perlukan. Seterusnya kita lihat
Ia mengatakan perkara berikut:
"Imej" ialah gabungan fail manifes JSON dan lapisan individu. Proses menarik > imej tertumpu pada mendapatkan semula dua komponen ini."
Jadi langkah pertama mengikut dokumentasi ialah "Menarik Manifes Imej".
Sudah tentu, kami tidak akan menembaknya, tetapi kami memerlukan data daripadanya. Berikut adalah contoh permintaan: GET /v2/{name}/manifests/{reference}
"Nama dan parameter rujukan mengenal pasti imej dan diperlukan. Rujukan mungkin termasuk teg atau ringkasan."
Repositori docker kami digunakan secara tempatan, mari cuba laksanakan permintaan:
curl -s -X GET "http://localhost:8081/link/to/docker/registry/v2/centos-11-10/manifests/1.1.1" -H "header_if_needed"
Sebagai tindak balas, kami menerima json yang pada masa ini kami hanya berminat dengan talian hayat, atau lebih tepatnya cincang mereka. Setelah menerimanya, kami boleh meneruskan setiap satu dan melaksanakan permintaan berikut: "GET /v2/{name}/blobs/{digest}"
"Akses kepada lapisan akan berpagar dengan nama repositori tetapi dikenal pasti secara unik dalam pendaftaran melalui ringkasan."
digest dalam kes ini ialah cincangan yang kami terima.
Mencuba
curl -s -X GET "http://localhost:8081/link/to/docker/registry/v2/centos-11-10/blobs/sha256:f972d139738dfcd1519fd2461815651336ee25a8b54c358834c50af094bb262f" -H "header_if_needed" --output firstLayer
Mari lihat jenis fail yang akhirnya kami terima sebagai talian hayat pertama.
file firstLayer
mereka. rel adalah arkib tar, membongkarnya dalam susunan yang sesuai kita akan mendapat kandungan imej.
Mari kita tulis skrip bash kecil supaya semua ini boleh diautomasikan
#!/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
Sekarang kita boleh menjalankannya dengan parameter yang dikehendaki dan mendapatkan kandungan imej yang diperlukan
./script.sh dirName βhttp://localhost:8081/link/to/docker/registryβ myAwesomeImage 1.0
Bahagian 2 - docker push
Ini akan menjadi sedikit lebih rumit.
Mari kita mulakan semula dengan
Selepas mengkaji dokumentasi, kami boleh membahagikan proses muat turun kepada beberapa langkah:
- Permulaan proses - "POST /v2/{repoName}/blobs/uploads/"
- Memuat naik talian hayat (kami akan menggunakan muat naik monolitik, iaitu kami menghantar setiap talian hayat secara keseluruhan) - "PUT /v2/{repoName}/blobs/uploads/{uuid}?digest={digest}
Panjang Kandungan: {saiz lapisan}
Jenis Kandungan: aplikasi/strim oktet
Data Perduaan Lapisan". - Memuatkan manifes - "PUT /v2/{repoName}/manifests/{reference}".
Tetapi dokumentasi terlepas satu langkah, tanpanya tiada apa yang akan berfungsi. Untuk pemuatan monolitik, serta untuk separa (potongan), sebelum memuatkan rel, anda mesti melakukan permintaan PATCH:
"PATCH /v2/{repoName}/blobs/uploads/{uuid}
Panjang Kandungan: {size of chunk}
Jenis Kandungan: aplikasi/strim oktet
{Layer Chunk Binary Data}".
Jika tidak, anda tidak akan dapat bergerak melepasi titik pertama, kerana... Daripada kod respons yang dijangkakan 202, anda akan menerima 4xx.
Sekarang algoritma kelihatan seperti:
- Permulaan
- Rel tampalan
- Memuatkan susur tangan
- Memuatkan manifes
Mata 2 dan 3, masing-masing, akan diulang seberapa banyak bilangan baris yang perlu dimuatkan.
Pertama, kita memerlukan sebarang imej. Saya akan menggunakan archlinux:latest
docker pull archlinux
Sekarang mari simpannya secara tempatan untuk analisis lanjut
docker save c24fe13d37b9 -o savedArch
Buka pek arkib yang terhasil ke dalam direktori semasa
tar xvf savedArch
Seperti yang anda lihat, setiap talian hayat berada dalam folder yang berasingan. Sekarang mari kita lihat struktur manifes yang kami terima
cat manifest.json | json_pp
Tidak banyak. Mari lihat manifes apa yang diperlukan untuk dimuatkan, menurut
Jelas sekali, manifesto sedia ada tidak sesuai dengan kami, jadi kami akan membuat sendiri dengan blackjack dan courtesans, talian hayat dan konfigurasi.
Kami akan sentiasa mempunyai sekurang-kurangnya satu fail konfigurasi dan pelbagai talian hayat. Skim versi 2 (semasa pada masa penulisan), mediaType akan dibiarkan tidak berubah:
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
Selepas mencipta manifes asas, anda perlu mengisinya dengan data yang sah. Untuk melakukan ini, kami menggunakan templat json objek rel:
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": ${layersSizes[$i]},
"digest": "sha256:${layersNames[$i]}"
},
Kami akan menambahkannya pada manifes untuk setiap rel.
Seterusnya, kita perlu mengetahui saiz fail konfigurasi dan menggantikan stub dalam manifes dengan data sebenar
sed -i "s/config_size/$configSize/g; s/config_hash/$configName/g" $manifestFile
Kini anda boleh memulakan proses muat turun dan menyelamatkan diri anda uuid, yang sepatutnya mengiringi semua permintaan seterusnya.
Skrip lengkap kelihatan seperti ini:
#!/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
kita boleh menggunakan skrip siap sedia:
./uploadImage.sh "~/path/to/saved/image" "http://localhost:8081/link/to/docker/registry" myRepoName 1.0
UPD:
Apa yang kita dapat sebagai hasilnya?
Pertama, data sebenar untuk analisis, kerana ujian dijalankan dalam blazemeter dan data pada permintaan klien docker tidak begitu bermaklumat, tidak seperti permintaan HTTP tulen.
Kedua, peralihan itu membolehkan kami meningkatkan bilangan pengguna maya untuk muat naik buruh pelabuhan sebanyak kira-kira 150% dan mendapat purata masa tindak balas 20-25% lebih cepat. Untuk muat turun buruh pelabuhan, kami berjaya meningkatkan bilangan pengguna sebanyak 500%, manakala purata masa tindak balas menurun sebanyak kira-kira 60%.
Terima kasih atas perhatian anda.
Sumber: www.habr.com