Qatlamlar va kesh — tez build uchun tartib

~15 daq · Docker · Dockerfile — o'z image ingiz

Muammodan boshlaylik

Dockerfile:

FROM node:22-alpine
WORKDIR /app
COPY . .
RUN npm ci
CMD ["node", "src/index.js"]

src/index.js da bitta vergulni o'zgartirdingiz. docker build — 3 daqiqa: npm ci 800 ta paketni qaytadan yuklayapti. Har bir kichik o'zgarishda. CI serverda har push da.

Xuddi shu natijani 3 soniyada olish mumkin — faqat qatorlar tartibini o'zgartirib.


Har bir instruksiya — qatlam

FROM node:22-alpine          # qatlam 1 (asos image qatlamlari)
WORKDIR /app                 # qatlam 2
COPY package*.json ./        # qatlam 3
RUN npm ci                   # qatlam 4 — 150 MB
COPY . .                     # qatlam 5
CMD ["node", "src/index.js"] # metama'lumot (qatlam emas)

RUN, COPY, ADD — har biri yangi qatlam yaratadi. Qatlam — oldingisiga nisbatan fayl tizimidagi o'zgarishlar.

docker history mening-api
IMAGE          CREATED BY                                      SIZE
9f2c1a...      CMD ["node" "src/index.js"]                     0B
<missing>      COPY . .                                        1.2MB
<missing>      RUN npm ci                                      152MB
<missing>      COPY package*.json ./                           340kB
<missing>      WORKDIR /app                                    0B
<missing>      ... node:22-alpine qatlamlari ...

Kesh qanday ishlaydi

docker build har bir instruksiya uchun so'raydi: "Bu qatlamni oldin yasaganmanmi, va kirishlar o'zgarmaganmi?"

  • Ha → keshdan oladi (CACHED) — bir zumda
  • Yo'q → qaytadan bajaradi, va undan keyingi barcha qatlamlar ham qaytadan
Instruksiya Kesh qachon buziladi
RUN npm ci Buyruq matni o'zgarsa (yoki oldingi qatlam buzilsa)
COPY src/ ./src/ Ko'chirilayotgan fayllardan birortasi o'zgarsa
FROM Asos image yangilangan bo'lsa

Asosiy qoida: bir qatlam buzilsa — undan keyingilarining hammasi qaytadan quriladi.


Muammoli Dockerfile — nima bo'lyapti

COPY . .           # ← index.js o'zgardi → kesh buzildi
RUN npm ci         # ← qaytadan! (3 daqiqa) — garchi package.json o'zgarmagan bo'lsa ham

COPY . . barcha fayllarni ko'chiradi, jumladan src/index.js ni. U o'zgardi → qatlam yangi → keyingi npm ci ham qaytadan.

To'g'ri tartib

FROM node:22-alpine
WORKDIR /app

COPY package.json package-lock.json ./   # 1. Faqat bog'liqliklar ro'yxati
RUN npm ci                               # 2. Bog'liqliklar

COPY . .                                 # 3. Kod — oxirida
CMD ["node", "src/index.js"]

Endi src/index.js o'zgarganda:

 => CACHED [2/5] WORKDIR /app
 => CACHED [3/5] COPY package.json package-lock.json ./
 => CACHED [4/5] RUN npm ci                    ← keshdan!
 => [5/5] COPY . .                             ← faqat shu

3 daqiqa → 3 soniya. npm ci faqat package.json / package-lock.json o'zgarganda — ya'ni yangi paket qo'shilganda qayta bajariladi.

Qoida: kam o'zgaradigan narsalar — tepada, ko'p o'zgaradigan narsalar — pastda.

Asos image          ← deyarli hech qachon
Tizim paketlari     ← kamdan-kam
Bog'liqliklar       ← haftada bir
Ilova kodi          ← har kuni, har soat

Boshqa tillar — xuddi shu naqsh

# Python
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .

# PHP
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-scripts --no-autoloader
COPY . .
RUN composer dump-autoload --optimize

# Go
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o /app/server

RUN larni birlashtirish

# ❌ Uch qatlam; apt keshi image da qoladi
RUN apt-get update
RUN apt-get install -y curl git
RUN rm -rf /var/lib/apt/lists/*

# ✅ Bitta qatlam, kesh tozalangan
RUN apt-get update \
 && apt-get install -y --no-install-recommends curl git \
 && rm -rf /var/lib/apt/lists/*

Nima uchun? Qatlam — o'zgarishlar ro'yxati. Agar fayl bir qatlamda yaratilib, keyingi qatlamda o'chirilsa — u birinchi qatlamda baribir qoladi va image hajmiga kiradi. O'chirish — faqat yaratilgan qatlamning o'zida samarali.

Va yana bir sabab: alohida RUN apt-get update keshlanib qoladi — bir oydan keyin apt-get install eski paket ro'yxati bilan ishlaydi va xato beradi.


BuildKit kesh mount — yanada tez

Paket menejerining o'z keshi (~/.npm, ~/.cache/pip) build lar orasida saqlansin:

# syntax=docker/dockerfile:1
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm npm ci
COPY . .

package.json o'zgarganda ham npm ci paketlarni internetdan emas, keshdan oladi. Kesh image ga kirmaydi — faqat build mashinasida.


Keshni chetlab o'tish

docker build --no-cache -t ilova .           # hammasini noldan
docker build --pull -t ilova .               # asos image ning eng yangisini tortib olish

Xavfsizlik yangilanishlari uchun vaqti-vaqti bilan --pull --no-cache — aks holda asos image va tizim paketlari keshlangan eski versiyada qoladi.


Nima uchun shunday?

Nima uchun bitta qatlam o'zgarsa, keyingilarining hammasi qaytadan quriladi — faqat o'zgarganini qayta qurish mumkin emasmi?

Chunki har bir qatlam oldingisi ustiga quriladi va undan bog'liq bo'lishi mumkin. RUN npm ci — COPY package.json natijasiga bog'liq; RUN npm run build — COPY . . ga. Docker buyruq ichida nima bo'layotganini bilmaydi — u RUN ning qaysi fayllarni o'qishini tahlil qila olmaydi. Shuning uchun yagona xavfsiz qoida: oldingi qatlam o'zgardi — keyingilari eskirgan bo'lishi mumkin. Bu qoidani bilsangiz — tartib orqali uni o'zingiz foydangizga ishlatasiz.


Xulosa

Eslab qoling:

  • RUN, COPY, ADD — har biri qatlam; docker history — ularni ko'rish
  • Kesh: kirish o'zgarmasa — CACHED; bitta qatlam buzilsa — keyingilari ham
  • Kam o'zgaradigan — tepada, ko'p o'zgaradigan — pastda
  • Avval package.json / requirements.txt → o'rnatish → keyin kod
  • Bog'liq RUN larni && bilan birlashtiring, kesh/vaqtinchalik fayllarni o'sha qatlamda tozalang
  • RUN --mount=type=cache — paket menejeri keshi
  • --no-cache --pull — vaqti-vaqti bilan xavfsizlik uchun

Keyingi dars

15-dars: .dockerignore — keraksiz fayllarni chiqarib tashlash