Blogga qaytish
5 daqiqa o'qish

Docker multi-stage build: image hajmini 40 barobar kichraytiramiz

Go ilovangizning Docker image'i 900 MB'mi? Multi-stage build yordamida uni 20 MB atrofiga tushirish, xavfsizlikni oshirish va deployni tezlashtirish bo'yicha amaliy misollar.

GoPythonDocker
Docker multi-stage build: image hajmini 40 barobar kichraytiramiz

Muammo

Ko'pchilik Dockerfile'ni shunday yozadi:

FROM golang:1.23
WORKDIR /app
COPY . .
RUN go build -o server .
CMD ["./server"]

Bu ishlaydi. Lekin yakuniy image ichida butun Go kompilyatori, kesh, manba kod va keraksiz utilitalar qoladi. Hajm osongina 900 MB dan oshib ketadi. Bu quyidagilarga olib keladi:

  • Sekin deploy: har safar yuzlab megabayt registry'ga yuklanadi va serverga tortiladi.
  • Katta hujum yuzasi: image'dagi har bir ortiqcha paket potensial zaiflik.
  • Ortiqcha xarajat: disk, trafik va CI vaqti behuda ketadi.

Yechim: multi-stage build

G'oya oddiy: bitta bosqichda ilovani quramiz, boshqasida faqat tayyor binarni ishga tushiramiz.

# 1-bosqich: build
FROM golang:1.23 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o server .

# 2-bosqich: runtime
FROM gcr.io/distroless/static-debian12
COPY --from=builder /app/server /server
USER nonroot:nonroot
ENTRYPOINT ["/server"]

Natija: image hajmi taxminan 15–25 MB.

Nimalar o'zgardi?

  1. AS builder: birinchi bosqichga nom beramiz, keyin undan fayl olamiz.
  2. go.mod alohida nusxalanadi: bog'liqliklar kodga qaraganda kamroq o'zgaradi, shuning uchun Docker bu qatlamni keshlaydi va build tezlashadi.
  3. CGO_ENABLED=0: statik binar hosil bo'ladi, tashqi C kutubxonalariga bog'liq emas.
  4. -ldflags="-s -w": debug ma'lumotlari olib tashlanadi, binar kichrayadi.
  5. distroless: ichida shell ham, paket menejeri ham yo'q. Faqat sizning ilovangiz.
  6. USER nonroot: konteyner root huquqisiz ishlaydi.

Eslatma: distroless'da shell yo'q, shuning uchun docker exec -it ... sh ishlamaydi. Debug kerak bo'lsa, static-debian12:debug variantidan foydalaning.

Python uchun ham ishlaydimi?

Ha. Builder bosqichida wheel'larni yig'ib, runtime uchun slim image olamiz:

FROM python:3.12 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt

FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /wheels /wheels
RUN pip install --no-cache-dir /wheels/* && rm -rf /wheels
COPY . .
CMD ["python", "main.py"]

Bu yerda yutuq Go'dagidek katta emas. Lekin kompilyatorlar va build vositalari yakuniy image'ga tushmaydi, bu esa hajm va xavfsizlik uchun foydali.

Xulosa

Multi-stage build eng oson optimizatsiyalardan biri: Dockerfile'ga 5 daqiqa vaqt sarflaysiz, har bir deployda esa vaqt va xavfsizlik yutasiz. Agar loyihangizda hali bitta FROM bo'lsa, bugun sinab ko'ring va docker images natijasini solishtiring.