Asosiy kontentga o‘tish

Maqolalar 7 daqiqa 35 ko‘rish

Docker Compose: «menda ishlayapti-ku» muammosini butunlay yopish

Jamoadagi eng ko‘p eshitiladigan ibora — «menda ishlayapti-ku». Docker Compose butun development muhitini bitta faylga yozadi. Postgres va Redis'ni bir buyruq bilan ko‘taramiz va yo‘l-yo‘lakay uchraydigan tuzoqlarni ko‘ramiz.

devops backend

Mundarija

Har bir jamoada bir kun kelib aytiladigan ibora bor: "menda ishlayapti-ku". Kimningdir kompyuterida hammasi joyida, boshqasida esa yo‘q. Sabab ko‘pincha muhitda bo‘ladi: birida PostgreSQL 15, boshqasida 17; birida Redis o‘rnatilgan, boshqasida yo‘q. Har kim o‘z kompyuterini qo‘lda sozlagani uchun ular bir-biridan sekin-asta uzoqlashib boradi.

Docker Compose aynan shu muammoni yechadi. G‘oyasi oddiy: butun development muhitini — ilova qanday xizmatlarga tayanadi, qaysi versiyada — bitta faylga yozib qo‘yasiz. Bu fayl repozitoriyda turadi, demak jamoaning hamma a'zosida bir xil. Yangi odam kelganda u bir buyruq beradi va bir necha daqiqada hamma bilan aynan bir xil muhitga ega bo‘ladi.

docker-compose.yml faylini yozamiz#

Faraz qilaylik, ilovamizga PostgreSQL va Redis kerak. Loyiha ildizida docker-compose.yml fayl ochamiz:

YAML
services:
  db:
    image: postgres:17-alpine
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: app
      POSTGRES_PASSWORD: app
    ports:
      - "5432:5432"
    healthcheck:
      # baza haqiqatan so'rovga tayyor bo'ldimi — shuni tekshiradi
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 5s
      timeout: 3s
      retries: 5

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

Bu faylda ikkita xizmat tasvirlangan: db va redis. Har biriga aniq versiya ko‘rsatilgan (17-alpine, 7-alpine) — bu muhim, chunki aynan shu jamoadagi hammada bir xil versiya bo‘lishini kafolatlaydi.

Bir buyruq bilan ko‘taramiz#

Endi bitta buyruq — va butun muhit tayyor:

Terminal
docker compose up -d      # xizmatlarni fon rejimida ko'taradi

Holatini ko‘rish, loglarni kuzatish va to‘xtatish uchun yana bir necha buyruq bor:

Terminal
docker compose ps          # qaysi xizmat ishlab turibdi
docker compose logs -f db  # baza loglarini jonli kuzatish
docker compose down        # hammasini to'xtatish

Birinchisining javobi shunday ko‘rinadi:

Natija
SERVICE   STATUS
db        Up 13 seconds (healthy)
redis     Up 18 seconds

db yonidagi (healthy) — bu yuqorida yozgan healthcheck ning natijasi. redis da bunday yozuv yo‘q, chunki unga tekshiruv qo‘ymadik: Compose uning faqat ishlab turganini biladi, javob berishga tayyor-tayyor emasligini emas.

up -d ni bir marta bergan yangi jamoa a'zosi PostgreSQL'ni qo‘lda o‘rnatish, versiya moslashtirish yoki "menda boshqacha chiqyapti" bilan umuman shug‘ullanmaydi. Hammasi faylda yozilgan va u hamma uchun bir xil ishlaydi.

Yo‘l-yo‘lakay uchraydigan uch tuzoq#

Compose bilan ishlashda bir necha holat boshda savol tug‘diradi, ularni oldindan aytib qo‘yaman.

Ma'lumot yo‘qolib qolishi. docker compose down dan keyin up bersangiz, bazadagi jadvallaringiz yo‘q bo‘lib qoladi. Buni o‘zingiz sinab ko‘rishingiz mumkin: jadval yarating, down qiling, up qiling va o‘sha jadvalni so‘rang — ERROR: relation "t" does not exist javobini olasiz.

Bu yerda nozik bir narsa bor va uni bilib qo‘ygan ma'qul. Ma'lumot aslida o‘chib ketmaydi. PostgreSQL obrazi o‘zi uchun anonim volume yaratadi, down esa uni o‘chirmaydi — u diskda qolaveradi, lekin nomi tasodifiy bo‘lgani uchun keyingi up uni topa olmaydi va o‘ziga yangisini yaratadi. Ya'ni siz ma'lumotni yo‘qotasiz va shu bilan birga diskda hech kimga kerak bo‘lmagan volume to‘planib boradi. Ularni docker volume ls bilan ko‘rish, docker compose down -v bilan esa konteyner bilan birga o‘chirish mumkin.

Yechim — volume'ga nom berish. U holda down dan keyin ham keyingi up o‘sha joyni topadi:

YAML
services:
  db:
    # ... yuqoridagi sozlamalar ...
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:          # e'tibor bering: bu services bilan bir darajada
  pgdata:

Endi o‘sha sinovni takrorlasangiz, down/up dan keyin jadvalingiz ham, ichidagi qatorlar ham joyida turadi.

Port band bo‘lishi. Agar kompyuteringizda allaqachon PostgreSQL 5432 portida ishlab tursa, Compose xizmatini ko‘targanda port to‘qnashuvi xatosi chiqadi. Yechim — tashqi portni o‘zgartirish:

YAML
    ports:
      - "5433:5432"   # kompyuterda 5433, konteyner ichida 5432

Endi ilovangiz bazaga 5433 port orqali ulanadi va lokal PostgreSQL bilan to‘qnashmaydi. Aynan shu sayt ham development'da shunday sozlangan.

Ilova bazadan oldin ishga tushishi. Ilova ko‘tarilib, bazaga ulanmoqchi bo‘ladi-yu, baza hali tayyor emas — birinchi ulanish xato bilan yiqiladi. Bu yerda ko‘pchilik bir xil xatoga yo‘l qo‘yadi: depends_on yozadi va ish bitdi deb o‘ylaydi.

YAML
  app:
    depends_on:
      - db        # bu YETARLI EMAS

Bunday yozilganda Compose faqat db konteyneri ishga tushishini kutadi, uning javob berishga tayyor bo‘lishini emas. Natija shunday bo‘ladi:

Natija
app-1  | psql: error: connection to server at "db" (172.21.0.2), port 5432 failed: Connection refused

Aynan shu uchun yuqoridagi faylda healthcheck bor: u bazaning haqiqatan so‘rovga tayyor bo‘lishini tekshiradi. Ilovani esa o‘sha tekshiruvga bog‘lash kerak — depends_on ning uzun shakli bilan:

YAML
  app:
    depends_on:
      db:
        condition: service_healthy

Endi Compose avval db sog‘lom deb belgilanishini kutadi, keyin ilovani ishga tushiradi:

Natija
 Container myapp-db-1  Healthy
app-1  | ILOVA-ULANDI

Ilova bazaga qaysi manzil bilan ulanadi#

Yuqoridagi xato xabarida bitta muhim tafsilot bor: ilova bazaga db degan nom bilan murojaat qilyapti, localhost bilan emas. Bu boshida ko‘pchilikni chalkashtiradi, shuning uchun alohida aytib qo‘yaman — manzil ilovaning qayerda ishlashiga qarab ikki xil bo‘ladi.

Agar ilova ham Compose ichida, alohida xizmat sifatida ishlasa, u bazani xizmat nomi orqali topadi va konteyner ichidagi portga ulanadi:

postgres://app:app@db:5432/app

Agar ilovani o‘z kompyuteringizda (masalan uv run manage.py runserver bilan) ishga tushirsangiz, db degan nom sizga hech narsa demaydi — uni faqat Docker tarmog‘i biladi. U holda localhost va ports: da ko‘rsatilgan tashqi port ishlatiladi:

postgres://app:app@localhost:5433/app

Shu saytning .env.example faylida aynan ikkinchi variant turadi, chunki Compose faqat bazani ko‘taradi, Django esa to‘g‘ridan-to‘g‘ri kompyuterda ishlaydi. Xato xabari ham shu ikkitasini ajratishga yordam beradi: "could not translate host name db" — demak siz konteyner nomini konteyner tashqarisidan ishlatyapsiz.

Development va production#

Bu maqoladagi sozlama development uchun — ya'ni o‘z kompyuteringizda ishlash uchun. Aynan shu sayt ham lokal ishlab chiqishda docker compose up -d db bilan Postgres ko‘taradi. Production'da esa Docker biroz boshqacha ishlatiladi: u yerda parollar ochiq yozilmaydi, portlar tashqariga chiqarilmaydi va butun tuzilma xavfsizlik nuqtai nazaridan qattiqroq sozlanadi. Lekin g‘oya bir xil bo‘lib qoladi — muhitni qo‘lda emas, faylda tasvirlash.

7 daqiqa 35 marta o‘qildi