7-bo‘lim
Ko'p bosqichli qurish
Qurish vositalarini yakuniy obrazdan chiqarib tashlash, COPY --from, scratch va --target.
Ushbu bo‘lim mundarijasi
Ilovani qurish uchun kompilyator, kutubxona sarlavhalari va paket menejeri kerak. Ishlatish uchun esa - faqat tayyor natija.
Ko'p bosqichli qurish shu ikkisini ajratadi.
Muammo #
Kichik C dasturini olamiz - u mingtagacha sonlarni qo'shadi:
#include <stdio.h>
int main(void) {
long jami = 0;
for (long i = 1; i <= 1000000; i++) jami += i;
printf("Dokon hisoboti: %ld\n", jami);
return 0;
}
Eng oddiy Dockerfile:
FROM alpine:3.21
RUN apk add --no-cache build-base
WORKDIR /ilova
COPY hisob.c .
RUN gcc -static -O2 -o hisob hisob.c
CMD ["./hisob"]
Ishlaydi:
docker run --rm bir-bosqich:1
Dokon hisoboti: 500000500000
Lekin obrazda kerakmas narsa bor:
docker run --rm bir-bosqich:1 which gcc
/usr/bin/gcc
Ishlab chiqarish serveringizda kompilyator turibdi. U hech qachon kerak bo'lmaydi, lekin obrazni kattalashtiradi va hujum yuzasini kengaytiradi.
Yechim: bosqichlarga bo'lish #
FROM alpine:3.21 AS quruvchi
RUN apk add --no-cache build-base
WORKDIR /ilova
COPY hisob.c .
RUN gcc -static -O2 -o hisob hisob.c
FROM alpine:3.21
WORKDIR /ilova
COPY --from=quruvchi /ilova/hisob .
CMD ["./hisob"]
Ikkita FROM - ikkita bosqich. Birinchisiga AS quruvchi deb nom
berdik.
Ikkinchi bosqich toza alpine dan boshlanadi va undan faqat
bitta narsa oladi: COPY --from=quruvchi orqali tayyor faylni.
Natija bir xil:
docker run --rm kop-bosqich:1
Dokon hisoboti: 500000500000
Kompilyator esa yo'q:
docker run --rm kop-bosqich:1 which gcc || echo "gcc yo'q - yaxshi"
gcc yo'q - yaxshi
Farqni o'lchaymiz #
for t in bir-bosqich:1 kop-bosqich:1; do
docker images "$t" --format '{{.Repository}} {{.Size}}'
done
bir-bosqich 353MB
kop-bosqich 12.4MB
353 MB va 12.4 MB - 28 barobar farq. Va bu farq har bir serverga, har bir yetkazishda takrorlanadi.
Yana ham kichik: scratch #
scratch - bu obraz emas, balki "asos yo'q" degan maxsus so'z.
Statik bog'langan dastur uchun undan boshqa hech narsa kerak emas:
FROM alpine:3.21 AS quruvchi
RUN apk add --no-cache build-base
WORKDIR /ilova
COPY hisob.c .
RUN gcc -static -O2 -o hisob hisob.c
FROM scratch
COPY --from=quruvchi /ilova/hisob /hisob
CMD ["/hisob"]
docker run --rm scratch-bosqich:1
docker images scratch-bosqich:1 --format '{{.Repository}} {{.Size}}'
Dokon hisoboti: 500000500000
scratch-bosqich 200kB
200 kilobayt. Butun obraz - bitta bajariladigan fayl.
Uchalasini yonma-yon qo'yamiz:
for t in bir-bosqich:1 kop-bosqich:1 scratch-bosqich:1; do
printf '%-18s %s ta qatlam\n' "$t" \
"$(docker inspect "$t" -f '{{len .RootFS.Layers}}')"
done
bir-bosqich:1 5 ta qatlam
kop-bosqich:1 3 ta qatlam
scratch-bosqich:1 1 ta qatlam
| Variant | Hajmi | Qatlam | Ichida nima bor |
|---|---|---|---|
| Bir bosqichli | 353 MB | 5 | Kompilyator, sarlavhalar, manba kod |
| Ko'p bosqichli | 12.4 MB | 3 | Alpine + dastur |
scratch | 200 kB | 1 | Faqat dastur |
scratch da hech narsa yo'q - haqiqatan hech narsadocker run --rm scratch-bosqich:1 ls
Bu ishlamaydi: ls ham, sh ham obrazda yo'q. Demak:
docker exec ... shbilan ichiga kira olmaysiz- Xato xabarlari tushunarsiz bo'ladi
- Ilovangiz
libcga bog'liq bo'lsa, umuman ishga tushmaydi
scratch faqat statik bog'langan dasturlar uchun: Go, Rust,
-static bilan qurilgan C.
Oraliq yechim - distroless obrazlari: ular qobiqsiz, lekin
libc va sertifikatlarni saqlaydi.
--target bilan bitta bosqichni qurish #
Ba'zan faqat quruvchi bosqich kerak bo'ladi - masalan CI da testlarni o'sha muhitda ishga tushirish uchun:
docker run --rm faqat-quruvchi:1 sh -c 'which gcc && ls hisob'
/usr/bin/gcc
hisob
Bu obraz shunday qurilgan:
docker build -f Dockerfile.kop --target quruvchi -t faqat-quruvchi:1 .
--target qurishni belgilangan bosqichda to'xtatadi.
Ko'p loyihalarda bitta faylda uchta bosqich bo'ladi:
FROM node:22-alpine AS quruvchi # bog'liqliklar + qurish
FROM quruvchi AS sinov # testlar shu yerda ishlaydi
FROM nginx:alpine AS yakuniy # faqat natija
CI da:
docker build --target sinov -t app:sinov . # testlar
docker build -t app:1.0 . # ishlab chiqarish
Sinov bosqichi quruvchidan meros oladi, demak bog'liqliklar qaytadan o'rnatilmaydi.
Bosqichlar orasida nusxa olish #
COPY --from uchta shaklda ishlaydi:
| Yozuv | Nimadan oladi |
|---|---|
COPY --from=quruvchi | Nomlangan bosqichdan |
COPY --from=0 | Tartib raqami bo'yicha (0 - birinchi) |
COPY --from=nginx:alpine | To'g'ridan-to'g'ri boshqa obrazdan |
Uchinchisi foydali: masalan sertifikatlarni tayyor obrazdan olish.
COPY --from=alpine:3.21 /etc/ssl/certs /etc/ssl/certs
--from=0 ishlaydi, lekin bosqich qo'shsangiz raqamlar suriladi
va Dockerfile jimgina buziladi.
AS quruvchi deb nom bergan ma'qul - u o'qishga ham oson.
Kesh bilan birga ishlatish #
Ko'p bosqichli qurish 5-bobdagi qoidani bekor qilmaydi. Ikkalasi birga ishlatiladi:
FROM node:22-alpine AS quruvchi
WORKDIR /ilova
# 1) kam o'zgaradigan
COPY package.json package-lock.json ./
RUN npm ci
# 2) tez-tez o'zgaradigan
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=quruvchi /ilova/dist /usr/share/nginx/html
Kod o'zgarganda npm ci keshdan olinadi, yakuniy obraz esa
har doim toza nginx dan boshlanadi.
Xulosa #
- Qurish uchun kerak bo'lgan vositalar ishlatish uchun kerak emas - ularni yakuniy obrazdan chiqarib tashlang.
- Har bir
FROMyangi bosqich boshlaydi;AS nombilan unga nom beriladi. COPY --from=<bosqich>oldingi bosqichdan faqat kerakli faylni oladi.- Vositachi bosqich yakuniy obrazga umuman kirmaydi va registry ga yuborilmaydi.
- O'lchangan farq: 353 MB → 12.4 MB, qatlamlar 5 → 3.
scratch- "asos yo'q" degani; statik dastur uchun obraz 200 kB ga tushdi.scratchda qobiq ham,lsham yo'q - nosozlik topish qiyinlashadi; oraliq yechim distroless.--targetqurishni belgilangan bosqichda to'xtatadi - CI da test bosqichini alohida ishga tushirish uchun qulay.COPY --fromboshqa obrazdan ham nusxa olishi mumkin.- Nomlangan bosqichni ishlating:
--from=0bosqich qo'shilganda jimgina buziladi.
- Bir bosqichli Dockerfile yozing va obraz hajmini o'lchang.
- Uni ikki bosqichga bo'lib, hajmni yana o'lchang.
- Yakuniy obrazda kompilyator yo'qligini tekshiring.
scratchvariantini yasab, uchala hajmni jadvalga yozing.scratchobrazidashishga tushirib ko'ring va xatoni o'qing.--targetbilan faqat quruvchi bosqichni quring.- Quruvchi bosqichda test ishga tushiradigan bosqich qo'shing.
COPY --from=<obraz>bilan boshqa obrazdan fayl oling.- Bog'liqlik keshini ko'p bosqichli qurish bilan birlashtiring.
- O'z loyihangizni ko'p bosqichli qilib qayta yozing va hajmdagi farqni yozib qo'ying.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.