WisarWisar
Dasturlash kitobi/10-QISM — DevOps37 daqiqa

10.3-bob: Docker — image, container, Dockerfile

10-QISM — DevOps va Deploy · 3-mavzu


1. Kirish va motivatsiya

10.1da bo'sh serverni xavfsiz sozladik, 10.2da Nginx bilan so'rovlarni boshqardik. Lekin bir muammo hali ham bor — eng mashhur dasturchi iborasi: "mening kompyuterimda ishlayapti" (it works on my machine). Dasturchi ilovani lokal kompyuterida yozadi: Node.js 22, ma'lum kutubxona versiyalari, ma'lum operatsion tizim. Keyin uni serverga chiqaradi — u yerda Node.js 18, boshqa kutubxona versiyalari, boshqa Linux distributivi. Va ilova ishlamaydi. Sabab — muhit farqi (environment difference): qaramliklar (dependency), tizim kutubxonalari, OS sozlamalari lokal kompyuter bilan serverda har xil. Junior dasturchi soatlab "nega serverda ishlamadi?" deb azoblanadi; senior esa bu muammoni butunlay yo'q qiladiDocker bilan.

Docker — ilovani va uning barcha qaramliklarini (Node.js versiyasi, kutubxonalar, OS fayllari, sozlamalar) bitta standart paketga (image) joylaydigan platforma. Bu paket har qanday Docker o'rnatilgan mashinada — dasturchining laptopida, hamkasbning kompyuterida, AWS serverida, CI/CD muhitida — aynan bir xil ishlaydi. "Mening kompyuterimda ishlayapti" o'rniga endi "konteynerda ishlayapti — demak hamma joyda ishlaydi". Docker 2013-yilda chiqqan va bugun deyarli har bir zamonaviy backend Docker'da ishlaydi — bu majburiy ko'nikma.

Bu bob: konteyner vs virtual mashina (nega yengil — 2.1), image vs container (klass va obyekt analogiyasi — 2.2), layer va caching (nega tartib muhim — 2.3), Docker arxitektura (daemon, client, registry — 2.4), Dockerfile direktivalari (FROM, COPY, RUN, CMD... — 2.5), CMD vs ENTRYPOINT 2.6-bob, volume vs bind mount (ma'lumot saqlash — 2.7), port mapping va networking 2.8-bob, .dockerignore 2.9-bob, image hajmini kichraytirish (alpine — 2.10), xavfsizlik (non-root user — 2.11), registry va versiyalash (tag, digest, push/pull — 2.12), BuildKit va image skanerlash (secret, trivy — 2.13). Bu — 10.4 (Compose), 10.5 (CI/CD), 10.6 (AWS) va butun zamonaviy deploy uchun poydevor.

O'xshatish: Docker konteyneri — standart yuk konteyneri (kemadagi temir quti). Bu g'oya transport olamini o'zgartirgan: ilgari har xil yuk (banan, mashina, mebel) har xil tarzda yuklanardi — uzoq, qimmat, nostandart. Standart konteyner kashf etilgach — ichida nima borligi muhim emas bo'lib qoldi: har bir kran, kema, poyezd, yuk mashina bir xil quti bilan ishlaydi. Docker ham xuddi shunday: ichida Node.js ilovasi, Python skripti yoki PostgreSQL bormi — Docker uchun farqi yo'q, hammasi bir xil docker run bilan ishga tushadi. Ilovani "qutiga" (image) joylaysiz, va u har qanday "kran-kema" (Docker xost) da bir xil ishlaydi. Image — qutining chizmasi/qolipi; container — o'sha chizma bo'yicha yasalgan ishlayotgan quti; registry (Docker Hub) — qutilar saqlanadigan ombor/port.

Nega muhim?

  • "Ishlayapti" muammosini yo'q qiladi — lokal = server = CI (bir xil muhit, kafolatlangan).
  • Deploy oson — bitta image, har joyda ishlaydi (10.4, 10.5, 10.6).
  • Izolyatsiya — har ilova alohida konteyner (bir-biriga xalal bermaydi).
  • Intervyu/ish — 2026da deyarli har backend e'lonida "Docker" talab qilinadi.

2. Nazariya — chuqur tushuntirish

2.1. Konteyner vs virtual mashina (nega yengil)

text
  VIRTUAL MASHINA (VM) — har biri TO'LIQ OS (og'ir):
  ┌─────────┐ ┌─────────┐ ┌─────────┐
  │ Ilova A │ │ Ilova B │ │ Ilova C │
  ├─────────┤ ├─────────┤ ├─────────┤
  │ Guest OS│ │ Guest OS│ │ Guest OS│   har birida TO'LIQ OS (GB'lar)
  ├─────────┴─┴─────────┴─┴─────────┤
  │         HYPERVISOR              │   VMware/VirtualBox
  ├────────────────────────────────┤
  │         XOST OS                 │
  └────────────────────────────────┘

  KONTEYNER — yadroni ULASHADI (yengil):
  ┌─────────┐ ┌─────────┐ ┌─────────┐
  │ Ilova A │ │ Ilova B │ │ Ilova C │   faqat ilova + qaramligi (MB'lar)
  ├─────────┴─┴─────────┴─┴─────────┤
  │      DOCKER ENGINE             │   konteynerlarni boshqaradi
  ├────────────────────────────────┤
  │      XOST OS (Linux yadro)     │   BITTA yadro — barchaga ULASHILADI
  └────────────────────────────────┘

  VM: sekundlar-daqiqada ko'tariladi, GB joy    og'ir
  Konteyner: millisekundda, MB joy              yengil

Konteyner vs VM — eng asosiy farq. Virtual mashina har biri uchun to'liq operatsion tizim (guest OS — yadro, drayverlar, hamma narsa) ishlatadi og'ir (GB'lab joy, sekundlar-daqiqada ko'tariladi). Konteyner esa xostning Linux yadrosini ulashadi (share) — alohida OS o'rnatmaydi, faqat ilova va uning qaramliklarini saqlaydi yengil (MB'lar, millisekundda ko'tariladi). Sirini bilib qo'yish kerak: konteyner — bu izolyatsiya qilingan jarayon (process), virtuallashtirilgan kompyuter emas. Linux yadrosining namespaces (izolyatsiya — har konteyner o'z fayl tizimi/tarmog'ini ko'radi) va cgroups (resurs cheklash — CPU/RAM) imkoniyatlaridan foydalanadi. Shuning uchun bitta serverda o'nlab konteyner ishlaydi, lekin faqat bir nechta VM. Ko'pincha ular birga ishlaydi: bulutdagi VM ichida o'nlab konteyner.

2.2. Image vs container (klass vs obyekt)

text
  IMAGE — o'zgarmas QOLIP (read-only shablon):
  - Ilova + qaramliklar + OS fayllari + sozlamalar (hammasi ichida)
  - Dockerfile'dan "build" qilinadi
  - Registry'da saqlanadi (Docker Hub)
  - O'zgarmas (immutable) — bir marta yasalsa, o'zgarmaydi

  CONTAINER — image'dan ISHGA TUSHIRILGAN nusxa (running instance):
  - "docker run <image>"  konteyner
  - Bir image'dan KO'P konteyner (har biri alohida)
  - O'zgaruvchan (yozish mumkin — lekin o'chsa yo'qoladi)

  ┌────────────────────────────────────────────┐
  │  KLASS (OOP — 2.10)  IMAGE               │
  │  class User {...}        node:22-alpine    │
  │                                            │
  │  OBYEKT (instance)   CONTAINER           │
  │  new User()              docker run        │
  │  new User()   ko'p      docker run   ko'p│
  └────────────────────────────────────────────┘

Image vs container — eng ko'p chalkashtiriladigan tushuncha, lekin OOP 2.10-bob bilan oson: image — bu klass (qolip, shablon — o'zgarmas), container — bu obyekt (o'sha klassdan yasalgan ishlayotgan nusxa). class User {} dan new User() bilan ko'p obyekt yaratgandek, bitta imagedan docker run bilan ko'p container ko'tarasiz — har biri alohida, bir-biridan mustaqil. Image — o'zgarmas (immutable): Dockerfile'dan build qilinadi, registry'da saqlanadi, ichida ilova + barcha qaramliklar bor. Container — image'ning ishlab turgan nusxasi: o'zgaruvchan (ichiga yozish mumkin), lekin konteyner o'chirilsa, ichidagi o'zgarishlar yo'qoladi (shuning uchun muhim ma'lumot volume'da saqlanadi — 2.7). Bu farq Docker'ni tushunishning kalitidir.

2.3. Layer va build cache (nega tartib muhim)

text
  IMAGE — QATLAMLARDAN (layer) iborat (har direktiva = layer):

  Dockerfile:                          Layerlar (ustma-ust):
  FROM node:22-alpine        ────────► [Layer 0: bazaviy OS + Node]
  WORKDIR /app               ────────► [Layer 1: papka]
  COPY package*.json ./      ────────► [Layer 2: package fayllar]
  RUN npm ci                 ────────► [Layer 3: node_modules]
  COPY . .                   ────────► [Layer 4: ilova kodi]
  CMD ["node","main.js"]     ────────► [metadata]

  BUILD CACHE — o'zgarmagan layer QAYTA ISHLATILADI (tez):
  - Docker har layer'ni xotirada saqlaydi (cache)
  - Layer o'zgarmasa  cache'dan oladi (qayta bajarmaydi — TEZ)
  - Bir layer o'zgarsa  o'sha va undan KEYINGI hammasi qayta quriladi

   TARTIB MUHIM: kam o'zgaradigani YUQORIDA, ko'p o'zgaradigani PASTDA
   package.json (kam o'zgaradi) AVVAL  npm ci cache'da qoladi
   kod (ko'p o'zgaradi) KEYIN  faqat shu qayta quriladi (npm qayta emas)

Layer (qatlam) — Docker'ning ichki mexanizmi: image bir necha qatlamdan iborat va Dockerfile'dagi har bir direktiva (FROM, COPY, RUN...) yangi qatlam yaratadi. Qatlamlar ustma-ust joylashadi. Eng muhim tushuncha — build cache: Docker har qatlamni saqlab qoladi va keyingi build'da o'zgarmagan qatlamni qayta ishlatadi (cache'dan oladi — juda tez). Lekin bir qatlam o'zgarsa, o'sha qatlam va undan keyingi hamma qatlam qaytadan quriladi. Shundan kelib chiqadi eng muhim qoida: kam o'zgaradigan narsalarni yuqorida, ko'p o'zgaradigan narsalarni pastda joylashtir. Aynan shuning uchun COPY package*.json va RUN npm ci ni kod nusxasidan (COPY . .) oldin yozamiz: kod har o'zgarganda npm ci qayta ishlamasin (qaramliklar kam o'zgaradi). Bu — Misol 1 va Xato 4ning asosi.

2.4. Docker arxitektura (daemon, client, registry)

text
  DOCKER — client-server arxitektura (3 qism):

  ┌──────────────┐   buyruq    ┌────────────────────────┐
  │ DOCKER CLIENT│ ──────────► │  DOCKER DAEMON (engine) │
  │ "docker ..." │  (REST API) │  - image'larni quradi   │
  │ (terminal)   │ ◄────────── │  - konteyner ishga tush │
  └──────────────┘   javob     │  - tarmoq, volume       │
                               └───────────┬────────────┘
                                           │ pull/push
                                           ▼
                               ┌────────────────────────┐
                               │  REGISTRY (Docker Hub)  │
                               │  - image'lar ombori     │
                               │  - node, postgres,nginx │
                               │  - o'z image'laring ham │
                               └────────────────────────┘

   "docker run nginx"  daemon Hub'dan "nginx" image'ni PULL qiladi
     (lokal'da yo'q bo'lsa), keyin konteyner sifatida ishga tushiradi

Docker arxitekturasi — uch qismdan iborat client-server tizim: Docker client (docker buyrug'ini yozadigan terminal — siz bilan ishlaydi), Docker daemon (dockerd — asosiy "ishchi": image'larni quradi, konteynerlarni ishga tushiradi, tarmoq/volume boshqaradi — fonda ishlaydi), va registry (image'lar ombori). Client daemon'ga REST API orqali buyruq beradi. Eng mashhur registry — Docker Hub (hub.docker.com): u yerda rasmiy image'lar bor (node, postgres, nginx, redis...) hamda har kim o'z image'larini joylashi mumkin. docker run nginx deganingda daemon avval lokalda nginx image bor-yo'qligini tekshiradi; bo'lmasa Hub'dan pull (yuklab oladi) qiladi, keyin konteyner sifatida ishga tushiradi. O'z image'ingni docker push bilan Hub'ga yuborasiz (10.5da CI/CD shuni avtomatlashtiradi).

2.5. Dockerfile direktivalari

text
  DOCKERFILE — image qurish RETSEPTI (matn fayl, har qatori direktiva):

  FROM <image>:<tag>     bazaviy image (har Dockerfile shu bilan boshlanadi)
  WORKDIR /app           ishchi papka (keyingi buyruqlar shu yerda)
  COPY <src> <dest>      fayl ko'chirish (xostdan image'ga)
  ADD <src> <dest>       COPY + URL/tar (oddiy holatda COPY ishlat)
  RUN <buyruq>           BUILD paytida buyruq bajarish (npm ci, apt install)
  ENV KEY=value          muhit o'zgaruvchisi (image'da qoladi)
  ARG KEY=value          build paytidagi o'zgaruvchi (image'da QOLMAYDI)
  EXPOSE 3000            qaysi portni ishlatishini HUJJATLASH (faqat info)
  USER node              qaysi foydalanuvchi sifatida ishlash (non-root)
  VOLUME ["/data"]       tashqi saqlash nuqtasi
  HEALTHCHECK ...        konteyner sog'ligini tekshirish
  CMD ["node","main"]    konteyner ISHGA TUSHGANDA bajariladigan buyruq
  ENTRYPOINT [...]       asosiy bajariluvchi (CMD bilan birga — 2.6)

   FROM (build) vs CMD (run): RUN — qurish paytida; CMD — ishga tushganda

Dockerfile — image qurish uchun retsept (matn fayl): har bir qatori bir direktiva (instruction). Asosiylari: FROM — bazaviy image (har Dockerfile shundan boshlanadi, masalan node:22-alpine); WORKDIR — ishchi papka (keyingi buyruqlar shu yerda bajariladi, cd o'rniga); COPY — xostdagi fayllarni image'ga ko'chiradi (ADD — COPY + URL/tar extract, lekin oddiy holatda COPY tavsiya etiladi); RUNbuild paytida buyruq bajaradi (npm ci, apt install — natija layer'ga yoziladi); ENV — muhit o'zgaruvchisi (image'da qoladi); ARG — build paytidagi o'zgaruvchi (image'da qolmaydi); EXPOSE — qaysi portni ishlatishini hujjatlash (faqat axborot, port ochmaydi — buni -p qiladi, 2.8); USER — qaysi foydalanuvchi sifatida ishlash 2.11-bob; CMD/ENTRYPOINT — konteyner ishga tushganda bajariladigan asosiy buyruq 2.6-bob. Asosiy farqni yodda tutish kerak: RUN — image qurish paytida (build), CMD — konteyner ishga tushganda (run).

Yana bir necha muhim direktiva bor. LABEL — image'ga metadata yozadi (kalit=qiymat), masalan muallif, versiya, manba: LABEL org.opencontainers.image.source="https://github.com/user/app" (bu standart yorliq registry'da manbani ko'rsatadi, GHCR uni avtomatik bog'laydi). VOLUME ["/data"] — Dockerfile ichida saqlash nuqtasini e'lon qiladi (o'sha papkaga yozilgan ma'lumot uchun Docker anonim volume yaratadi); lekin ko'pincha volume'ni Dockerfile'da emas, docker run -v 2.7-bob bilan aniq boshqarish afzal, chunki anonim volume'lar to'planib disk to'ldiradi. ONBUILD <direktiva> — bu image'ni boshqa Dockerfile FROM sifatida ishlatganda avtomatik ishlaydigan buyruqni "kechiktiradi" (bazaviy image mualliflari uchun ilg'or vosita — kundalik ilova Dockerfile'ida deyarli kerak emas).

COPY vs ADD — chuqurroq: ikkalasi ham fayl ko'chiradi, lekin ADD qo'shimcha ikki "sehr"ga ega — (1) URL'dan yuklab olish, (2) lokal .tar arxivni avtomatik ochish (extract). Aynan shu "sehr" xatoga sabab bo'ladi (kutilmagan extract, tekshirilmagan URL), shuning uchun rasmiy tavsiya: oddiy fayl ko'chirishda doim COPY, ADD faqat mahalliy tar-arxivni ochish kerak bo'lganda. ARG va FROM tartibi — bir nozik jihat: FROMdan oldin e'lon qilingan ARG (masalan ARG NODE_VERSION=22 keyin FROM node:${NODE_VERSION}-alpine) faqat FROM qatorida ko'rinadi; agar u qiymat FROMdan keyin ham kerak bo'lsa, FROMdan so'ng ARG NODE_VERSIONni qayta e'lon qilish shart. Bu bilan bazaviy versiyani build vaqtida (--build-arg) almashtirsa bo'ladigan moslashuvchan Dockerfile chiqadi.

2.6. CMD vs ENTRYPOINT (eng chalkash farq)

text
  HAR IKKISI — konteyner ishga tushganda nima bajarilishini belgilaydi,
  lekin XULQI har xil:

  CMD — STANDART buyruq (run paytida OSON o'zgartiriladi):
  CMD ["node", "main.js"]
   docker run myapp               "node main.js" bajariladi
   docker run myapp npm test      "npm test" bajariladi (CMD ALMASHADI)

  ENTRYPOINT — ASOSIY bajaruvchi (oson o'zgarmaydi):
  ENTRYPOINT ["node", "main.js"]
   docker run myapp arg1          "node main.js arg1" (arg QO'SHILADI)

  IKKALASI BIRGA (eng kuchli — ENTRYPOINT = buyruq, CMD = default arg):
  ENTRYPOINT ["node", "main.js"]
  CMD ["--port=3000"]
   docker run myapp               "node main.js --port=3000"
   docker run myapp --port=8080   "node main.js --port=8080" (CMD almashdi)

   Ikki SHAKL: exec ["node","main"] (TAVSIYA — signal to'g'ri) vs
                shell "node main" (/bin/sh -c orqali — signal muammosi)

CMD vs ENTRYPOINT — Docker'ning eng chalkash farqi. Ikkalasi ham konteyner ishga tushganda nima bajarilishini belgilaydi, lekin xulqi har xil: CMDstandart buyruq, docker run myapp <yangi buyruq> bilan oson almashtiriladi (masalan docker run myapp npm test CMD o'rniga npm test ishlaydi). ENTRYPOINTasosiy bajaruvchi, oson o'zgarmaydi: docker run myapp arg1 deganda argument ENTRYPOINT'ga qo'shiladi, almashtirmaydi. Eng kuchli usul — ikkalasini birga: ENTRYPOINT = asosiy buyruq, CMD = standart argumentlar (run paytida o'zgartirsa bo'ladi). Ko'p Node.js ilovasida oddiy CMD ["node", "dist/main.js"] yetadi. Yana muhim narsa — ikki shakl: exec shakl (["node", "main.js"] — JSON massiv, tavsiyanode to'g'ridan-to'g'ri ishlaydi, signal (SIGTERM) ilovaga yetadi toza to'xtaydi) va shell shakl (node main.js/bin/sh -c orqali, signal shga boradi, ilovaga yetmaydi muammo). Doim exec shakldan foydalanish tavsiya etiladi.

2.7. Volume vs bind mount (ma'lumot saqlash)

text
  MUAMMO: konteyner O'CHSA — ichidagi yozilgan ma'lumot YO'QOLADI
   DB ma'lumoti, yuklangan fayllar konteyner ichida saqlansa — xavfli

  YECHIM: ma'lumotni konteynerdan TASHQARIDA saqlash (2 usul):

  ┌──────────────────────────────────────────────────────────┐
  │  VOLUME — Docker BOSHQARADIGAN saqlash (production):      │
  │  docker run -v mydata:/var/lib/postgresql/data postgres  │
  │  - Docker o'zi joylashtiradi (/var/lib/docker/volumes)   │
  │  - Konteyner o'chsa ham QOLADI; ko'chirish/backup oson   │
  │  - DB, doimiy ma'lumot uchun                            │
  ├──────────────────────────────────────────────────────────┤
  │  BIND MOUNT — XOST papkasini ulash (development):        │
  │  docker run -v $(pwd):/app node                          │
  │  - Aniq xost papkasi konteynerga ulanadi                │
  │  - Xostda o'zgartirsang — konteynerda DARROV ko'rinadi  │
  │  - Dev (hot-reload), konfiguratsiya fayl uchun         │
  └──────────────────────────────────────────────────────────┘

Volume vs bind mount — ma'lumot saqlashning ikki usuli. Muammo: konteyner o'chirilsa, ichiga yozilgan ma'lumot yo'qoladi 2.2-bob — DB ma'lumoti yoki yuklangan fayllar konteyner ichida qolmasligi kerak. Yechim — ma'lumotni konteynerdan tashqarida saqlash: volume (Docker boshqaradigan saqlash — docker run -v mydata:/path) — Docker o'zi /var/lib/docker/volumesda joylashtiradi, konteyner o'chsa ham qoladi, ko'chirish/backup oson, production DB uchun ideal. Bind mount — aniq xost papkasini konteynerga ulash (docker run -v $(pwd):/app) — xostda faylni o'zgartirsangiz konteynerda darrov ko'rinadi, shuning uchun development (hot-reload, kodni ko'rib turish) va konfiguratsiya fayllar uchun ideal. Yodda tutish kerak: volume — production ma'lumoti (DB), bind mount — dev (kod, config). --mount type=volume,src=...,dst=... — yangi, aniqroq sintaksis, lekin -v hali keng tarqalgan.

2.8. Port mapping va networking

text
  KONTEYNER — IZOLYATSIYA qilingan (ichidagi port tashqaridan KO'RINMAYDI):
   ilova konteyner ichida 3000-portda ishlaydi, lekin xostdan kira olmaysan

  PORT MAPPING (-p) — xost portini konteyner portiga BOG'LASH:

  docker run -p 8080:3000 myapp
                │     │
                │     └─ KONTEYNER porti (ilova ichida eshitadi)
                └─ XOST porti (tashqaridan kiriladigan)

   xost:8080 ga so'rov  konteyner:3000 ga uzatiladi
   brauzerda http://localhost:8080  ilova javob beradi

  NETWORKING (konteynerlar BIR-BIRI bilan gaplashadi):
  docker network create mynet             maxsus tarmoq
  docker run --network mynet --name db postgres
  docker run --network mynet --name api myapp
   "api" konteyneri "db" ni NOMI bilan topadi (DNS): host=db, port=5432

   EXPOSE faqat hujjatlash; haqiqiy ochish — "-p" (port mapping)

Port mapping — konteyner izolyatsiya qilingani uchun, ichidagi port tashqaridan ko'rinmaydi: ilova konteyner ichida 3000-portda eshitsa ham, xostdan to'g'ridan-to'g'ri kira olmaysiz. -p <xost>:<konteyner> flagi xost portini konteyner portiga bog'laydi: docker run -p 8080:3000 myapp xostning 8080-portiga kelgan so'rov konteynerning 3000-portiga uzatiladi (brauzerda http://localhost:8080). Tartibni yodda tutish kerak: -p XOST:KONTEYNER (chapda tashqi, o'ngda ichki). Networking — konteynerlar bir-biri bilan gaplashishi: maxsus tarmoq yaratasiz (docker network create mynet), unga konteynerlarni qo'shasiz, va ular bir-birini nomi bilan topadi (Docker ichki DNS) — masalan api konteyneri db konteynerini host=db deb ulaydi (IP kerak emas). 10.4da Docker Compose buni avtomatik qiladi. EXPOSE esa faqat hujjatlash (qaysi portni ishlatadi — info), haqiqiy ochish -p orqali.

Tarmoq rejimlari (network driver) — Docker bir necha rejimni qo'llab-quvvatlaydi. bridge (standart) — har konteyner o'z virtual tarmoq interfeysini oladi, Docker ichki NAT/DNS orqali ularni bog'laydi; tashqariga chiqish -p port mapping bilan. Yuqoridagi docker network create bilan yaratilgani ham bridge (foydalanuvchi belgilagan bridge — DNS bilan nom orqali topishni yoqadi; standart bridge esa faqat IP bilan). host — konteyner xostning tarmog'ini to'g'ridan-to'g'ri ishlatadi (izolyatsiya yo'q, port mapping shart emas — konteyner porti = xost porti); tezlik muhim va izolyatsiya kerak bo'lmagan holatlarda, faqat Linux'da. none — konteyner umuman tarmoqsiz (faqat loopback); tashqi aloqaga muhtoj bo'lmagan, izolyatsiya maksimal kerak vazifalar uchun. Boshqa rejimlar (overlay — bir necha xost bo'ylab, Swarm/Kubernetes uchun; macvlan) ilg'or holatlarga tegishli. tmpfs — bu tarmoq emas, saqlash rejimi: docker run --tmpfs /tmp bilan faqat RAM'da yashaydigan vaqtinchalik papka beriladi (konteyner o'chsa yo'qoladi, diskka yozilmaydi — maxfiy vaqtinchalik ma'lumot yoki tezkor keshni diskdan uzoq tutish uchun).

2.9. .dockerignore (kontekstni tozalash)

text
  BUILD KONTEKST — "docker build ." dagi "." (papka daemon'ga YUBORILADI):
   COPY . . qilsang — butun papka image'ga ko'chiriladi

  MUAMMO (.dockerignore'siz):
   node_modules/ ko'chiriladi (KATTA — lekin RUN npm ci qayta quradi!)
   .git/ ko'chiriladi (tarix — keraksiz, katta)
   .env ko'chiriladi (MAXFIY kalitlar — image'ga tushadi — XAVFLI!)

  YECHIM: .dockerignore (Dockerfile yonida — .gitignore'ga o'xshash):
  node_modules         konteynerda RUN npm ci o'zi quradi
  .git                 kerak emas
  .env                 MAXFIY (image'ga tushmasin)
  dist                 build natijasi (konteyner ichida quriladi)
  Dockerfile           o'zini ko'chirish shart emas
  *.log                loglar

   Natija: kichik image + tez build + maxfiy ma'lumot xavfsiz

.dockerignoredocker build . da . (nuqta) build kontekst deyiladi: o'sha papka butunlay daemon'ga yuboriladi va COPY . . qilganda image'ga ko'chiriladi. Muammo: agar boshqarmasangiz, node_modules (katta — lekin baribir RUN npm ci qayta quradi), .git (tarix), va eng xavflisi .env (maxfiy kalitlar — image'ga tushib ketadi) ham ko'chiriladi. Yechim — Dockerfile yonida .dockerignore fayli (xuddi .gitignore kabi): unga node_modules, .git, .env, dist, *.log ni yozasiz. Natija uch tomonlama foyda: kichikroq image (keraksiz fayllar yo'q), tezroq build (kontekst kichik), va xavfsizlik (maxfiy .env image'ga tushmaydi — bu eng muhimi). Har bir Docker loyihasida .dockerignore majburiy.

2.10. Image hajmini kichraytirish (alpine)

text
  IMAGE HAJMI MUHIM: katta image — sekin pull/push, ko'p joy, ko'p xavf

  BAZAVIY IMAGE TANLASH (eng katta ta'sir):
  node:22           ~1.1 GB (to'liq Debian — ko'p keraksiz narsa)
  node:22-slim      ~250 MB (minimal Debian)
  node:22-alpine    ~150 MB (Alpine Linux — ENG KICHIK) 

  ALPINE — juda kichik Linux (~6 MB asos, apk paket menejeri — 10.1: 2.5):

  BOSHQA USULLAR:
   .dockerignore (keraksiz fayl yo'q — 2.9)
   RUN'larni birlashtir (kam layer — 2.3, quyida)
   npm ci --omit=dev (faqat production qaramlik)
   MULTI-STAGE BUILD — build vositalarini tashlab, faqat natija
    (TO'LIQ 10.4da — ishora: build stage + production stage)

   Kichik image = tez deploy + kam xavf (attack surface kichik)

Image hajmini kichraytirish — production uchun muhim (katta image sekin pull/push qilinadi, ko'p joy egallaydi, xavf yuzasi katta). Eng katta ta'sir — bazaviy image tanlash: node:22 (1.1 GB — to'liq Debian, ko'p keraksiz narsa), node:22-slim (250 MB — minimal Debian), va eng yaxshisi node:22-alpine (~150 MB — Alpine Linux asosida, ~6 MB minimal Linux, apk paket menejeri — 10.1: 2.5). Boshqa usullar: .dockerignore 2.9-bob, RUN buyruqlarini birlashtirish (kam layer — 2.3), npm ci --omit=dev (faqat production qaramliklar). Eng kuchli usul — multi-stage build: bir bosqichda build qilasiz (TypeScript kompilyatsiya, build vositalari), keyingi bosqichga faqat natijani ko'chirasiz (build vositalari tashlanadi) — natijada juda kichik image. Bu mavzuga to'liq 10.4da kiramiz; hozircha shuni bilish yetarli — multi-stage = eng kichik production image. Kichik image = tez deploy + kam xavf.

2.11. Xavfsizlik (non-root user)

text
  STANDART: konteyner ROOT sifatida ishlaydi (xavfli — 10.1: 2.4):
   konteyner buzilsa, hujumchi root huquqi oladi (xost'ga ham xavf)

  YECHIM: NON-ROOT foydalanuvchi sifatida ishlash (least privilege):

  # node image'da tayyor "node" useri bor (UID 1000):
  FROM node:22-alpine
  WORKDIR /app
  COPY --chown=node:node . .        fayl egasi "node" (root emas)
  RUN npm ci --omit=dev
  USER node                         shu yerdan keyin "node" sifatida ishlaydi
  CMD ["node", "dist/main.js"]

  YANA (xavfsizlik):
   Aniq versiya (node:22-alpine, "latest" EMAS — bashorat qilinadigan)
   Faqat kerakli paket (kam attack surface)
   .env image'ga tushmasin (.dockerignore — 2.9; runtime'da -e/--env-file)
   Image'larni skanerlash (docker scout — zaifliklar)

   Eng kam imtiyoz (10.1: 2.4) — konteynerda ham amal qiladi

Xavfsizlik — non-root user. Standart holatda konteyner root sifatida ishlaydi, bu xavfli (10.1: 2.4 — eng kam imtiyoz): agar ilova buzilsa, hujumchi konteyner ichida root huquqi oladi va potensial xostga ham xavf soladi. Yechimnon-root foydalanuvchi sifatida ishlash. Rasmiy node image'da tayyor node useri bor (UID 1000): Dockerfile'da USER node direktivasidan keyin barcha buyruqlar shu foydalanuvchi sifatida ishlaydi (COPY --chown=node:node bilan fayl egasini ham to'g'rilaysiz). Boshqa xavfsizlik qoidalari: aniq versiya ishlatish kerak (node:22-alpinelatest emas, chunki latest bashorat qilib bo'lmaydigan, bugun va ertaga har xil bo'lishi mumkin); faqat kerakli paketlar (kam attack surface); .envni image'ga qo'shmaslik kerak (.dockerignore — 2.9, o'rniga runtime'da -e/--env-file); image'larni docker scout bilan zaifliklarga skanerlash lozim. Eng kam imtiyoz tamoyili konteynerda ham amal qiladi.

2.12. Registry, tag va versiyalash (image'larni tarqatish)

text
  IMAGE NOMI TO'LIQ SHAKLDA:
  ghcr.io / myuser / api : 1.4.2
   │         │        │     │
   │         │        │     └─ TAG (versiya yorlig'i — o'zgaruvchan ko'rsatkich)
   │         │        └─ REPOSITORY (image nomi)
   │         └─ NAMESPACE (foydalanuvchi/tashkilot)
   └─ REGISTRY (yo'q bo'lsa — Docker Hub; boshqasi aniq yoziladi)

  PUSH/PULL OQIMI:
  docker login ghcr.io                  autentifikatsiya (token)
  docker build -t ghcr.io/myuser/api:1.4.2 .
  docker push ghcr.io/myuser/api:1.4.2    registry'ga yuklash
  docker pull ghcr.io/myuser/api:1.4.2    boshqa mashinada olish

  TAG — O'ZGARUVCHAN KO'RSATKICH (git branch'ga o'xshaydi):
  :1.4.2    aniq versiya (o'zgarmas — bir marta chiqarilsa qotadi) 
  :1.4      oxirgi 1.4.x
  :1        oxirgi 1.x
  :latest   "oxirgi push qilingan" (BASHORATSIZ — anti-pattern) 

  DIGEST — O'ZGARMAS KRIPTO-BARMOQ IZI (eng qat'iy):
  api@sha256:9f2c...    aynan SHU baytlar (tag o'zgarsa ham qotib qoladi)

Registry va tag — image'ni tarqatish mexanizmi. Image to'liq nomi bir necha qismdan iborat: registry/namespace/repository:tag (masalan ghcr.io/myuser/api:1.4.2). Registry ko'rsatilmasa, Docker uni Docker Hubdan izlaydi; GHCR (ghcr.io — GitHub Container Registry) va bulut registrylari (AWS ECR, Google GAR) aniq yoziladi. Oqim oddiy: docker login bilan autentifikatsiya, docker build -t <to'liq nom>, docker push bilan yuklash, boshqa mashinada docker pull. Private registry — parolli/tokenli, faqat ruxsat berilganlar pull qiladi (kompaniya ichki image'lari uchun; GHCR va ECR standart holatda private). Tag — o'zgaruvchan ko'rsatkich (git branch kabi): u qaysidir image'ga "ishora"laydi va qayta yozilishi mumkin. Shundan latest anti-pattern kelib chiqadi: latest shunchaki "oxirgi push qilingan" degani, aniq versiyani kafolatlamaydi — bugun bir image, ertaga boshqa, deploy takrorlanmaydi 2.11-bob. Yaxshi amaliyot — semver tag (1.4.2, 1.4, 1): CI har relizda aniq versiya bilan tag qo'yadi 10.5-bob. Eng qat'iy usul — digest bilan bog'lash (api@sha256:...): digest — image kontentining kriptografik barmoq izi, u aynan o'sha baytlarni bildiradi va hech qachon o'zgarmaydi (tag qayta yozilsa ham). Production'da takrorlanadigan (reproducible) deploy uchun digest — eng ishonchli. Bitta image bir vaqtda bir necha tag'ga ega bo'lishi mumkin: docker tag <manba> <yangi_nom> bilan qo'shimcha yorliq beriladi (masalan CI 1.4.2 va 1.4 va stableni bitta image'ga bog'laydi).

2.13. BuildKit va image xavfsizligini skanerlash

text
  BUILDKIT — zamonaviy build dvigateli (Docker'da standart yoqilgan):
   Parallel layer build (bog'liq bo'lmagan bosqichlar bir vaqtda)
   Aqlliroq cache (faqat kerakli fayl o'zgarsa qayta quriladi)
   Build-time SECRET (kalit image'ga TUSHMAYDI — quyida)
   Multi-platform (amd64 + arm64 bitta buyruqda — 10.6)

  BUILD-TIME SECRET (ARG bilan XATO — secret layer'da qoladi!):
   ARG NPM_TOKEN             image tarixida (docker history) KO'RINADI
   RUN --mount=type=secret,id=npmtoken \
         npm ci                secret faqat shu RUN paytida, layer'ga YOZILMAYDI
     (docker build --secret id=npmtoken,src=$HOME/.npmrc .)

  IMAGE SKANERLASH (zaiflik — CVE — qidirish):
  docker scout cves myapp:1.0      Docker'ning o'z skaneri
  trivy image myapp:1.0            mashhur mustaqil skaner (CVE bazasi)
   natija: bazaviy image/paketlardagi ma'lum zaifliklar ro'yxati
   yechim: bazani yangilash (node:22-alpine  yangi patch), paket update

BuildKit — Docker'ning zamonaviy build dvigateli (hozirgi versiyalarda standart yoqilgan). U eski build'dan tezroq: bir-biriga bog'liq bo'lmagan bosqichlarni parallel quradi, cache'ni aqlliroq boshqaradi, va multi-stage (2.10, 10.4) hamda multi-platform build (bitta image'ni amd64 va arm64 uchun — 10.6) imkonini beradi. BuildKit'ning eng muhim xavfsizlik imkoni — build-time secret. Muammo: agar maxfiy kalitni (masalan xususiy npm token, SSH kaliti) ARG bilan uzatsangiz, u image tarixida qoladi (docker history yoki layer'ni ochib ko'rish bilan topiladi) — bu jiddiy nuqson. Yechim — RUN --mount=type=secret: secret faqat o'sha RUN bajarilayotgan payt vaqtincha ulanadi, hech qaysi layer'ga yozilmaydi (docker build --secret id=...,src=...). Runtime maxfiy ma'lumot esa umuman boshqa masala — u -e/--env-file bilan (2.5, Misol 4, 10.11) beriladi, hech qachon image ichiga qo'yilmaydi. Image skanerlash — production'ga chiqarishdan oldin majburiy qadam: docker scout cves <image> yoki mustaqil trivy image <image> bazaviy image va o'rnatilgan paketlardagi ma'lum zaifliklarni (CVE) topadi. Topilsa — bazani yangi patch versiyaga ko'tarish yoki muammoli paketni yangilash kerak. Aynan shu sabab kichik baza (alpine/distroless — 2.10) afzal: kamroq paket = kamroq potensial zaiflik = kichik hujum yuzasi. 10.5da CI/CD skanerlashni har build'da avtomatlashtiradi.


3. Sintaksis — tez ma'lumotnoma

text
DOCKERFILE 2.5-bob: FROM | WORKDIR | COPY | RUN | ENV | ARG | EXPOSE | USER | CMD | ENTRYPOINT
BUILD: docker build -t myapp:1.0 .          image qurish (-t = nom:tag, . = kontekst)
RUN 2.8-bob: docker run -d -p 8080:3000 --name api myapp
           -d (fonda) | -p XOST:KONTEYNER | --name | -e KEY=val | -v vol:/path | --rm
RO'YXAT: docker ps           ishlayotgan konteynerlar | docker ps -a (hammasi)
         docker images       lokal image'lar
DEBUG (Misol 6): docker logs <id> | docker logs -f <id> | docker exec -it <id> sh
BOSHQARISH: docker stop <id> | docker start <id> | docker rm <id> | docker rmi <image>
REGISTRY (2.4, 2.12): docker login | docker tag src reg/user/app:1.0 | docker push reg/user/app:1.0 | docker pull ...
VOLUME 2.7-bob: docker run -v mydata:/path (volume) | -v $(pwd):/app (bind mount)
TARMOQ 2.8-bob: --network mynet | --network host | --network none | --tmpfs /tmp
INSPECT/STATS: docker inspect <id> | docker stats | docker history <image> (layerlar)
SKAN 2.13-bob: docker scout cves <image> | trivy image <image>     zaiflik (CVE)
BUILD 2.13-bob: docker build --build-arg K=V --secret id=..,src=.. -t app:1.0 .
TOZALASH: docker system prune -a (barchasi) | docker image prune | docker volume prune

4. Batafsil kod namunalari

Misol 1 — Oddiy Node.js Dockerfile (cache-optimal tartib — 2.3)

dockerfile
# Dockerfile — oddiy Node.js (Express) ilova uchun
FROM node:22-alpine                  # bazaviy image — kichik Alpine (2.10)

WORKDIR /app                         # ishchi papka (keyingi buyruqlar shu yerda — 2.5)

#  AVVAL package fayllar (kam o'zgaradi — cache uchun — 2.3)
COPY package*.json ./                # package.json + package-lock.json
RUN npm ci --omit=dev                # qaramliklar (faqat production — 2.10)
                                     #  bu layer cache'da qoladi (kod o'zgarsa ham)

# KEYIN kod (ko'p o'zgaradi — pastda — 2.3)
COPY . .                             # qolgan barcha kod

EXPOSE 3000                          # 3000-portni ishlatadi (hujjatlash — 2.8)
CMD ["node", "src/main.js"]          # ishga tushganda (exec shakl — 2.6)

Misol 2 — .dockerignore (Dockerfile yonida — 2.9)

text
# .dockerignore — image'ga TUSHMASLIGI kerak bo'lganlar
node_modules        # RUN npm ci konteyner ichida o'zi quradi (qayta ko'chirmang)
npm-debug.log
.git                # versiya tarixi — keraksiz
.gitignore
.env                #  MAXFIY kalitlar — image'ga TUSHMASIN (xavfsizlik)
.env.*
dist                # build natijasi (konteyner ichida quriladi)
Dockerfile          # o'zini ko'chirish shart emas
.dockerignore
README.md
*.md
coverage            # test natijalari
.vscode             # IDE sozlamalari

Misol 3 — Build va run (asosiy ish oqimi)

bash
# 1. Image qurish (Dockerfile'dan)
docker build -t myapp:1.0 .          # -t = nom:tag ; "." = build kontekst (joriy papka)
#  har layer quriladi 2.3-bob; natijada "myapp:1.0" image hosil bo'ladi

docker images                        # lokal image'lar ro'yxati (myapp ko'rinadi)

# 2. Konteyner ishga tushirish
docker run -d -p 8080:3000 --name myapi myapp:1.0
#          │   │            │
#          │   │            └─ konteynerga nom beramiz (id o'rniga qulay)
#          │   └─ port: xost 8080  konteyner 3000 (2.8)
#          └─ -d = detached (fonda ishlaydi, terminalni band qilmaydi)

docker ps                            # ishlayotgan konteynerlar (myapi ko'rinadi)
#  brauzer: http://localhost:8080  ilova javob beradi 

Misol 4 — Env va port (muhit o'zgaruvchilari — 5.8, 2.5)

bash
# Variant A — alohida -e bilan (har biri)
docker run -d -p 8080:3000 \
  -e NODE_ENV=production \            # muhit o'zgaruvchisi (5.8)
  -e DATABASE_URL=postgres://db:5432/app \
  --name myapi myapp:1.0

# Variant B — fayldan (--env-file — ko'p o'zgaruvchi uchun qulay)
docker run -d -p 8080:3000 \
  --env-file .env \                  # .env fayldagi barcha o'zgaruvchilar
  --name myapi myapp:1.0
#  .env image'ga TUSHMAYDI (.dockerignore — 2.9), runtime'da BERILADI (xavfsiz)
dockerfile
# Dockerfile ichida ENV (standart qiymat, image'da qoladi):
ENV NODE_ENV=production              # build paytida o'rnatiladi (2.5)
ENV PORT=3000
#  ENV — barcha konteynerlarga; -e/--env-file — runtime'da ustun (override)

Misol 5 — Volume (ma'lumotni saqlash — 2.7)

bash
# PostgreSQL — DB ma'lumoti VOLUME'da (konteyner o'chsa ham qoladi)
docker run -d \
  --name pgdb \
  -e POSTGRES_PASSWORD=secret \
  -v pgdata:/var/lib/postgresql/data \   # volume: pgdata  DB papkasi (2.7)
  -p 5432:5432 \
  postgres:17-alpine

#  Konteyner o'chsa ham — "pgdata" volume QOLADI:
docker rm -f pgdb                        # konteyner o'chdi
docker run -d --name pgdb2 -v pgdata:/var/lib/postgresql/data postgres:17-alpine
#  eski ma'lumot saqlanib qoldi (volume tufayli) 

docker volume ls                         # volume'lar ro'yxati
docker volume inspect pgdata             # batafsil (qayerda saqlanadi)

# DEV uchun bind mount (kod o'zgarishi darrov ko'rinadi — 2.7):
docker run -v $(pwd):/app -w /app node:22-alpine npm run dev

Misol 6 — exec va logs bilan debug (eng muhim debug ko'nikmasi)

bash
# Konteyner ishlamayapti yoki xato beryapti — qayerdan boshlash?

docker ps -a                         # 1. holat (Up? Exited? exit kodi nima?)
docker logs myapi                    # 2. loglar (ilova stdout/stderr — xato xabari)
docker logs -f myapi                 # 3. jonli loglar (-f = follow, kuzatib turish)
docker logs --tail 50 myapi          # oxirgi 50 qator

# Konteyner ICHIGA kirib tekshirish (eng kuchli debug):
docker exec -it myapi sh             # interaktiv shell (alpine'da "sh"; debian'da "bash")
#           │  │  │    └─ qaysi buyruq (shell)
#           │  │  └─ konteyner nomi
#           │  └─ -t = terminal
#           └─ -i = interaktiv
# Endi konteyner ichidasan: ls, cat, env, ping db ... bilan tekshir
#  exit bilan chiqasan (konteyner ishlashda davom etadi)

docker inspect myapi                 # konteyner haqida HAMMA narsa (tarmoq, mount, env)
docker stats                         # jonli resurs (CPU/RAM — qaysi konteyner ko'p yeyapti)

Misol 7 — Alpine bilan kichik image va RUN birlashtirish (2.3, 2.10)

dockerfile
FROM node:22-alpine                  # kichik baza (~150 MB — 2.10)

# Tizim paketi kerak bo'lsa — apk (alpine paket menejeri — 10.1: 2.5):
#  RUN'larni BIRLASHTIR (bitta layer — kam joy — 2.3):
RUN apk add --no-cache curl          # --no-cache = paket cache saqlanmaydi (kichik)

WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev && \           # qaramlik + cache tozalash — BITTA RUN
    npm cache clean --force          # \ bilan davom (bir layer)

COPY . .
EXPOSE 3000
CMD ["node", "src/main.js"]
#  Yomon: har "RUN" alohida  ko'p layer, katta image
#    Yaxshi: bog'liq buyruqlar "&&" bilan bitta RUN'da

Misol 8 — Non-root user (xavfsizlik — 2.11)

dockerfile
FROM node:22-alpine

WORKDIR /app

# Egasini "node" qilib ko'chiramiz (root emas — 2.11):
COPY --chown=node:node package*.json ./
RUN npm ci --omit=dev

COPY --chown=node:node . .

USER node                            #  shu yerdan keyin "node" useri (UID 1000)
                                     #  konteyner buzilsa ham root huquqi YO'Q

EXPOSE 3000
CMD ["node", "src/main.js"]
#  node image'da "node" useri TAYYOR (qo'shimcha yaratish shart emas)
#    Agar yo'q bo'lsa: RUN addgroup -S app && adduser -S app -G app

Misol 9 — HEALTHCHECK (konteyner sog'ligi — 2.5)

dockerfile
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .

# Konteyner ishlayaptimi — Docker muntazam tekshiradi:
HEALTHCHECK --interval=30s \         # har 30 sekundda tekshir
            --timeout=10s \          # 10s ichida javob bermasa — fail
            --start-period=40s \     # ishga tushish uchun 40s grace (yangi konteyner)
            --retries=3 \            # 3 marta ketma-ket fail  "unhealthy"
  CMD wget -q --spider http://localhost:3000/health || exit 1
#     │                                                    └─ 1 = unhealthy, 0 = healthy
#     └─ wget alpine'da bor (curl o'rniga); /health endpoint ilovada bo'lsin

EXPOSE 3000
CMD ["node", "src/main.js"]
#  docker ps  "STATUS" ustunida (healthy)/(unhealthy) ko'rinadi
#    Compose/orkestratsiya (10.4, 10.8) unhealthy konteynerni qayta ko'taradi

Misol 10 — NestJS uchun Dockerfile (TypeScript build — 8.1)

dockerfile
# NestJS — TypeScript build kerak (dist/ ga kompilyatsiya — 7.1)
FROM node:22-alpine

WORKDIR /app

# 1. Qaramliklar (BARCHASI — build uchun devDependencies ham kerak)
COPY package*.json ./
RUN npm ci                           # hammasi (TS, @nestjs/cli — build uchun)

# 2. Kod + build (TypeScript  JavaScript)
COPY . .
RUN npm run build                    # dist/ papka hosil bo'ladi (nest build)

# 3. Production qaramliklarga tushirish (devDependencies o'chadi — kichik)
RUN npm prune --omit=dev             # faqat production qaramlik qoladi

USER node                            # non-root (2.11)
EXPOSE 3000
CMD ["node", "dist/main.js"]         # build natijasini ishga tushir (exec — 2.6)
#  Bu BITTA stage — ishlaydi, lekin build vositalari image'da qoladi (kattaroq)
#    To'liq optimal — MULTI-STAGE BUILD (build + production alohida — 10.4)

Misol 11 — Registry: tag, push va pull (image'ni tarqatish — 2.12)

bash
# 1. Registry'ga kirish (GHCR misolida — token bilan)
echo "$GITHUB_TOKEN" | docker login ghcr.io -u myuser --password-stdin
#     parolni stdin orqali ber — terminal tarixida qolmaydi (10.1: 2.4)

# 2. Aniq versiya bilan qurish (latest EMAS — 2.12)
docker build -t ghcr.io/myuser/api:1.4.2 .

# 3. Bitta image'ga bir necha tag (semver ko'rsatkichlari)
docker tag ghcr.io/myuser/api:1.4.2 ghcr.io/myuser/api:1.4
docker tag ghcr.io/myuser/api:1.4.2 ghcr.io/myuser/api:stable
#     uchala tag AYNAN bir image'ga ishora qiladi (qo'shimcha joy egallamaydi)

# 4. Registry'ga yuklash (har bir tag alohida push)
docker push ghcr.io/myuser/api:1.4.2
docker push ghcr.io/myuser/api:1.4

# 5. Boshqa mashinada (server, CI) olish
docker pull ghcr.io/myuser/api:1.4.2         # tag bilan
docker pull ghcr.io/myuser/api@sha256:9f2c…  # digest bilan (o'zgarmas — 2.12)
#  10.5da GitHub Actions bu oqimni har commit'da AVTOMATIK bajaradi

Misol 12 — BuildKit secret (kalitni image'ga tushirmaslik — 2.13)

dockerfile
#  YOMON — token ARG bilan (image tarixida qoladi, docker history KO'RSATADI):
#    ARG NPM_TOKEN
#    RUN echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc && npm ci

#  TO'G'RI — BuildKit secret (kalit HECH QAYSI layer'ga yozilmaydi):
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc \
    npm ci --omit=dev
#   └─ .npmrc faqat SHU RUN paytida ulanadi, keyin yo'qoladi (image'da yo'q)
COPY . .
USER node
EXPOSE 3000
CMD ["node", "src/main.js"]
bash
# Build — secret'ni tashqaridan (fayldan) uzatib:
docker build --secret id=npmrc,src=$HOME/.npmrc -t myapp:1.0 .
#  Tekshirish: docker history myapp:1.0  token HECH QAYERDA ko'rinmaydi

5. To'g'ri va noto'g'ri holatlar

1) Dockerfile tartibi (cache)

text
 COPY . .  RUN npm ci (kod o'zgarsa — npm har safar qayta — 2.3)
 COPY package*.json  RUN npm ci  COPY . . (npm cache'da qoladi)

2) Bazaviy image hajmi

text
 FROM node:22 (~1.1 GB — to'liq Debian, keraksiz)
 FROM node:22-alpine (~150 MB — kichik, tez — 2.10)

3) Foydalanuvchi (xavfsizlik)

text
 root sifatida ishlash (standart — buzilsa root huquqi — 2.11)
 USER node (non-root — least privilege)

4) Maxfiy ma'lumot

text
 .env image'ga ko'chiriladi (COPY . . — kalitlar tarqaladi — 2.9)
 .dockerignore'da .env + runtime'da --env-file (2.9, Misol 4)

5) CMD shakli

text
 CMD node main.js (shell shakl — SIGTERM ilovaga yetmaydi — 2.6)
 CMD ["node", "main.js"] (exec shakl — toza to'xtaydi)

6) Image versiyasi

text
 FROM node:latest (bashorat qilib bo'lmaydi — bugun/ertaga har xil)
 FROM node:22-alpine (aniq versiya — barqaror — 2.11)

7) Ma'lumot saqlash

text
 DB ma'lumoti konteyner ichida (konteyner o'chsa — yo'qoladi — 2.7)
 volume (-v pgdata:/var/lib/postgresql/data — qoladi)

6. Keng tarqalgan xatolar va yechimlari

Xato 1 — Cannot connect to the Docker daemon

Sababi: Docker daemon (engine) ishlamayapti, yoki foydalanuvchi docker guruhida emas. Yechimi: Docker Desktop'ni ishga tushir (yoki Linux'da sudo systemctl start docker — 10.1: 2.6); Linux'da sudo usermod -aG docker $USER keyin qayta login (har safar sudo yozmaslik uchun).

Xato 2 — Build cache buzilishi (har safar sekin)

Sababi: COPY . . ni RUN npm ci dan oldin qo'ygan kod har o'zgarganda qaramliklar qaytadan o'rnatiladi 2.3-bob. Yechimi: avval COPY package*.json ./ + RUN npm ci, keyin COPY . . (Misol 1).

Xato 3 — Image juda katta (GB'lar)

Sababi: to'liq baza (node:22), .dockerignore yo'q, node_modules ko'chirilgan, devDependencies qolgan. Yechimi: node:22-alpine 2.10-bob, .dockerignore 2.9-bob, npm ci --omit=dev, multi-stage 10.4-bob.

Xato 4 — COPY . . ni npm installdan oldin qilish

Sababi: Xato 2 bilan bir xil ildiz — tartib noto'g'ri. Yechimi: package fayllarni alohida, oldin ko'chir — qaramliklar layer cache'da qolsin 2.3-bob.

Xato 5 — port is already allocated (port band)

Sababi: xost porti (masalan 8080) boshqa konteyner/jarayon tomonidan band. Yechimi: docker ps bilan portni kim band qilganini ko'rish, eski konteynerni docker stop/rm qilish, yoki boshqa xost port tanlash kerak (-p 8081:3000). Lokalda port band bo'lsa ss -tulpn yordam beradi (10.1: 2.7).

Xato 6 — Konteyner darrov o'chib qoladi (Exited)

Sababi: asosiy jarayon tugadi (CMD noto'g'ri, ilova crash bo'ldi, yoki fon jarayoni emas). Yechimi: docker logs <id> bilan xatoni ko'rish (Misol 6); CMD to'g'riligini tekshirish kerak; ilova foregroundda ishlashi shart (node main.js — fonga o'tmasin).

Xato 7 — .env yoki maxfiy ma'lumot image'da qolib ketishi

Sababi: .dockerignore yo'q yoki .env unda emas. Yechimi: .dockerignorega .env qo'shish kerak 2.9-bob; maxfiy ma'lumotni runtime'da --env-file bilan berish lozim (Misol 4); secret kerak bo'lsa BuildKit --secret ishlatiladi 10.11-bob.

Xato 8 — Volume'dagi fayl ruxsati (permission denied)

Sababi: non-root user (node) volume papkasiga yozolmaydi (egasi root). Yechimi: volume papkasi egasini to'g'rilash (chown), yoki COPY --chown=node:node ishlatish kerak; named volume'da Docker odatda ruxsatni o'zi boshqaradi (2.7, 2.11).

Xato 9 — denied / unauthorized push paytida

Sababi: registry'ga login qilinmagan, token muddati o'tgan, yoki image nomi registry namespace'iga mos emas (masalan myapp:1.0 deb ghcr.io/user/siz push qilinmoqda). Yechimi: docker login <registry> bilan qayta kirish; image nomini to'liq shaklda tag qilish (docker tag myapp:1.0 ghcr.io/user/myapp:1.0 — 2.12, Misol 11); GHCR/ECR'da token'da write:packages/push ruxsati borligini tekshirish.

Xato 10 — latest tufayli takrorlanmaydigan deploy

Sababi: FROM node:latest yoki image'ni :latest tag bilan deploy qilish — tag qayta yozilib, kecha ishlagan build bugun boshqa image'ni tortadi 2.12-bob. Yechimi: hamma joyda aniq versiya ishlatish (node:22-alpine, api:1.4.2); production'da eng qat'iy kafolat kerak bo'lsa digest bilan bog'lash (api@sha256:... — takrorlanadigan deploy).


7. Integratsiya — bu mavzu stack'ning qayerida uchraydi

  • Linux server 10.1-bob: konteyner Linux yadrosi ustida; apt/apk, port, foydalanuvchi tushunchalari shu yerdan.
  • Nginx 10.2-bob: Nginx ham konteynerda ishlaydi; reverse proxy konteynerlar oldida.
  • Docker Compose 10.4-bob: ko'p konteynerni (ilova + DB + Redis) bitta fayl bilan; multi-stage build to'liq.
  • CI/CD 10.5-bob: GitHub Actions image quradi, registry'ga (GHCR/ECR) push qiladi, image'ni skanerlaydi (trivy — 2.13), serverga deploy.
  • Registry 2.12-bob: GHCR/Docker Hub/ECR — image ombori; semver tag va digest bilan versiyalanadi.
  • AWS 10.6-bob: image ECR'ga, konteyner ECS/EC2'da ishlaydi.
  • Node.js (5.x): npm ci, package.json, env (5.2, 5.8) — Dockerfile ichida.
  • NestJS 8.1-bob: TypeScript build (nest build dist/) Dockerfile'da (Misol 10).
  • Kubernetes 10.8-bob: image — Pod'ning asosi (orkestratsiya konteynerlarni boshqaradi).
  • Secrets 10.11-bob: .env image'ga tushmaydi, runtime/secret bilan beriladi.

8. Eng yaxshi amaliyotlar (best practices)

  • Kichik baza (node:22-alpinenode:22 emas — 2.10).
  • Cache-optimal tartib (package fayllar npm ci kod — 2.3, Misol 1).
  • .dockerignore (node_modules, .git, .env — har loyihada — 2.9).
  • Non-root user (USER node — least privilege — 2.11, Misol 8).
  • Aniq versiya (node:22-alpinelatest emas — 2.11).
  • exec shakl CMD (["node","main.js"] — signal to'g'ri — 2.6).
  • Faqat production qaramlik (npm ci --omit=dev, multi-stage — 2.10).
  • Volume — DB uchun (konteyner o'chsa ham ma'lumot qolsin — 2.7).
  • Secret runtime'da (.envni image'ga qo'shmaslik; --env-file — 2.9, 10.11).
  • HEALTHCHECK (orkestratsiya unhealthy'ni qayta ko'tarsin — 2.5, Misol 9).
  • RUN birlashtirish (&& bilan — kam layer, kichik image — 2.3, Misol 7).
  • Semver tag + digest (api:1.4.2 / @sha256:...latest emas — 2.12, Misol 11).
  • Build-time secret BuildKit bilan (kalit image'ga tushmasin — 2.13, Misol 12).
  • Image skanerlash (docker scout/trivy — deploydan oldin CVE tekshir — 2.13).
  • Muntazam tozalash (docker system prune — disk to'lmasin — 10.1: Xato 5).

9. Amaliy loyiha: "Node.js Ilovani Dockerlashtirish"

Mavjud Node.js/NestJS ilovani production-ready Docker image'ga aylantirish — har bir zamonaviy backendchining majburiy ko'nikmasi.

Maqsad

Kichik Express yoki NestJS ilovani (bir nechta endpoint + /health + PostgreSQL ulanish) optimal, xavfsiz Dockerfile bilan image'ga qadoqlash, konteyner sifatida ishga tushirish va DB konteyneri bilan bog'lash.

Talablar (requirements)

  1. Ilova: kichik Express/Nest API (/, /health, va DB'dan o'qiydigan bitta endpoint).
  2. Dockerfile: node:22-alpine baza, cache-optimal tartib (package npm ci kod — Misol 1, 2.3).
  3. .dockerignore: node_modules, .git, .env (Misol 2, 2.9).
  4. Build va run: docker build -t myapp:1.0 . + docker run -d -p 8080:3000 (Misol 3).
  5. Env: NODE_ENV, DATABASE_URL ni --env-file bilan berish (Misol 4, 2.5).
  6. PostgreSQL konteyner: postgres:17-alpine + volume (ma'lumot saqlansin — Misol 5, 2.7).
  7. Networking: ilova konteyneri DB'ni nomi bilan topishi (docker network — 2.8).
  8. Non-root: USER node + COPY --chown (Misol 8, 2.11).
  9. HEALTHCHECK: /health endpoint'ni tekshirish (Misol 9, 2.5).
  10. Debug: docker logs va docker exec -it ... sh bilan konteyner ichini tekshirish (Misol 6).

Maslahatlar (hint)

  • Cache uchun albatta package fayllarni koddan oldin ko'chirish kerak (aks holda har build sekin — 2.3, Xato 2).
  • .envni .dockerignorega qo'shish lozim — maxfiy kalitlar image'ga tushmasin (2.9, Xato 7).
  • Konteyner darrov o'chsa — docker logs <id> birinchi qadam (Misol 6, Xato 6).
  • DB bilan bog'lanish uchun docker network create + ikkala konteynerni shu tarmoqqa qo'shish kerak 2.8-bob.
  • Alpine'da shell — sh (bash emas); HEALTHCHECK'da wget (curl o'rniga — 2.10).

"Tayyor" mezonlari (acceptance criteria)

  • docker build xatosiz image quradi (docker imagesda ko'rinadi).
  • Kod o'zgarganda build tez (npm ci cache'dan — qayta ishlamaydi).
  • http://localhost:8080 va /health brauzerdan javob beradi.
  • .dockerignore bor; .env image'ga tushmagan.
  • PostgreSQL volume'da; konteyner o'chib qayta ko'tarilsa ma'lumot qoladi.
  • Ilova DB'ni nomi bilan topadi (bir tarmoqda).
  • Konteyner USER node (non-root) sifatida ishlaydi.
  • docker ps da STATUS (healthy) ko'rinadi.
  • Image hajmi oqilona (docker images — alpine tufayli kichik).

Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.


10. Xulosa va keyingi bobga ko'prik

Bu bobda Docker'ning asoslarini chuqur o'rgandik:

  • Konteyner vs VM (yadro ulashish — yengil — 2.1); image vs container (klass vs obyekt — 2.2); layer va cache (tartib muhim — 2.3); arxitektura (daemon, client, registry — 2.4).
  • Dockerfile direktivalari (FROM, COPY, RUN, CMD... — 2.5); CMD vs ENTRYPOINT (exec vs shell — 2.6); volume vs bind mount (ma'lumot saqlash — 2.7); port mapping/networking 2.8-bob.
  • .dockerignore 2.9-bob; image kichraytirish (alpine — 2.10); xavfsizlik (non-root — 2.11).
  • Registry va versiyalash (tag, semver, digest, push/pull — 2.12); BuildKit va image skanerlash (build-time secret, trivy/scout — 2.13).

Endi siz ilovani bir marta qadoqlab, hamma joyda bir xil ishlatadigan holatga keltira olasiz — "mening kompyuterimda ishlayapti" muammosi tarixga aylandi. Bu — zamonaviy deploy'ning markaziy ko'nikmasi.

Keyingi bob — 10.4-bob: Docker Compose va multi-stage build. Hozir bitta konteynerni qo'lda docker run bilan ko'tardik. Lekin real ilova — bir nechta konteyner: ilova + PostgreSQL + Redis + Nginx. Har birini qo'lda, uzun flaglar bilan ishga tushirish — og'ir va xatoga moyil. Docker Compose buni hal qiladi: bitta docker-compose.yml fayl bilan butun tizimni (servis, tarmoq, volume) ta'riflaysiz va docker compose up bilan bir buyruqda ko'tarasiz. Hamda multi-stage build bilan image hajmini bir necha barobar kichraytirib, eng optimal production image yasashni o'rganamiz.


Foydalanilgan rasmiy/ishonchli manbalar

  • Docker rasmiy hujjatlari — "What is a container?" va "What is an image?" (asosiy tushunchalar, konteyner vs VM).
  • Docker rasmiy hujjatlari — Dockerfile ma'lumotnomasi (barcha direktivalar: FROM, COPY/ADD, RUN, ENV/ARG, EXPOSE, USER, VOLUME, HEALTHCHECK, LABEL, ONBUILD; CMD vs ENTRYPOINT; exec va shell shakl).
  • Docker rasmiy hujjatlari — "Building best practices" (kichik baza/alpine, layer cache tartibi, multi-stage, non-root user, .dockerignore).
  • Docker rasmiy hujjatlari — saqlash (storage): volume, bind mount va tmpfs mount farqlari.
  • Docker rasmiy hujjatlari — tarmoq (networking): bridge, host, none va foydalanuvchi bridge tarmoqlari, konteyner-DNS.
  • Docker rasmiy hujjatlari — docker build va docker run CLI ma'lumotnomasi; HEALTHCHECK qo'llanmasi.
  • Docker rasmiy hujjatlari — BuildKit va RUN --mount=type=secret (build-time secret'ni image'ga tushirmaslik).
  • Docker rasmiy hujjatlari — image tag va push/pull; Docker Scout bilan zaiflik (CVE) skanerlash.
  • OCI (Open Container Initiative) — image va runtime spetsifikatsiyalari (digest, image formati).
  • Trivy rasmiy hujjatlari — konteyner image'larida zaiflik (CVE) skanerlash.
  • GitHub rasmiy hujjatlari — GitHub Container Registry (GHCR) bilan ishlash: login, tag, push.

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
10.3-bob: Docker — image, container, Dockerfile — Wisar