Kami memiliki 2 kantong rumput, 75 tablet mescaline lingkungan unix, repositori buruh pelabuhan dan tugas mengimplementasikan perintah docker pull dan docker Push tanpa klien buruh pelabuhan.
UPD:
Pertanyaan: Untuk apa semua ini?
Jawaban: Memuat pengujian produk (TIDAK menggunakan bash, skrip disediakan untuk tujuan pendidikan). Diputuskan untuk tidak menggunakan klien buruh pelabuhan untuk mengurangi lapisan tambahan (dalam batas wajar) dan, karenanya, meniru beban yang lebih tinggi. Hasilnya, semua penundaan sistem klien Docker telah dihapus. Kami menerima muatan yang relatif bersih langsung pada produk.
Artikel ini menggunakan alat versi GNU.
Pertama, mari kita cari tahu apa yang dilakukan perintah-perintah ini.
Jadi untuk apa docker pull digunakan? Berdasarkan
"Tarik gambar atau repositori dari registri".
Di sana kami juga menemukan tautan ke
Dari sini kita dapat memahami bahwa image docker adalah sekumpulan layer tertentu yang berisi informasi tentang perubahan terbaru pada image, yang tentunya kita butuhkan. Selanjutnya kita lihat
Dikatakan sebagai berikut:
"Sebuah" gambar "adalah kombinasi manifes JSON dan file lapisan individual. Proses menarik gambar > berpusat pada pengambilan kedua komponen ini."
Jadi langkah pertama menurut dokumentasi adalah βMenarik Manifes Gambar".
Tentu saja kami tidak akan memotretnya, tetapi kami memerlukan data darinya. Berikut contoh permintaannya: GET /v2/{name}/manifests/{reference}
"Nama dan parameter referensi mengidentifikasi gambar dan diperlukan. Referensi dapat menyertakan tag atau intisari."
Repositori buruh pelabuhan kami diterapkan secara lokal, mari coba jalankan 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 tanggapan, kami menerima json yang saat ini kami hanya tertarik pada jalur hidup, atau lebih tepatnya hashnya. Setelah menerimanya, kita dapat memeriksa masing-masingnya dan menjalankan permintaan berikut: "GET /v2/{name}/blobs/{digest}"
βAkses ke suatu lapisan akan dibatasi berdasarkan nama repositori tetapi diidentifikasi secara unik di registri berdasarkan intisari.β
intisari dalam hal ini adalah hash yang kami terima.
Mencoba
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 kita lihat file seperti apa yang akhirnya kita terima sebagai penyelamat pertama.
file firstLayer
itu. rails adalah arsip tar, membongkarnya dalam urutan yang sesuai kita akan mendapatkan konten gambar.
Mari kita tulis skrip bash kecil agar semua ini bisa diotomatisasi
#!/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 dapat menjalankannya dengan parameter yang diinginkan dan mendapatkan konten gambar yang diperlukan
./script.sh dirName βhttp://localhost:8081/link/to/docker/registryβ myAwesomeImage 1.0
Bagian 2 - dorongan buruh pelabuhan
Ini akan menjadi sedikit lebih rumit.
Mari kita mulai lagi dengan
Setelah mempelajari dokumentasinya, kita dapat membagi proses pengunduhan menjadi beberapa langkah:
- Inisialisasi proses - "POST /v2/{repoName}/blobs/uploads/"
- Mengunggah lifeline (kami akan menggunakan unggahan monolitik, yaitu kami mengirimkan setiap lifeline secara keseluruhan) - "PUT /v2/{repoName}/blobs/uploads/{uuid}?digest={digest}
Panjang Konten: {ukuran lapisan}
Tipe-Konten: aplikasi/aliran oktet
Lapisan Data Biner". - Memuat manifes - "PUT /v2/{repoName}/manifests/{reference}".
Namun dokumentasinya melewatkan satu langkah, yang tanpanya tidak ada yang akan berhasil. Untuk pemuatan monolitik, serta untuk pemuatan parsial (terpotong), sebelum memuat rel, Anda harus melakukan permintaan PATCH:
"PATCH /v2/{repoName}/blobs/uploads/{uuid}
Panjang Konten: {ukuran potongan}
Tipe-Konten: aplikasi/aliran oktet
{Data Biner Potongan Lapisan}".
Jika tidak, Anda tidak akan bisa melampaui poin pertama, karena... Alih-alih kode respons yang diharapkan 202, Anda akan menerima 4xx.
Sekarang algoritmanya terlihat seperti:
- Inisialisasi
- Rel tambalan
- Memuat pegangan
- Memuat manifes
Poin 2 dan 3, masing-masing, akan diulangi sebanyak jumlah baris yang perlu dimuat.
Pertama, kita membutuhkan gambar apa pun. Saya akan menggunakan archlinux: terbaru
docker pull archlinux
Sekarang mari simpan secara lokal untuk analisis lebih lanjut
docker save c24fe13d37b9 -o savedArch
Buka paket arsip yang dihasilkan ke direktori saat ini
tar xvf savedArch
Seperti yang Anda lihat, setiap jalur hidup berada dalam folder terpisah. Sekarang mari kita lihat struktur manifes yang kami terima
cat manifest.json | json_pp
Tidak banyak. Mari kita lihat manifes apa yang diperlukan untuk memuat, menurut
Jelas sekali, manifesto yang ada tidak cocok untuk kami, jadi kami akan membuatnya sendiri dengan blackjack dan pelacur, garis hidup, dan konfigurasi.
Kami akan selalu memiliki setidaknya satu file konfigurasi dan serangkaian jalur hidup. Skema versi 2 (saat ini pada saat penulisan), mediaType tidak akan 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
Setelah membuat manifes dasar, Anda perlu mengisinya dengan data yang valid. Untuk melakukan ini, kita menggunakan template json dari objek rail:
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": ${layersSizes[$i]},
"digest": "sha256:${layersNames[$i]}"
},
Kami akan menambahkannya ke manifes untuk setiap rel.
Selanjutnya, kita perlu mengetahui ukuran file konfigurasi dan mengganti stub di manifes dengan data sebenarnya
sed -i "s/config_size/$configSize/g; s/config_hash/$configName/g" $manifestFile
Sekarang Anda dapat memulai proses pengunduhan dan menyimpan uuid, yang akan menyertai semua permintaan berikutnya.
Script lengkapnya terlihat 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 dapat menggunakan skrip yang sudah jadi:
./uploadImage.sh "~/path/to/saved/image" "http://localhost:8081/link/to/docker/registry" myRepoName 1.0
UPD:
Apa yang kami dapatkan sebagai hasilnya?
Pertama, data nyata untuk analisis, karena pengujian dijalankan di blazemeter dan data permintaan klien buruh pelabuhan tidak terlalu informatif, tidak seperti permintaan HTTP murni.
Kedua, transisi ini memungkinkan kami meningkatkan jumlah pengguna virtual untuk unggahan buruh pelabuhan sekitar 150% dan mendapatkan waktu respons rata-rata 20-25% lebih cepat. Untuk pengunduhan buruh pelabuhan, kami berhasil meningkatkan jumlah pengguna sebesar 500%, sementara waktu respons rata-rata menurun sekitar 60%.
Terima kasih atas perhatian Anda.
Sumber: www.habr.com