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.
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:
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:
docker compose up -d # xizmatlarni fon rejimida ko'taradi
Holatini ko‘rish, loglarni kuzatish va to‘xtatish uchun yana bir necha buyruq bor:
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:
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:
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:
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.
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:
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:
app:
depends_on:
db:
condition: service_healthy
Endi Compose avval db sog‘lom deb belgilanishini kutadi, keyin ilovani
ishga tushiradi:
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.