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 qiladi — Docker 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 runbilan 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)
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 yengilKonteyner 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) vacgroups(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)
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 {}dannew User()bilan ko'p obyekt yaratgandek, bitta imagedandocker runbilan 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)
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*.jsonvaRUN npm cini kod nusxasidan (COPY . .) oldin yozamiz: kod har o'zgargandanpm ciqayta ishlamasin (qaramliklar kam o'zgaradi). Bu — Misol 1 va Xato 4ning asosi.
2.4. Docker arxitektura (daemon, client, registry)
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 tushiradiDocker arxitekturasi — uch qismdan iborat client-server tizim: Docker client (
dockerbuyrug'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 nginxdeganingda daemon avval lokaldanginximage bor-yo'qligini tekshiradi; bo'lmasa Hub'dan pull (yuklab oladi) qiladi, keyin konteyner sifatida ishga tushiradi. O'z image'ingnidocker pushbilan Hub'ga yuborasiz (10.5da CI/CD shuni avtomatlashtiradi).
2.5. Dockerfile direktivalari
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 tushgandaDockerfile — image qurish uchun retsept (matn fayl): har bir qatori bir direktiva (instruction). Asosiylari:
FROM— bazaviy image (har Dockerfile shundan boshlanadi, masalannode:22-alpine);WORKDIR— ishchi papka (keyingi buyruqlar shu yerda bajariladi,cdo'rniga);COPY— xostdagi fayllarni image'ga ko'chiradi (ADD— COPY + URL/tar extract, lekin oddiy holatdaCOPYtavsiya etiladi);RUN— build 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-pqiladi, 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)
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:
CMD— standart buyruq,docker run myapp <yangi buyruq>bilan oson almashtiriladi (masalandocker run myapp npm testCMD o'rniganpm testishlaydi).ENTRYPOINT— asosiy bajaruvchi, oson o'zgarmaydi:docker run myapp arg1deganda 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 oddiyCMD ["node", "dist/main.js"]yetadi. Yana muhim narsa — ikki shakl: exec shakl (["node", "main.js"]— JSON massiv, tavsiya —nodeto'g'ridan-to'g'ri ishlaydi, signal (SIGTERM) ilovaga yetadi toza to'xtaydi) va shell shakl (node main.js—/bin/sh -corqali, signalshga boradi, ilovaga yetmaydi muammo). Doim exec shakldan foydalanish tavsiya etiladi.
2.7. Volume vs bind mount (ma'lumot saqlash)
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-vhali keng tarqalgan.
2.8. Port mapping va networking
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 myappxostning 8080-portiga kelgan so'rov konteynerning 3000-portiga uzatiladi (brauzerdahttp://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) — masalanapikonteyneridbkonteynerinihost=dbdeb ulaydi (IP kerak emas). 10.4da Docker Compose buni avtomatik qiladi.EXPOSEesa faqat hujjatlash (qaysi portni ishlatadi — info), haqiqiy ochish-porqali.
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)
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.dockerignore —
docker build .da.(nuqta) build kontekst deyiladi: o'sha papka butunlay daemon'ga yuboriladi vaCOPY . .qilganda image'ga ko'chiriladi. Muammo: agar boshqarmasangiz,node_modules(katta — lekin baribirRUN npm ciqayta quradi),.git(tarix), va eng xavflisi.env(maxfiy kalitlar — image'ga tushib ketadi) ham ko'chiriladi. Yechim — Dockerfile yonida.dockerignorefayli (xuddi.gitignorekabi): unganode_modules,.git,.env,dist,*.logni yozasiz. Natija uch tomonlama foyda: kichikroq image (keraksiz fayllar yo'q), tezroq build (kontekst kichik), va xavfsizlik (maxfiy.envimage'ga tushmaydi — bu eng muhimi). Har bir Docker loyihasida.dockerignoremajburiy.
2.10. Image hajmini kichraytirish (alpine)
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),250 MB — minimal Debian), va eng yaxshisinode:22-slim(node:22-alpine(~150 MB — Alpine Linux asosida, ~6 MB minimal Linux,apkpaket menejeri — 10.1: 2.5). Boshqa usullar:.dockerignore2.9-bob,RUNbuyruqlarini 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)
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 qiladiXavfsizlik — 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. Yechim — non-root foydalanuvchi sifatida ishlash. Rasmiy
nodeimage'da tayyornodeuseri bor (UID 1000): Dockerfile'daUSER nodedirektivasidan keyin barcha buyruqlar shu foydalanuvchi sifatida ishlaydi (COPY --chown=node:nodebilan fayl egasini ham to'g'rilaysiz). Boshqa xavfsizlik qoidalari: aniq versiya ishlatish kerak (node:22-alpine—latestemas, chunkilatestbashorat 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'larnidocker scoutbilan zaifliklarga skanerlash lozim. Eng kam imtiyoz tamoyili konteynerda ham amal qiladi.
2.12. Registry, tag va versiyalash (image'larni tarqatish)
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(masalanghcr.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 loginbilan autentifikatsiya,docker build -t <to'liq nom>,docker pushbilan yuklash, boshqa mashinadadocker 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. Shundanlatestanti-pattern kelib chiqadi:latestshunchaki "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 CI1.4.2va1.4vastableni bitta image'ga bog'laydi).
2.13. BuildKit va image xavfsizligini skanerlash
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 updateBuildKit — 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
amd64vaarm64uchun — 10.6) imkonini beradi. BuildKit'ning eng muhim xavfsizlik imkoni — build-time secret. Muammo: agar maxfiy kalitni (masalan xususiy npm token, SSH kaliti)ARGbilan uzatsangiz, u image tarixida qoladi (docker historyyoki layer'ni ochib ko'rish bilan topiladi) — bu jiddiy nuqson. Yechim —RUN --mount=type=secret: secret faqat o'shaRUNbajarilayotgan payt vaqtincha ulanadi, hech qaysi layer'ga yozilmaydi (docker build --secret id=...,src=...). Runtime maxfiy ma'lumot esa umuman boshqa masala — u-e/--env-filebilan (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 mustaqiltrivy 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
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 prune4. Batafsil kod namunalari
Misol 1 — Oddiy Node.js Dockerfile (cache-optimal tartib — 2.3)
# 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)
# .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 sozlamalariMisol 3 — Build va run (asosiy ish oqimi)
# 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)
# 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 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)
# 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 devMisol 6 — exec va logs bilan debug (eng muhim debug ko'nikmasi)
# 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)
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'daMisol 8 — Non-root user (xavfsizlik — 2.11)
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 appMisol 9 — HEALTHCHECK (konteyner sog'ligi — 2.5)
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'taradiMisol 10 — NestJS uchun Dockerfile (TypeScript build — 8.1)
# 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)
# 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 bajaradiMisol 12 — BuildKit secret (kalitni image'ga tushirmaslik — 2.13)
# 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"]# 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'rinmaydi5. To'g'ri va noto'g'ri holatlar
1) Dockerfile tartibi (cache)
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
FROM node:22 (~1.1 GB — to'liq Debian, keraksiz)
FROM node:22-alpine (~150 MB — kichik, tez — 2.10)3) Foydalanuvchi (xavfsizlik)
root sifatida ishlash (standart — buzilsa root huquqi — 2.11)
USER node (non-root — least privilege)4) Maxfiy ma'lumot
.env image'ga ko'chiriladi (COPY . . — kalitlar tarqaladi — 2.9)
.dockerignore'da .env + runtime'da --env-file (2.9, Misol 4)5) CMD shakli
CMD node main.js (shell shakl — SIGTERM ilovaga yetmaydi — 2.6)
CMD ["node", "main.js"] (exec shakl — toza to'xtaydi)6) Image versiyasi
FROM node:latest (bashorat qilib bo'lmaydi — bugun/ertaga har xil)
FROM node:22-alpine (aniq versiya — barqaror — 2.11)7) Ma'lumot saqlash
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 builddist/) Dockerfile'da (Misol 10). - Kubernetes 10.8-bob: image — Pod'ning asosi (orkestratsiya konteynerlarni boshqaradi).
- Secrets 10.11-bob:
.envimage'ga tushmaydi, runtime/secret bilan beriladi.
8. Eng yaxshi amaliyotlar (best practices)
- Kichik baza (
node:22-alpine—node:22emas — 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-alpine—latestemas — 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:...—latestemas — 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)
- Ilova: kichik Express/Nest API (
/,/health, va DB'dan o'qiydigan bitta endpoint). - Dockerfile:
node:22-alpinebaza, cache-optimal tartib (package npm ci kod — Misol 1, 2.3). - .dockerignore:
node_modules,.git,.env(Misol 2, 2.9). - Build va run:
docker build -t myapp:1.0 .+docker run -d -p 8080:3000(Misol 3). - Env:
NODE_ENV,DATABASE_URLni--env-filebilan berish (Misol 4, 2.5). - PostgreSQL konteyner:
postgres:17-alpine+ volume (ma'lumot saqlansin — Misol 5, 2.7). - Networking: ilova konteyneri DB'ni nomi bilan topishi (
docker network— 2.8). - Non-root:
USER node+COPY --chown(Misol 8, 2.11). - HEALTHCHECK:
/healthendpoint'ni tekshirish (Misol 9, 2.5). - Debug:
docker logsvadocker exec -it ... shbilan 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(bashemas); HEALTHCHECK'dawget(curlo'rniga — 2.10).
"Tayyor" mezonlari (acceptance criteria)
-
docker buildxatosiz image quradi (docker imagesda ko'rinadi). - Kod o'zgarganda build tez (npm ci cache'dan — qayta ishlamaydi).
-
http://localhost:8080va/healthbrauzerdan javob beradi. -
.dockerignorebor;.envimage'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 psda 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 buildvadocker runCLI 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!