WisarWisar
Dasturlash kitobi/10-QISM — DevOps34 daqiqa

10.4-bob: Docker Compose va multi-stage build

10-QISM — DevOps va Deploy · 4-mavzu


1. Kirish va motivatsiya

10.3da bitta ilovani Docker image'ga qadoqlab, docker run bilan ishga tushirdik. Lekin real loyiha hech qachon bitta konteyner emas. Oddiy backend ilovasini eslang: NestJS ilovasi 10.3-bob ishlaydi, lekin u PostgreSQL 6.6-bob ga ulanadi, sessiya va cache uchun Redis 5.21-bob kerak, oldida esa so'rovlarni qabul qiladigan Nginx 10.2-bob turadi. Demak — kamida to'rtta konteyner, va ular bir-biri bilan gaplashishi kerak.

Endi tasavvur qil: bularning har birini qo'lda ko'tarish. Avval tarmoq yaratasiz (docker network create), keyin Postgres'ni uzun flaglar bilan ishga tushirasiz (-e POSTGRES_PASSWORD, -v pgdata:..., --network, --name), keyin Redis'ni, keyin ilovani (yana -e DATABASE_URL, -e REDIS_URL, --network, -p), keyin Nginx'ni. Bu — uzun, yodda saqlash qiyin, xatoga moyil jarayon. Har safar serverni qayta ko'targanda yana o'sha 5-6 ta uzun buyruqni to'g'ri tartibda yozishing kerak. Junior dasturchi shu yerda chalkashadi; senior esa butun tizimni bitta faylga yozib, bitta buyruq bilan ko'taradi — bu Docker Compose.

Docker Compose — ko'p konteynerli ilovani bitta compose.yaml faylda ta'riflaydigan va boshqaradigan vosita. Faylda barcha service (servis — ilovani tashkil etuvchi har bir konteyner: app, db, redis, nginx), ularning tarmog'i (network) va doimiy ma'lumoti (volume) bir joyda yoziladi. Keyin docker compose up — va butun tizim bir buyruqda, to'g'ri tartibda ko'tariladi. docker compose down — hammasini tozalaydi. Bu bobning ikkinchi yarmi — multi-stage build (ko'p bosqichli qurish): image'ni ikki qismga ajratib (build bosqichi + ishlash bosqichi), production image hajmini bir necha barobar kichraytirish texnikasi.

O'xshatish: Docker Compose — orkestr dirijyori. Orkestrda ko'p cholg'u bor: skripka (app), violonchel (DB), nay (Redis), baraban (Nginx) — har biri alohida, lekin ular birga, muvofiqlashtirilgan holda chalishi kerak. Har bir musiqachiga alohida "boshla", "to'xta" deb baqirsangiz — tartibsizlik bo'ladi. Dirijyor esa bitta tayoq harakati bilan hammasini boshqaradi: kim qachon kiradi (depends_on — DB avval tayyor bo'lsin), kim kim bilan gaplashadi (tarmoq), qaysi nota chalinadi (sozlamalar). compose.yamlpartitura (nota varag'i): butun "asar" qanday ijro etilishi yozilgan. docker compose up — dirijyor tayog'ini ko'tarishi: hamma cholg'u bir vaqtda, to'g'ri tartibda boshlaydi. Siz endi har bir musiqachi bilan emas, butun orkestr bilan bitta partitura orqali ishlaysiz.

Nega muhim?

  • Bir buyruq — butun stackdocker compose up app+DB+Redis+Nginx'ni birga ko'taradi (qo'lda 5-6 buyruq o'rniga).
  • Takrorlanadigan muhitcompose.yaml Git'da; har kim bir xil tizimni bir xil ko'taradi (lokal = jamoa = CI).
  • Multi-stage = kichik image — build vositalari production'da qolmaydi; image hajmi keskin kichrayadi (tez deploy, kam xavf).
  • Intervyu/ish — 2026da har backend e'lonida "Docker Compose" talab qilinadi (lokal dev va kichik deploy standarti).

2. Nazariya — chuqur tushuntirish

2.1. Compose nima va qaysi muammoni hal qiladi

text
  MUAMMO: real ilova = KO'P konteyner (qo'lda boshqarish og'ir):

  $ docker network create mynet
  $ docker run -d --name db --network mynet \
      -e POSTGRES_PASSWORD=secret -v pgdata:/var/lib/postgresql/data postgres:17
  $ docker run -d --name redis --network mynet redis:7-alpine
  $ docker run -d --name app --network mynet -p 3000:3000 \
      -e DATABASE_URL=... -e REDIS_URL=... myapp:1.0
  $ docker run -d --name nginx --network mynet -p 80:80 -v ...:/etc/nginx nginx
   uzun, tartib muhim, yodda saqlash qiyin, har safar qayta yozish

  YECHIM: COMPOSE — hammasini BITTA faylga (compose.yaml) yoz:

  $ docker compose up -d         butun tizim BIR buyruqda ko'tariladi
  $ docker compose down          hammasini to'xtatib, tozalaydi
   deklarativ (NIMA kerakligini yozasan, QANDAY emas)
   Git'da saqlanadi (takrorlanadigan)
   tarmoq/tartib avtomatik

Docker Compose — ko'p konteynerli ilovani bitta YAML faylda ta'riflab, bir buyruq bilan boshqaradigan vosita. Muammo aniq: real ilova bir nechta konteynerdan iborat (10.3: 2.8 — networking), va ularni qo'lda docker run bilan ko'tarish — uzun, tartibga bog'liq, takrorlash qiyin. Compose deklarativ: siz nima kerakligini yozasiz (qaysi servislar, qanday sozlamalar, qanday bog'lanish), Docker esa qanday qilishni o'zi hal qiladi. Butun tizim compose.yaml faylida — uni Git'ga qo'shasiz, va har kim (siz, jamoadosh, CI server) aynan bir xil tizimni ko'taradi. Tarmoq, ishga tushirish tartibi, ma'lumot saqlash — hammasi bitta faylda. Compose ayniqsa lokal development va kichik/o'rta production uchun ideal (katta miqyos uchun — Kubernetes, 10.8).

2.2. compose.yaml anatomiyasi (services, networks, volumes)

text
  COMPOSE.YAML — uchta asosiy yuqori darajadagi (top-level) blok:

  services:               ASOSIY: har bir konteyner (app, db, redis...)
    app:                  servis nomi (= tarmoqda hostname — 2.4)
      build: .            yoki image: myapp:1.0
      ports: ["3000:3000"]
    db:
      image: postgres:17
      volumes: [pgdata:/var/lib/postgresql/data]

  networks:               (ixtiyoriy) maxsus tarmoqlar
    backend:              Compose avtomatik default ham yaratadi 2.4-bob

  volumes:                named volume'lar (DB ma'lumoti — 2.5)
    pgdata:               Docker boshqaradigan doimiy saqlash

   FAYL NOMI: compose.yaml (zamonaviy) yoki docker-compose.yml (eski, hali ishlaydi)
   "version:" — ESKIRGAN (obsolete) — endi YOZMA (2026)

compose.yaml anatomiyasi — uchta asosiy yuqori darajadagi blokdan iborat: services (eng muhimi — har bir konteyner shu yerda: app, db, redis, nginx; har birining nomi bor), networks (ixtiyoriy — maxsus tarmoqlar, lekin Compose default tarmoqni avtomatik yaratadi — 2.4), volumes (named volume'lar — DB ma'lumoti uchun, 2.5). Fayl nomi: zamonaviy standart — compose.yaml (compose-spec rasmiy nomi), lekin eski docker-compose.yml ham hali ishlaydi (orqaga moslik). Eng muhim 2026 o'zgarish: yuqoridagi eski version: "3.8" qatori endi eskirgan (obsolete) — uni umuman yozmang, Compose o'zi eng yangi spetsifikatsiyani ishlatadi (yozsangiz ogohlantirish chiqaradi). YAML — bo'shliqqa sezgir (indentatsiya muhim, tab emas, probel).

2.3. Service ta'rifi (image vs build, ports, environment, env_file)

text
  HAR SERVIS — bir konteynerni ta'riflaydi (asosiy atributlar):

  services:
    app:
      build: .                   Dockerfile'dan QUR (o'z kodimiz)
      # YOKI: image: myapp:1.0    tayyor image (registry'dan)
      ports:
        - "3000:3000"            XOST:KONTEYNER (10.3: 2.8)
      environment:               muhit o'zgaruvchilari (inline)
        - NODE_ENV=production
        - DATABASE_URL=postgres://db:5432/app
      env_file:                  yoki fayldan (ko'p o'zgaruvchi — 2.7)
        - .env
      restart: unless-stopped    yiqilsa qayta yoq (10.1: 2.6)

   build (o'z ilovamiz) vs image (tayyor: postgres, redis, nginx)
   environment USTUN turadi env_file ustidan (override)

Service ta'rifi — har bir servis bitta konteynerni ta'riflaydi. Asosiy atributlar: image — tayyor image (postgres:17, redis:7, nginx — registry'dan olinadi) yoki build — Dockerfile'dan qurish (o'z ilovamiz uchun: build: . — joriy papkadagi Dockerfile). Qoida: boshqalarning servisi (DB, Redis, Nginx) image; o'z ilovang build. ports — port mapping ("3000:3000" — XOST:KONTEYNER, 10.3: 2.8). environment — muhit o'zgaruvchilari to'g'ridan-to'g'ri (inline). env_file — o'zgaruvchilarni fayldan o'qish (.env — ko'p o'zgaruvchi uchun qulay, 2.7). restart — qayta ishga tushirish siyosati (unless-stopped, always, on-failure — 10.1: 2.6 systemd'dagi g'oya). Ustunlik: environment qiymati env_file dagini ustidan yozadi (override). YAML ro'yxat (-) yoki map (KEY: value) shaklida yozish mumkin.

2.4. Tarmoq — Compose avtomatik network va DNS

text
  COMPOSE — barcha servislarga BITTA default tarmoq yaratadi (avtomatik):

  ┌─────────────────────────────────────────────────┐
  │  DEFAULT NETWORK (loyiha nomi + "_default")      │
  │                                                  │
  │   ┌────────┐    ┌────────┐    ┌────────┐         │
  │   │  app   │───►│   db   │    │ redis  │         │
  │   └────────┘    └────────┘    └────────┘         │
  │                                                  │
  │  SERVIS NOMI = HOSTNAME (Docker ichki DNS):      │
  │   app  db'ga: host=db, port=5432 (IP KERAK EMAS)│
  │   app  redis'ga: host=redis, port=6379          │
  └─────────────────────────────────────────────────┘

  DATABASE_URL=postgres://user:pass@db:5432/mydb
                                    └─ servis NOMI (db), localhost EMAS!

   Maxsus tarmoq (networks:) — servislarni AJRATISH uchun (2.10)

Tarmoq — Compose'ning eng kuchli qulayligi. Compose avtomatik ravishda barcha servislar uchun bitta default tarmoq yaratadi (nomi: loyiha + _default). Eng muhim natija: servis nomi = hostname. Docker ichki DNS orqali har bir servis boshqasini nomi bilan topadi — IP manzil kerak emas (10.3: 2.8 — qo'lda docker network create qilgan ishni Compose o'zi bajaradi). Masalan app servisi db servisiga ulanmoqchi bo'lsa, ulanish manzili: postgres://db:5432 — bu yerda db — servis nomi (localhost emas! chunki DB boshqa konteynerda, localhost o'sha konteynerning o'zini bildiradi). Redis uchun: redis://redis:6379. Eng keng tarqalgan xato — localhostga ulanish (Xato 5). Maxsus tarmoqlar (networks: bloki) servislarni bir-biridan ajratish uchun ishlatiladi (masalan DB faqat backend tarmoqda — 2.10).

2.5. Volume — named volume (DB ma'lumoti)

text
  MUAMMO: konteyner o'chsa — ichidagi ma'lumot YO'QOLADI (10.3: 2.7)
   "docker compose down" qilsang — DB ma'lumoti ham ketadimi?

  YECHIM: NAMED VOLUME — Docker boshqaradigan doimiy saqlash:

  services:
    db:
      image: postgres:17-alpine
      volumes:
        - pgdata:/var/lib/postgresql/data    named volume  DB papkasi
                                            #  └─ konteyner ICHIDA DB shu yerda

  volumes:                 top-level: named volume'ni e'lon qil
    pgdata:                Docker o'zi joylashtiradi (/var/lib/docker/volumes)

   "docker compose down"      konteyner o'chadi, VOLUME QOLADI 
   "docker compose down -v"   volume ham O'CHADI (ehtiyot bo'l — DB ketadi!)

Volume — DB ma'lumotini saqlash uchun majburiy. Muammo (10.3: 2.7): konteyner o'chsa, ichiga yozilgan ma'lumot yo'qoladi — docker compose down qilganda DB ma'lumoti ham ketib qolmasin. Yechimnamed volume: servis ichida volumes: - pgdata:/var/lib/postgresql/data (volume nomi konteyner ichidagi DB papkasi), va top-level volumes: blokida pgdatani e'lon qilasiz. Docker volume'ni o'zi joylashtiradi (/var/lib/docker/volumes) va konteyner o'chsa ham saqlab qoladi. Juda muhim farq: docker compose down — konteynerlarni o'chiradi, lekin volume qoladi (DB ma'lumoti saqlanadi — qayta up qilganda joyida). docker compose down -v — volume'larni ham o'chiradi (DB ma'lumoti butunlay ketadi — ehtiyot bo'l, faqat toza boshlash kerak bo'lganda ishlat). Bind mount (xost papkasi) — dev/config uchun, named volume — DB uchun (10.3: 2.7).

2.6. depends_on va ishga tushish tartibi (healthcheck nega kerak)

text
  MUAMMO: app DB'dan oldin ko'tarilsa  ulanolmaydi (DB hali tayyor emas):

  depends_on:
    - db               FAQAT TARTIB: db AVVAL ishga tushadi
                      #   LEKIN "ishga tushdi" ≠ "TAYYOR" (qabul qilishga)!
                      #     Postgres jarayoni boshlandi, lekin hali init qilyapti

   DB jarayoni boshlanishi bilan ulanishni qabul qilmaydi (bir necha sekund init)
      app darrov ulanmoqchi  "connection refused"  app yiqiladi

  YECHIM: HEALTHCHECK + condition (DB HAQIQATAN tayyorligini kut):

  services:
    db:
      image: postgres:17-alpine
      healthcheck:                               DB sog'ligini tekshir (10.3: 2.5)
        test: ["CMD-SHELL", "pg_isready -U app"]   qabul qilishga tayyormi?
        interval: 5s
        timeout: 3s
        retries: 5
    app:
      depends_on:
        db:
          condition: service_healthy     db HEALTHY bo'lguncha KUT, keyin app

depends_on va ishga tushish tartibi — eng ko'p adashtiradigan mavzu. Oddiy depends_on: - db faqat tartibni belgilaydi: db appdan avval ishga tushadi. Lekin "ishga tushdi" (started) ≠ "tayyor" (ready): PostgreSQL konteyneri ko'tariladi, jarayon boshlanadi, lekin u bir necha sekund initsializatsiya qiladi (ma'lumotlar bazasini sozlash) va shu paytda ulanishni qabul qilmaydi. Agar app darrov ulanmoqchi bo'lsa — connection refused xatosi ilova yiqiladi. Yechimhealthcheck + condition: DB servisiga healthcheck qo'yasiz (pg_isready — Postgres ulanishga tayyormi tekshiradigan buyruq, 10.3: 2.5), va appda depends_onni uzun shaklda yozasiz: condition: service_healthy — bu appni DB healthy bo'lgunicha kuttiradi. Condition turlari: service_started (faqat ishga tushdi — default), service_healthy (healthcheck o'tdi — DB uchun shu kerak), service_completed_successfully (servis ishini tugatib chiqdi — masalan migratsiya/seed). Production'da DB'ga bog'liq servis doim service_healthy ishlatishi kerak.

2.7. env va .env fayl (interpolatsiya)

text
  IKKI XIL ".env" ROLI — chalkashtirma:

  1) HOST .env — Compose O'ZI o'qiydi (compose.yaml ichida ${...} bilan):
     # .env (compose.yaml yonida)
     POSTGRES_PASSWORD=secret
     APP_PORT=3000

     # compose.yaml — ${...} bilan interpolatsiya:
     services:
       db:
         environment:
           POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}    .env'dan o'qiladi
       app:
         ports: ["${APP_PORT}:3000"]                  .env'dan

  2) SERVIS env_file — KONTEYNER ichiga uzatiladi (ilova o'qiydi):
     services:
       app:
         env_file: [.env]       .env'dagi HAMMA o'zgaruvchi konteynerga

   ${VAR}  compose.yaml'ni to'ldiradi ;  env_file  konteynerga beradi
   .env hech qachon Git'ga TUSHMASIN (.gitignore) — maxfiy (10.11)

.env va interpolatsiya — ikki xil rol bor, ko'pchilik chalkashtiradi. (1) Host .env — Compose o'zi o'qiydi: compose.yaml ichida ${VAR} yozsangiz, Compose o'sha qiymatni compose.yaml yonidagi .env faylidan oladi (interpolatsiya — matnni qiymat bilan to'ldirish). Bu yashirin sozlamalarni (parol, port) faylga olib chiqib, compose.yamlni umumiy qilishga imkon beradi. (2) Servis env_file — fayldagi o'zgaruvchilarni konteyner ichiga uzatadi (ilovaning o'zi process.envdan o'qiydi — 5.8). Farqni yodda tuting: ${VAR}compose.yaml matnini to'ldiradi (Compose darajasi); env_file — konteynerga o'zgaruvchi beradi (ilova darajasi). Compose default'da .env faylni avtomatik o'qiydi (${...} uchun). Xavfsizlik: .env (maxfiy parollar) hech qachon Git'ga tushmasin.gitignorega qo'shing, o'rniga .env.example (bo'sh shablon) qo'ying (10.11 — secrets boshqaruvi).

2.8. profiles (servislarni shartli yoqish)

text
  PROFILES — ba'zi servislarni FAQAT kerak bo'lganda yoqish:

  services:
    app:
      build: .                     har doim ishlaydi (profil yo'q)
    db:
      image: postgres:17           har doim

    pgadmin:
      image: dpage/pgadmin4
      profiles: [debug]            FAQAT "debug" profil yoqilsa ishlaydi

    seeder:
      build: .
      command: npm run seed
      profiles: [tools]            FAQAT "tools" yoqilsa

  ISHLATISH:
  docker compose up                           app + db (profilsizlar)
  docker compose --profile debug up           + pgadmin
  COMPOSE_PROFILES=debug,tools docker compose up    bir nechta profil

   Profilsiz servis — DOIM ishlaydi; profilli — faqat yoqilganda

profiles — ba'zi servislarni faqat kerak bo'lganda yoqish mexanizmi. Servisga profiles: [debug] qo'ysangiz — u faqat debug profil yoqilganda ishga tushadi; oddiy docker compose upda e'tiborga olinmaydi. Qoida: profilsiz servis doim ishlaydi (app, db); profilli servis faqat profil aktivlashtirilganda. Yoqish: docker compose --profile debug up yoki COMPOSE_PROFILES=debug docker compose up (bir nechta — vergul bilan: debug,tools). Bu nimaga foydali? Bir xil compose.yamlda: asosiy servislar (app, db) + faqat developmentda kerak bo'ladigan qo'shimchalar — pgAdmin (DB ko'rish), seeder (test ma'lumot to'ldirish), debug vositalari. Production'da ularni ko'tarmaysiz, dev'da --profile bilan yoqasiz. Bu — bitta fayl bilan turli muhitlarni boshqarishning toza usuli (override bilan birga — 2.9).

2.9. override va bir nechta compose fayl (dev/prod)

text
  MUAMMO: dev va prod sozlamalari har xil (port, build vs image, volume):
   ikkita to'liq fayl saqlash — takror, sinxronlash qiyin

  YECHIM: BAZA + OVERRIDE (qatlamlab birlashtirish — merge):

  compose.yaml               BAZA (umumiy: servislar, tarmoq)
  compose.override.yaml      DEV qo'shimcha (avtomatik qo'shiladi)
  compose.prod.yaml          PROD qo'shimcha (qo'lda ko'rsatiladi)

  # compose.override.yaml (DEV — bind mount, hot-reload):
  services:
    app:
      build:
        target: dev           multi-stage'dagi dev bosqich 2.11-bob
      volumes:
        - ./src:/app/src      kod o'zgarishi darrov ko'rinsin (10.3: 2.7)
      command: npm run dev

  ISHLATISH:
  docker compose up                                   baza + override (DEV auto)
  docker compose -f compose.yaml -f compose.prod.yaml up    baza + PROD

Override va bir nechta fayl — dev va prod sozlamalarini boshqarishning toza usuli. Muammo: development (bind mount, hot-reload, debug portlar) va production (optimal image, restart siyosati) sozlamalari har xil; ikkita to'liq nusxa saqlash — takror va sinxronlash qiyin. Yechimbaza + override (qatlamlab birlashtirish, merge): compose.yaml (umumiy — servislar, tarmoq, volume) + compose.override.yaml (dev qo'shimchalari — Compose buni avtomatik qo'shadi) + compose.prod.yaml (prod — qo'lda ko'rsatiladi). Sehr: docker compose up deganingda Compose compose.yaml + compose.override.yamlni birlashtiradi (override baza ustiga "yopishtiriladi"). Production uchun esa override'ni o'tkazib, -f compose.yaml -f compose.prod.yaml bilan boshqa qatlamni qo'shasiz. Bu — DRY (takror yo'q): umumiy qism bir joyda, faqat farqlar override'da. -f bilan ko'rsatilgan fayllar tartib bo'yicha birlashadi (keyingisi oldingini ustidan yozadi).

2.10. networks bilan ajratish va scale

text
  TARMOQ AJRATISH — xavfsizlik (DB tashqi tarmoqdan ko'rinmasin):

  services:
    nginx:
      networks: [frontend]             faqat frontend tarmoqda
    app:
      networks: [frontend, backend]    IKKALA tarmoqda (ko'prik)
    db:
      networks: [backend]              faqat backend (nginx ko'rmaydi!)

  networks:
    frontend:
    backend:

   nginx db'ga to'g'ridan ulanolmaydi (alohida tarmoq) — XAVFSIZ
   app ikkala tarmoqda — o'rtada (10.1: 2.7 — least exposure)

  SCALE — bir servisning bir necha nusxasi (gorizontal):
  docker compose up --scale app=3      app'ning 3 nusxasi (Nginx oldida balanslar)
   scale uchun servisda qat'iy "ports" bo'lmasligi kerak (konflikt)

Tarmoq ajratish va scale — ikki ilg'or imkoniyat. Tarmoq ajratish (xavfsizlik): har bir servisni alohida tarmoqqa qo'yib, kim kim bilan gaplasha olishini cheklaysiz. Masalan nginxfrontend tarmoqda, dbbackend tarmoqda, appikkalasida (ko'prik). Natijada nginx to'g'ridan-to'g'ri dbga ulanolmaydi (alohida tarmoqlar) — bu xavfsizlik: agar Nginx buzilsa, DB undan himoyalangan (10.1: 2.7 — eng kam ochiqlik, faqat keraklisi ulansin). Scale — bir servisning bir necha nusxasini ko'tarish (gorizontal masshtablash — 9.9): docker compose up --scale app=3appning 3 nusxasi ishlaydi, Nginx (10.2 — load balancer) oldida yukni taqsimlaydi. Scale uchun servisda qat'iy ports bo'lmasligi kerak (3 nusxa bir xost portini band qila olmaydi — konflikt). Bu — Compose'ning chegarasi; haqiqiy auto-scaling/orkestratsiya uchun Kubernetes 10.8-bob.

2.11. MULTI-STAGE BUILD (build vs runtime bosqich)

text
  MUAMMO: build vositalari final image'da QOLADI (katta, xavfli):

  BITTA STAGE (10.3: Misol 10) — hammasi bitta image'da:
  - TypeScript kompilyator, @nestjs/cli, devDependencies, manba kod
  - npm run build  dist/ ; LEKIN build vositalari ham QOLADI  ~400 MB 

  MULTI-STAGE — IKKI bosqich, oxirgisiga FAQAT natija ko'chiriladi:

  # ── 1-BOSQICH: BUILDER (quradi — vositalar shu yerda) ──
  FROM node:22-alpine AS builder        "builder" deb NOMLAYMIZ
  WORKDIR /app
  COPY package*.json ./
  RUN npm ci                            HAMMA qaramlik (dev ham — build uchun)
  COPY . .
  RUN npm run build                     dist/ hosil bo'ladi

  # ── 2-BOSQICH: RUNTIME (faqat ishlatadi — toza, kichik) ──
  FROM node:22-alpine                   YANGI, toza image
  WORKDIR /app
  COPY package*.json ./
  RUN npm ci --omit=dev                 FAQAT production qaramlik
  COPY --from=builder /app/dist ./dist  faqat NATIJA (builder'dan) 
  USER node
  CMD ["node", "dist/main.js"]
   ~150 MB  (build vositalari YO'Q — final image'da kerak emas)

Multi-stage build — bu bobning eng kuchli texnikasi (10.3: 2.10da ishora qilingan). Muammo: bitta bosqichli Dockerfile'da (10.3: Misol 10) build vositalari final image'da qoladi — TypeScript kompilyator, @nestjs/cli, barcha devDependencies, manba kod. Ular faqat build paytida kerak (npm run build), lekin ishlayotgan konteynerga kerak emas (faqat tayyor dist/ kerak). Natijada image 400 MB — katta va xavfli (ko'p keraksiz fayl = katta attack surface). Yechimmulti-stage: bir nechta FROM ishlatib, image'ni bosqichlarga ajratasiz. Mexanizm: (1) builder bosqichiFROM ... AS builder deb nomlaysiz, unda hamma qaramlikni o'rnatib (npm ci — dev ham), kodni build qilasiz (dist/ hosil bo'ladi). (2) runtime bosqichiyangi, toza FROM bilan boshlanadi, faqat production qaramlik (npm ci --omit=dev) va eng muhimi COPY --from=builder /app/dist ./dist — builder bosqichidan faqat natijani ko'chiradi. Final image'ga faqat oxirgi bosqich kiradi — build vositalari butunlay tashlanadi. Natija: image hajmi bir necha barobar kichrayadi (400 MB 150 MB). Yana: --target=builder bilan faqat ma'lum bosqichgacha qurish mumkin (dev/debug/test uchun — 2.9, Misol 6b) — bosqichlar deps build test production shaklida bo'linsa, CI test bosqichigacha, deploy esa production bosqichigacha quradi 10.5-bob. Build tezligini oshirish uchun cache mount ishlatiladi: RUN --mount=type=cache,target=/root/.npm npm ci — bunda paket menejerining cache'i build'lar orasida saqlanadi, shu sabab keyingi build'da qaramliklar qayta yuklanmaydi (Misol 6b). Go/Rust uchun multi-stage yanada keskin: FROM scratch (bo'sh baza) ga faqat kompilyatsiya qilingan binar fayl ko'chiriladi (10 MB).

2.12. Compose vs Kubernetes (qisqacha)

text
  COMPOSE vs KUBERNETES — qachon qaysi biri:

  DOCKER COMPOSE:                    KUBERNETES (K8s):
  - 1 mashina (xost)                - KO'P mashina (klaster)
  - oddiy, bitta YAML               - murakkab (ko'p obyekt: Pod, Service...)
  - lokal dev + kichik prod        - katta production, miqyos 
  - qo'lda scale (--scale)          - AVTO-scale, self-healing, rolling update
  - bitta server yiqilsa — hammasi  - bir nuqta yiqilsa — qayta joylashtiradi

   Compose — boshlang'ich va o'rta loyiha uchun YETARLI (90% holat)
   Katta miqyos kerak bo'lganda — Kubernetes (TO'LIQ 10.8da)

Compose vs Kubernetes — ikkalasi ham konteyner orkestratsiyasi, lekin miqyosi har xil. Docker Composebitta mashinada (xost) ishlaydi, oddiy (bitta YAML), lokal development va kichik/o'rta production uchun ideal; scale qo'lda (--scale). Kubernetes (K8s) — ko'p mashinali klaster: murakkab (ko'p obyekt turi — Pod, Service, Deployment), lekin avto-scaling, self-healing (yiqilgan konteynerni avtomatik qayta ko'taradi), rolling update (uzilishsiz yangilash) beradi — katta production uchun. Muhim xulosa: boshlanish uchun Compose yetarli (holatlarning ~90%i — kichik/o'rta loyiha bitta serverda); Kubernetes faqat haqiqiy katta miqyos (yuzlab konteyner, ko'p server, yuqori mavjudlik) kerak bo'lganda. Ko'pchilik loyiha umrining oxirigacha Compose'da qoladi — murakkablikni vaqtidan oldin qo'shmang. Kubernetes'ga to'liq 10.8da kiramiz.

2.13. Resurs cheklovlari (memory/CPU limits) va container_name

text
  MUAMMO: bitta servis butun xost xotirasini "yeb" qo'yishi mumkin:
   memory leak yoki og'ir so'rov  RAM to'ladi  BOSHQA servislar ham yiqiladi
   "shovqinli qo'shni" (noisy neighbour): bir konteyner butun serverni cho'ktiradi

  YECHIM: har servisga RESURS chegarasini belgila (deploy.resources):

  services:
    app:
      build: .
      deploy:
        resources:
          limits:               QAT'IY chegara (bundan oshsa cheklanadi)
            cpus: "1.5"         eng ko'pi 1.5 CPU yadro
            memory: 512M        eng ko'pi 512 MB RAM (oshsa  OOM-kill)
          reservations:         KAFOLATLANGAN minimum (band qilib qo'yiladi)
            cpus: "0.25"
            memory: 128M
    db:
      image: postgres:17-alpine
      deploy:
        resources:
          limits:
            memory: 1G          DB'ga ko'proq (256 MB shared_buffers + ish)

   "deploy.resources.limits" — Compose v2'da (docker compose) SWARM'siz ham
     hurmat qilinadi (eski holatda faqat Swarm'da ishlardi — endi lokal ham)
   ESKI muqobil (hali ishlaydi): mem_limit: 512m, cpus: 1.5 (top-level, deploy'siz)

Resurs cheklovlari — production'da majburiy himoya. Muammo: standart holatda konteyner xost resurslarini (RAM, CPU) cheklovsiz ishlatadi — bitta servisda xotira sizishi (memory leak) yoki og'ir so'rov butun serverning RAM'ini to'ldirishi mumkin, natijada boshqa barcha servislar ham yiqiladi (bu "noisy neighbour" — shovqinli qo'shni muammosi). Yechim — har servisga deploy.resources orqali chegara: limits — qat'iy shift (memory: 512M — bundan oshsa konteyner OOM-kill qilinadi; cpus: "1.5" — CPU vaqti cheklanadi), reservations — kafolatlangan minimum (Docker shu resursni o'sha servisga band qilib qo'yadi). Muhim nuance: deploy.resources.limits ilgari faqat Docker Swarmda ishlar edi, lekin zamonaviy docker compose (v2) uni oddiy upda ham hurmat qiladi. Eski muqobil hali qo'llab-quvvatlanadi: mem_limit: 512m va cpus: 1.5 (top-level, deploysiz). container_name — konteynerga qat'iy nom berish (container_name: my-app): standart holatda Compose nom generatsiya qiladi (loyiha-app-1), aniq nom debug'ni osonlashtiradi, lekin scale 2.10-bob bilan ziddiyatli (uch nusxa bir xil nomga ega bo'lolmaydi) — shu sabab miqyoslanadigan servisda ishlatmang.


3. Sintaksis — tez ma'lumotnoma

text
ASOSIY 2.1-bob: docker compose up -d | docker compose down | docker compose down -v
HOLAT: docker compose ps             servislar holati
       docker compose logs -f app    jonli loglar (-f = follow)
       docker compose top            jarayonlar
QURISH: docker compose build         image'larni qur | --no-cache (toza)
        docker compose up --build    qurib + ishga tushir
BOSHQARISH: docker compose stop | start | restart | rm
ICHIGA KIRISH: docker compose exec app sh    ishlayotgan servisga (10.3: Misol 6)
               docker compose run app npm test   yangi vaqtinchalik konteynerda
SCALE 2.10-bob: docker compose up --scale app=3
PROFIL 2.8-bob: docker compose --profile debug up | COMPOSE_PROFILES=debug ...
FAYL 2.9-bob: docker compose -f compose.yaml -f compose.prod.yaml up

YAML KALITLAR (2.3-6): services | image/build | ports | environment | env_file
  volumes | depends_on(condition) | healthcheck(test,interval,retries) | networks
  restart | profiles | command | container_name  ;  top-level: networks, volumes
RESURS 2.13-bob: deploy.resources.limits(cpus, memory) / reservations | mem_limit
MULTI-STAGE 2.11-bob: FROM x AS builder | COPY --from=builder /src /dst | --target=x
  CACHE MOUNT (Misol 6b): RUN --mount=type=cache,target=/root/.npm npm ci

4. Batafsil kod namunalari

Misol 1 — Oddiy compose.yaml (app + postgres)

yaml
# compose.yaml — eng oddiy ikki servisli ilova (app + DB)
#  "version:" yozMA — eskirgan (2.2)

services:
  app:
    build: .                      # joriy papkadagi Dockerfile'dan qur (2.3)
    ports:
      - "3000:3000"               # XOST:KONTEYNER (10.3: 2.8)
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgres://app:secret@db:5432/mydb   #  host=db (servis nomi — 2.4)
    depends_on:
      - db                        # db AVVAL ishga tushadi (lekin tartib ≠ tayyor — 2.6)

  db:
    image: postgres:17-alpine     # tayyor image (registry — 2.3)
    environment:
      - POSTGRES_USER=app
      - POSTGRES_PASSWORD=secret
      - POSTGRES_DB=mydb
    volumes:
      - pgdata:/var/lib/postgresql/data   # DB ma'lumoti named volume'da (2.5)

volumes:
  pgdata:                         # named volume'ni e'lon qil (2.5)

Misol 2 — env_file bilan (sozlamalarni faylga ajratish — 2.7)

yaml
# compose.yaml — sozlamalar .env faylda (compose.yaml umumiy bo'lib qoladi)
services:
  app:
    build: .
    ports:
      - "${APP_PORT}:3000"        # ${...}  host .env'dan interpolatsiya (2.7)
    env_file:
      - .env                      # .env'dagi HAMMA o'zgaruvchi konteynerga (2.7)
    depends_on:
      - db

  db:
    image: postgres:17-alpine
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}   # ${...}  host .env'dan
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:
bash
# .env (compose.yaml yonida —  .gitignore'ga qo'sh, Git'ga tushmasin — 10.11)
APP_PORT=3000
POSTGRES_PASSWORD=secret
DATABASE_URL=postgres://app:secret@db:5432/mydb
#  .env.example (bo'sh shablon) — bu Git'ga tushadi (jamoaga namuna)

Misol 3 — healthcheck + depends_on condition (DB tayyorligini kut — 2.6)

yaml
# compose.yaml — app DB HAQIQATAN tayyor bo'lgunicha kutadi (connection refused yo'q)
services:
  app:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      db:
        condition: service_healthy   #  db HEALTHY bo'lgunicha KUT (2.6)
      redis:
        condition: service_started   # redis faqat ishga tushsa kifoya

  db:
    image: postgres:17-alpine
    environment:
      - POSTGRES_PASSWORD=secret
    healthcheck:                                  # DB sog'ligini tekshir (10.3: 2.5)
      test: ["CMD-SHELL", "pg_isready -U postgres"]  # qabul qilishga tayyormi?
      interval: 5s                                # har 5s tekshir
      timeout: 3s                                 # 3s javob bermasa — fail
      retries: 5                                  # 5 marta fail  unhealthy
      start_period: 10s                           # dastlabki 10s grace (init uchun)
    volumes:
      - pgdata:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine

volumes:
  pgdata:

Misol 4 — To'liq stack: Nginx + app + db (real production tuzilma)

yaml
# compose.yaml — Nginx (oldida)  app  db (+redis): to'liq real stack
services:
  nginx:
    image: nginx:1.27-alpine
    ports:
      - "80:80"                   #  FAQAT Nginx tashqariga ochiq (80/443)
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro   # config (bind mount, ro=faqat o'qish)
    depends_on:
      - app
    networks:
      - frontend

  app:
    build: .
    environment:
      - DATABASE_URL=postgres://app:secret@db:5432/mydb   # host=db (2.4)
      - REDIS_URL=redis://redis:6379                       # host=redis (2.4)
    depends_on:
      db:
        condition: service_healthy   # DB tayyor bo'lgunicha kut (2.6)
    networks:
      - frontend                  # Nginx bilan (tashqi)
      - backend                   # db/redis bilan (ichki)
    #  app'da "ports" YO'Q — tashqariga ochilmaydi, Nginx orqali kiriladi

  db:
    image: postgres:17-alpine
    environment:
      - POSTGRES_USER=app
      - POSTGRES_PASSWORD=secret
      - POSTGRES_DB=mydb
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 5s
      retries: 5
    volumes:
      - pgdata:/var/lib/postgresql/data
    networks:
      - backend                   #  faqat ichki — Nginx ko'rmaydi (2.10)

  redis:
    image: redis:7-alpine
    networks:
      - backend

volumes:
  pgdata:

networks:
  frontend:                       # Nginx  app
  backend:                        # app  db/redis (ajratilgan — xavfsiz — 2.10)

Misol 5 — Multi-stage Dockerfile: Node build prod (2.11)

dockerfile
# Dockerfile — multi-stage: build vositalari final image'da QOLMAYDI
# syntax=docker/dockerfile:1

# ─────────── 1-BOSQICH: BUILDER (quradi) ───────────
FROM node:22-alpine AS builder         #  "builder" deb nomlaymiz (2.11)
WORKDIR /app
COPY package*.json ./
RUN npm ci                             # HAMMA qaramlik (devDeps ham — build kerak)
COPY . .
RUN npm run build                      # dist/ hosil bo'ladi (TSJS yoki bundler)

# ─────────── 2-BOSQICH: RUNTIME (faqat ishlatadi) ───────────
FROM node:22-alpine                    # YANGI, toza image (build vositalari yo'q)
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev && \             # FAQAT production qaramlik (10.3: 2.10)
    npm cache clean --force            # cache tozalash (bitta layer)
COPY --from=builder /app/dist ./dist   #  builder'dan FAQAT natija (2.11)
USER node                              # non-root (10.3: 2.11)
EXPOSE 3000
CMD ["node", "dist/main.js"]           # exec shakl (10.3: 2.6)
#  Natija: ~150 MB (bitta stage ~400 MB o'rniga) — build vositalari TASHLANDI

Misol 6 — Multi-stage NestJS (TypeScript build — 8.1)

dockerfile
# Dockerfile — NestJS uchun multi-stage (nest build  dist/)
# syntax=docker/dockerfile:1

FROM node:22-alpine AS builder         # build bosqichi
WORKDIR /app
COPY package*.json ./
RUN npm ci                             # @nestjs/cli, TS, devDeps — build uchun
COPY . .
RUN npm run build                      # "nest build"  dist/ (7.1, 8.1)

FROM node:22-alpine                    # toza runtime bosqichi
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev                  # faqat production (TS/cli QOLMAYDI)
COPY --from=builder /app/dist ./dist   # faqat kompilyatsiya natijasi
USER node
EXPOSE 3000
CMD ["node", "dist/main.js"]
#  @nestjs/cli (~katta), TypeScript, manba kod — final image'da YO'Q
#    Faqat dist/ (JS) + production node_modules  kichik, xavfsiz

Misol 6b — Cache mount + target (build tezligi va uch bosqich — 2.11)

dockerfile
# Dockerfile — cache mount (npm cache'ni layer'lar orasida saqlab, build TEZlashadi)
# + uch bosqich: deps  build  test  production
# syntax=docker/dockerfile:1

# ─── 1) DEPS: qaramliklarni cache mount bilan o'rnat ───
FROM node:22-alpine AS deps
WORKDIR /app
COPY package*.json ./
#  --mount=type=cache: npm'ning global cache'i BUILD'lar orasida saqlanadi
#     keyingi build'da paketlar qayta yuklanmaydi (tarmoqsiz, tez)
RUN --mount=type=cache,target=/root/.npm \
    npm ci

# ─── 2) BUILD: kompilyatsiya (deps'dan node_modules olib) ───
FROM node:22-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build                      # dist/ hosil bo'ladi

# ─── 3) TEST: alohida bosqich (CI shu bosqichgacha quradi — 10.5) ───
FROM build AS test
RUN npm run test                       # test o'tmasa — build TO'XTAYDI

# ─── 4) PRODUCTION: toza runtime (test'ni chetlab, faqat natija) ───
FROM node:22-alpine AS production
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci --omit=dev                  # cache mount bu yerda ham tezlashtiradi
COPY --from=build /app/dist ./dist     # faqat natija (test bosqichi chetda qoladi)
USER node
EXPOSE 3000
CMD ["node", "dist/main.js"]

#  TARGET bilan istalgan bosqichgacha qurish mumkin:
#    docker build --target test .         faqat test bosqichgacha (CI)
#    docker build --target production .   final (default: oxirgi bosqich)
#    docker build --target build .        dev/debug (dist/ + devDeps ichida)

Misol 7 — compose.override (dev) va prod fayl (2.9)

yaml
# compose.yaml — BAZA (umumiy, har ikki muhitda bir xil)
services:
  app:
    build:
      context: .
      target: builder            # multi-stage'dagi bosqich (2.11, 2.9)
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres:17-alpine
    environment:
      - POSTGRES_PASSWORD=secret
    healthcheck:
      test: ["CMD-SHELL", "pg_isready"]
      interval: 5s
    volumes:
      - pgdata:/var/lib/postgresql/data
volumes:
  pgdata:
yaml
# compose.override.yaml — DEV (avtomatik qo'shiladi — 2.9)
services:
  app:
    ports:
      - "3000:3000"              # dev'da to'g'ridan ochiq (Nginx yo'q)
    volumes:
      - ./src:/app/src           # bind mount — hot-reload (10.3: 2.7)
    command: npm run start:dev   # watch rejim
    environment:
      - NODE_ENV=development
bash
docker compose up                 # baza + override (DEV — avtomatik)
docker compose -f compose.yaml -f compose.prod.yaml up -d   # baza + PROD (2.9)

Misol 8 — networks bilan ajratish (xavfsizlik — 2.10)

yaml
# compose.yaml — db backend tarmoqda (tashqi/nginx tarmog'idan ko'rinmaydi)
services:
  nginx:
    image: nginx:1.27-alpine
    ports: ["80:80"]
    networks: [frontend]         # faqat frontend
  app:
    build: .
    networks: [frontend, backend]   # ko'prik (ikkalasida — 2.10)
  db:
    image: postgres:17-alpine
    environment: [POSTGRES_PASSWORD=secret]
    networks: [backend]          #  faqat backend — nginx to'g'ridan ulanolmaydi
    volumes: [pgdata:/var/lib/postgresql/data]

networks:
  frontend:                      # nginx  app
  backend:                       # app  db (ajratilgan)
volumes:
  pgdata:

Misol 9 — profiles (dev vositalari — 2.8)

yaml
# compose.yaml — pgAdmin va seeder faqat kerak bo'lganda (profil bilan)
services:
  app:
    build: .                     # profilsiz — DOIM ishlaydi
    depends_on: [db]
  db:
    image: postgres:17-alpine
    environment: [POSTGRES_PASSWORD=secret]

  pgadmin:
    image: dpage/pgadmin4
    ports: ["5050:80"]
    profiles: [debug]            # faqat "debug" profilda (2.8)
    environment:
      - PGADMIN_DEFAULT_EMAIL=admin@admin.com
      - PGADMIN_DEFAULT_PASSWORD=admin

  seeder:
    build: .
    command: npm run seed        # DB'ni test ma'lumot bilan to'ldir
    depends_on:
      db:
        condition: service_healthy
    profiles: [tools]            # faqat "tools" profilda
bash
docker compose up                          # app + db (profilsizlar)
docker compose --profile debug up          # + pgadmin (DB ni brauzerda ko'rish)
docker compose --profile tools run seeder  # seed'ni bir marta ishlatish

Misol 10 — docker compose buyruqlari to'plami (kundalik ish oqimi)

bash
# === KO'TARISH / TO'XTATISH ===
docker compose up -d                 # butun stack'ni FONDA ko'tar (-d = detached)
docker compose up --build            # avval image'larni qayta qur, keyin ko'tar
docker compose down                  # to'xtatib, konteyner/tarmoqni o'chir (volume QOLADI)
docker compose down -v               #  volume ham o'chir (DB KETADI — ehtiyot — 2.5)

# === HOLAT / LOG (debug — 10.3: Misol 6) ===
docker compose ps                    # servislar holati (Up? healthy?)
docker compose logs -f app           # app servisining JONLI loglari (-f = follow)
docker compose logs --tail 50        # barcha servis, oxirgi 50 qator

# === ICHIGA KIRISH ===
docker compose exec app sh           # ishlayotgan app konteynerga kir (10.3: Misol 6)
docker compose exec db psql -U app mydb   # DB'ga to'g'ridan (psql — 6.6)
docker compose run app npm test      # YANGI vaqtinchalik konteynerda test

# === QURISH / TOZALASH ===
docker compose build --no-cache app  # app image'ni toza qayta qur (cache'siz)
docker compose restart app           # faqat app'ni qayta ishga tushir
docker compose config                # yakuniy birlashgan compose'ni ko'r (override + baza)

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

1) Servisga ulanish manzili (DNS — 2.4)

text
 DATABASE_URL=postgres://localhost:5432/db (localhost = o'sha konteyner!)
 DATABASE_URL=postgres://db:5432/db (db = servis nomi — Compose DNS)

2) DB tayyorligi (depends_on — 2.6)

text
 depends_on: [db] (faqat tartib — DB hali init qilyapti  connection refused)
 depends_on: { db: { condition: service_healthy } } + healthcheck

3) DB ma'lumotini saqlash (2.5)

text
 db servisida volume yo'q (down/up qilsa — ma'lumot YO'QOLADI)
 volumes: [pgdata:/var/lib/postgresql/data] + top-level volumes (named)

4) version maydoni (2.2)

text
 version: "3.8" (eskirgan — obsolete, ogohlantirish chiqaradi)
 to'g'ridan "services:" dan boshla (version YO'Q — 2026)

5) Maxfiy ma'lumot (2.7)

text
 parol/kalit to'g'ridan compose.yaml'da + Git'ga push (sir tarqaydi)
 .env faylda (${VAR}) + .gitignore'da .env (10.11)

6) Image hajmi (multi-stage — 2.11)

text
 bitta stage: build vositalari (TS, cli) final image'da (~400 MB)
 multi-stage: COPY --from=builder /app/dist (faqat natija — ~150 MB)

7) Tashqariga ochiq portlar (2.10)

text
 db'da ports: ["5432:5432"] (DB internetdan ko'rinadi — xavf)
 db portsiz, faqat backend tarmoqda; tashqariga faqat Nginx (80/443)

6. Keng tarqalgan xatolar va yechimlari

Xato 1 — App DB'ga ulanolmaydi: connection refused / ECONNREFUSED

Sababi: depends_on: [db] faqat tartibni beradi — DB konteyneri ko'tarildi, lekin hali initsializatsiya qilyapti va ulanishni qabul qilmaydi 2.6-bob. Yechimi: DB'ga healthcheck (pg_isready) qo'shing, app'da depends_on: { db: { condition: service_healthy } } yozing (Misol 3). Ilovada ham qayta urinish (retry) mantig'i foydali.

Xato 2 — App localhostga ulanmoqchi bo'lib topolmaydi

Sababi: ilova DATABASE_URL=...localhost:5432ni ishlatyapti, lekin DB boshqa konteynerdalocalhost app konteynerining o'zini bildiradi 2.4-bob. Yechimi: manzilni servis nomiga o'zgartiring: db:5432 (Compose DNS — 2.4). Lokal kompyuterdan ulansangiz localhost, konteynerlar orasida — servis nomi.

Xato 3 — docker compose down dan keyin DB ma'lumoti yo'qoldi

Sababi: down -v ishlatilgan (volume o'chadi), yoki DB servisida named volume umuman yo'q edi 2.5-bob. Yechimi: named volume qo'shing (Misol 1); oddiy to'xtatishda down (-vsiz) ishlating — volume qoladi. -v faqat butunlay toza boshlash kerak bo'lganda.

Xato 4 — version is obsolete ogohlantirishi

Sababi: compose.yamlda eski version: "3.x" qatori bor (2026da eskirgan — 2.2). Yechimi: version: qatorini butunlay o'chiring — faylni to'g'ridan services: dan boshlang.

Xato 5 — port is already allocated / bind: address already in use

Sababi: portsdagi xost porti (masalan 3000) boshqa jarayon/konteyner tomonidan band (10.3: Xato 5). Yechimi: docker compose ps va ss -tulpn (10.1: 2.7) bilan kim band qilganini toping; eski stack'ni docker compose down bilan to'xtating; yoki boshqa xost port bering ("3001:3000").

Xato 6 — ${VAR} qiymati bo'sh / interpolatsiya ishlamayapti

Sababi: .env fayli compose.yaml yonida emas, yoki o'zgaruvchi nomi noto'g'ri, yoki bo'sh 2.7-bob. Yechimi: .envni compose.yaml yoniga qo'ying; docker compose config bilan yakuniy qiymatlarni tekshiring (interpolatsiya natijasini ko'rsatadi). Default berish: ${VAR:-default}.

Xato 7 — Build cache ishlamay, har safar to'liq qayta quriladi

Sababi: Dockerfile tartibi noto'g'ri (COPY . . npm cidan oldin), yoki --no-cache doim ishlatilyapti (10.3: 2.3, Xato 2). Yechimi: cache-optimal tartib (package fayllar avval — 10.3: Misol 1); multi-stage'da ham har bosqichda shu qoida. --no-cache faqat zarur bo'lganda.

Xato 8 — COPY --from=builder "not found" yoki bo'sh

Sababi: bosqich nomi noto'g'ri (AS builder deb nomlanmagan), yoki manba yo'l xato (builder'da dist/ boshqa joyda — 2.11). Yechimi: FROM ... AS builder nomini tekshiring; builder'da WORKDIR /app va RUN npm run build dist/ ni qayerga chiqarganini aniqlang; COPY --from=builder /app/dist ./dist yo'llari mos kelsin.


7. Integratsiya — bu mavzu stack'ning qayerida uchraydi

  • Docker 10.3-bob: Compose — docker runlarni avtomatlashtiradi; servis build Dockerfile'dan; multi-stage — Dockerfile texnikasi.
  • Nginx 10.2-bob: Compose'da nginx servisi — app oldida reverse proxy; config bind mount bilan.
  • Linux server 10.1-bob: restart siyosati systemd g'oyasi 2.6-bob; tarmoq ajratish — least exposure 2.7-bob.
  • CI/CD 10.5-bob: GitHub Actions multi-stage image quradi, docker composeni serverda ishlatadi.
  • AWS 10.6-bob: Compose lokal/kichik server uchun; katta miqyosda ECS/EKS.
  • PostgreSQL/MongoDB (6.x): db servisi + named volume; pg_isready healthcheck.
  • Redis 5.21-bob: redis servisi — cache/sessiya; app redis://redis:6379 bilan ulanadi.
  • NestJS 8.1-bob: multi-stage build (nest build dist/ — Misol 6); env config 8.14-bob.
  • Secrets 10.11-bob: .env Git'dan tashqarida; ${VAR} interpolatsiya; secret boshqaruvi.
  • Kubernetes 10.8-bob: Compose'dan keyingi qadam — katta miqyos orkestratsiyasi 2.12-bob.

8. Eng yaxshi amaliyotlar (best practices)

  • version: yozma (eskirgan — to'g'ridan services: — 2.2).
  • Servis nomi bilan ulan (db:5432, localhost emas — Compose DNS — 2.4).
  • DB'ga healthcheck + service_healthy (depends_on tartibi yetarli emas — 2.6).
  • DB ma'lumoti named volume'da (downda yo'qolmasin; -vdan ehtiyot — 2.5).
  • Multi-stage build (build vositalari final image'da qolmasin — 2.11).
  • Tarmoq ajratish (DB faqat backend tarmoqda; tashqariga faqat Nginx — 2.10).
  • .env + ${VAR} (maxfiy ma'lumot fayl/Git'dan tashqarida — 2.7, 10.11).
  • restart: unless-stopped (server qayta yuklansa servis o'zi ko'tarilsin — 2.3).
  • override bilan dev/prod (umumiy baza + farqlar override'da — DRY — 2.9).
  • docker compose config (deploy oldidan yakuniy birlashgan faylni tekshir — Misol 10).
  • profiles (dev vositalari pgAdmin/seeder — production'da ko'tarilmasin — 2.8).
  • Resurs cheklovi (production'da deploy.resources.limits — bitta servis butun serverni cho'ktirmasin — 2.13).
  • Cache mount (build tezligi uchun --mount=type=cache — qaramliklar qayta yuklanmasin — Misol 6b).
  • Aniq image tag (postgres:17-alpine, latest emas — barqaror — 10.3: 2.11).

9. Amaliy loyiha: "To'liq Stack'ni Compose bilan Orkestrlash"

NestJS (yoki Express) ilovasini PostgreSQL, Redis va Nginx bilan birga bitta compose.yaml orqali ko'tarish — har bir backendchining kundalik ko'nikmasi.

Maqsad

10.3da Dockerlashtirgan ilovangni endi to'liq stack sifatida ishga tushir: app + PostgreSQL (volume bilan) + Redis + Nginx (oldida), hammasi compose.yamlda, multi-stage build bilan kichik image, healthcheck bilan to'g'ri tartib, va dev/prod uchun override.

Talablar (requirements)

  1. compose.yaml: app (build), db (postgres:17-alpine), redis (redis:7-alpine), nginx servislari — version: siz (Misol 1, 4, 2.2).
  2. Multi-stage Dockerfile: builder (build) + runtime (toza) bosqichlar; image ~150 MB (Misol 5/6, 2.11).
  3. Networking: app DB'ni nomi bilan topsin (db:5432, redis:6379 — 2.4).
  4. Named volume: Postgres ma'lumoti pgdata volume'da — down/upda saqlansin (Misol 1, 2.5).
  5. healthcheck + condition: db'ga pg_isready, app condition: service_healthy bilan kutsin (Misol 3, 2.6).
  6. env_file: parol/URL .envda, ${VAR} interpolatsiya; .env .gitignoreda, .env.example Git'da (Misol 2, 2.7).
  7. Tarmoq ajratish: db/redis faqat backend tarmoqda; tashqariga faqat Nginx (80) (Misol 8, 2.10).
  8. Nginx: reverse proxy app oldida (config bind mount); app portssiz (Misol 4, 10.2).
  9. override: compose.override.yaml (dev — bind mount, hot-reload) + compose.prod.yaml (Misol 7, 2.9).
  10. profiles: pgadmin (debug profil) — DB'ni brauzerda ko'rish uchun (Misol 9, 2.8).

Maslahatlar (hint)

  • appda ports qo'ymang (Nginx orqali kiriladi) — faqat dev override'da ochiq (2.10, Misol 7).
  • DB'ga ulanish manzili localhost emas, db (servis nomi) — eng keng xato (2.4, Xato 2).
  • depends_on: [db] yetarli emas — healthcheck + service_healthy (aks holda connection refused — 2.6, Xato 1).
  • docker compose config bilan override birlashganini va ${VAR} to'lganini tekshiring (Misol 10, Xato 6).
  • docker compose down (volume qoladi) vs down -v (DB ketadi) farqini esda tuting (2.5, Xato 3).
  • Image hajmini solishtiring: bitta stage vs multi-stage (docker images — 2.11).

"Tayyor" mezonlari (acceptance criteria)

  • docker compose up -d butun stack'ni (app+db+redis+nginx) bir buyruqda ko'taradi.
  • http://localhost (Nginx, 80) orqali ilova javob beradi (app'ga to'g'ridan kirilmaydi).
  • App DB va Redis'ni nomi bilan topadi (ulanish ishlaydi).
  • docker compose down so'ng up qilinganda DB ma'lumoti saqlanib qoladi (volume).
  • App DB tayyor bo'lguncha kutadi (connection refused yo'q — healthcheck).
  • .env Git'da yo'q; compose.yamlda ochiq parol yo'q.
  • db/redis tashqariga ochiq emas (docker compose ps — faqat Nginx porti).
  • Multi-stage image bitta stage'dan sezilarli kichik (docker images).
  • docker compose --profile debug up pgAdmin'ni qo'shadi.
  • dev (up) va prod (-f ... -f compose.prod.yaml) har xil sozlama bilan ishlaydi.

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


10. Xulosa va keyingi bobga ko'prik

Bu bobda ko'p konteynerli ilovani boshqarishni va image hajmini optimallashtirishni o'rgandik:

  • Compose nima (ko'p konteyner muammosi — 2.1); compose.yaml anatomiyasi (services/networks/volumes — 2.2); service ta'rifi (image vs build, ports, env — 2.3).
  • Tarmoq (avtomatik DNS — servis nomi = hostname — 2.4); named volume (DB ma'lumoti — 2.5); depends_on + healthcheck (DB tayyorligi — 2.6); env/.env (interpolatsiya — 2.7).
  • profiles (shartli servis — 2.8); override (dev/prod — 2.9); networks ajratish + scale 2.10-bob; multi-stage build (kichik image, cache mount, target — 2.11); Compose vs Kubernetes 2.12-bob; resurs cheklovlari (limits/reservations — 2.13).

Endi siz butun tizimni — ilova, DB, Redis, Nginx — bitta faylga yozib, bir buyruqda ko'tara olasiz, va multi-stage bilan production image'ni bir necha barobar kichraytirasiz. Bu — lokal development va kichik/o'rta deploy'ning markaziy ko'nikmasi.

Keyingi bob — 10.5-bob: CI/CD (GitHub Actions) — pipeline, avtomatik test/deploy. Hozir image quramiz va Compose bilan qo'lda ko'taramiz. Lekin har o'zgarishda qo'lda test qilish, image qurish, registry'ga push qilish, serverga ulanib deploy qilish — bu takror va xatoga moyil. CI/CD buni avtomatlashtiradi: kod Git'ga push qilinishi bilan GitHub Actions o'zi testlarni ishga tushiradi, multi-stage image quradi, registry'ga yuboradi va serverda docker composeni yangilaydi — odam aralashuvisiz. Bu — zamonaviy jamoaviy ishlab chiqishning yuragi.


Foydalanilgan rasmiy/ishonchli manbalar

  • Docker Docs — "Docker Compose overview" (docs.docker.com/compose — services/networks/volumes, docker compose v2 CLI, 2026)
  • Docker Docs — Compose file reference / compose-spec (services, depends_on condition, healthcheck, env_file, profiles; version obsolete — docs.docker.com/reference/compose-file)
  • Docker Docs — "Multi-stage builds" (FROM ... AS, COPY --from, --target — docs.docker.com/build/building/multi-stage)
  • Docker Docs — "Use Compose profiles" va override/merge (docs.docker.com/compose/how-tos/profiles, multiple-compose-files)
  • Compose Specification (compose-spec.io) — rasmiy spetsifikatsiya (2026)

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
10.4-bob: Docker Compose va multi-stage build — Wisar