6-bo‘lim
CMD, ENTRYPOINT va PID 1
Exec va shell shakllari, ENTRYPOINT bilan CMD farqi, konteynerdagi 1-jarayon va signallar.
Ushbu bo‘lim mundarijasi
2-bobda docker stop 137 kodini qaytarganini ko'rgan edik. Endi
sababini oxirigacha tushunamiz - va bu yo'lda ko'p tarqalgan bitta
noto'g'ri tushunchani ham to'g'rilaymiz.
Ikki yozuv shakli #
CMD va ENTRYPOINT ni ikki xil yozish mumkin:
CMD ["sleep", "300"] # exec shakl - JSON massiv
CMD sleep 300 # shell shakl - oddiy matn
Shell shaklda Docker buyruqni /bin/sh -c ga uzatadi. Exec shaklda
esa dasturni to'g'ridan-to'g'ri ishga tushiradi.
Birinchi farq: o'zgaruvchilar #
Shell shakl qobiq orqali o'tgani uchun o'zgaruvchi kengayadi:
docker run --rm kengay-shell
shell shakl: dokon
Exec shaklda qobiq yo'q - demak kengaytiradigan ham yo'q:
docker run --rm kengay-exec
exec shakl: $NOM
$NOM matn bo'lib chiqdi. Bu juda ko'p uchraydigan xato.
CMD ["sh", "-c", "echo $NOM"]
Bu exec shakl, lekin ichida qobiq bor - demak kengayish ishlaydi va nima bo'layotgani ko'rinib turadi.
Ikkinchi farq: kim PID 1 bo'ladi? #
Ko'p qo'llanmada "shell shakl sh ni PID 1 qiladi" deyiladi. Buni
tekshiramiz.
Exec shakl:
docker run -d --name ka exec-shakl >/dev/null
sleep 1
docker exec ka ps -o pid,args | sed -n 2p
1 sleep 300
Shell shakl, bitta buyruq:
docker run -d --name kb shell-bitta >/dev/null
sleep 1
docker exec kb ps -o pid,args | sed -n 2p
1 sleep 300
Bir xil. Qobiq PID 1 bo'lib qolmadi.
Sababi: sh ning bajaradigan boshqa ishi qolmaganda, u yangi
jarayon yaratmasdan o'z o'rnini buyruqqa beradi (exec
optimizatsiyasi).
Endi qobiqning ishi qolsa nima bo'lishini ko'ramiz:
docker run -d --name kc shell-ikki >/dev/null
sleep 1
docker exec kc ps -o pid,args | sed -n 2p
docker exec kc ps -o args | sed -n 3p
1 /bin/sh -c sleep 300 && echo tugadi
sleep 300
Mana endi qobiq PID 1, sleep esa uning bolasi - alohida
jarayon. Chunki sleep tugagach echo ni bajarish kerak, demak
qobiq ketolmaydi va kutib turishga majbur.
(Bolaning PID raqami har safar boshqacha bo'lishi mumkin, shuning uchun ikkinchi buyruqda uni ko'rsatmadik.)
Bu qobiqqa va buyruqqa bog'liq. Alpine dagi busybox sh
oddiy holatda o'z o'rnini beradi, murakkab holatda esa qolib
ketadi.
Shuning uchun "shell shakl ishlatmang" degan qoidaga emas, natijani tekshirishga tayaning:
docker exec <konteyner> ps -o pid,args
PID 1 kimligini bir marta ko'rish yuzta maslahatdan foydaliroq.
PID 1 nega muhim? #
Chunki docker stop signalni faqat PID 1 ga yuboradi.
Uchala konteynerni to'xtatamiz:
for n in ka kb kc; do
docker stop $n >/dev/null
echo "$n: kod=$(docker inspect -f '{{.State.ExitCode}}' $n)"
done
ka: kod=137
kb: kod=137
kc: kod=137
Uchalasi ham 137 - va har biri 10 soniya kutdi. sleep SIGTERM
ni ushlamaydi, qobiq ham uni bolasiga uzatmaydi.
Endi signalni to'g'ri ushlaydigan skriptni ko'ramiz:
#!/bin/sh
trap 'echo "SIGTERM keldi, toza chiqamiz"; exit 0' TERM
echo "xizmat ishlayapti"
sleep 300 &
wait
FROM alpine:3.21
COPY boshla.sh /boshla.sh
CMD ["/boshla.sh"]
docker run -d --name toza toza-chiqish >/dev/null
sleep 1
docker stop toza >/dev/null
echo "kod: $(docker inspect -f '{{.State.ExitCode}}' toza)"
docker logs toza
kod: 0
xizmat ishlayapti
SIGTERM keldi, toza chiqamiz
Chiqish kodi 0, va bu deyarli bir zumda sodir bo'ldi - 10 soniya kutish bo'lmadi.
E'tibor bering: sleep 300 & fondan ishga tushirilgan va wait
kutayapti. Shunday yozilmasa, trap ishlamas edi - qobiq sleep
tugashini kutib turgan bo'lardi va signalni faqat undan keyin
ko'rar edi.
ENTRYPOINT va CMD birgalikda #
Ikkalasi ham bo'lsa, ular qo'shiladi: ENTRYPOINT - buyruq,
CMD - unga standart argument.
FROM alpine:3.21
ENTRYPOINT ["echo", "Salom,"]
CMD ["dunyo"]
docker run --rm salomla
Salom, dunyo
Buyruq satrida bergan argumentingiz CMD ni almashtiradi:
docker run --rm salomla Husanboy
Salom, Husanboy
ENTRYPOINT esa joyida qoldi. Uni almashtirish uchun alohida
bayroq kerak:
docker run --rm --entrypoint echo salomla "butunlay boshqa"
butunlay boshqa
Faqat CMD bo'lsa, u to'liq almashtiriladi:
docker run --rm exec-shakl echo "almashtirildi"
almashtirildi
| Nima kerak | Qanday yoziladi |
|---|---|
| Foydalanuvchi buyruqni almashtira olsin | Faqat CMD |
| Buyruq qat'iy, argument o'zgaruvchan | ENTRYPOINT + CMD |
| Obraz bitta vazifa uchun vosita | Faqat ENTRYPOINT |
Obraz xizmat bo'lsa (veb server, ishchi jarayon) -
ENTRYPOINT ga ishga tushirish skriptini, CMD ga esa standart
argumentlarni qo'ying.
Obraz vosita bo'lsa (masalan konvertor) - ENTRYPOINT ga
vositani qo'ying, shunda foydalanuvchi uni oddiy buyruqdek
ishlatadi:
docker run --rm mening-vositam --help
Zombi jarayonlar va --init #
PID 1 ning yana bir vazifasi bor: egasiz qolgan bolalarni yig'ish. Oddiy ilovalar buni qilmaydi.
docker run -d --name z1 zombi >/dev/null
sleep 1
docker exec z1 ps -o pid,args | sed -n 2p
1 sh -c sleep 300 & sleep 300 & wait
Endi --init bilan:
docker run -d --init --name z2 zombi >/dev/null
sleep 1
docker exec z2 ps -o pid,args | sed -n 2p
1 /sbin/docker-init -- sh -c sleep 300 & sleep 300 & wait
PID 1 endi docker-init - kichik, faqat shu ish uchun yozilgan
dastur. U signallarni uzatadi va zombi jarayonlarni yig'adi.
--init qachon kerak?Ilovangiz ko'p bola jarayon yaratsa va ularni o'zi kutmasa - konteynerda zombi jarayonlar to'planadi.
Belgisi: ps da <defunct> yoki Z holatidagi jarayonlar.
Yechim ikkita: --init ishlatish yoki ilovaga to'g'ri PID 1
kutubxonasini qo'shish (tini, dumb-init).
STOPSIGNAL #
Ba'zi dasturlar SIGTERM emas, boshqa signalni kutadi. Nginx
masalan SIGQUIT ni "muloyim to'xtash" deb tushunadi.
FROM alpine:3.21
STOPSIGNAL SIGINT
CMD ["sh", "-c", "trap 'echo INT keldi; exit 0' INT; sleep 300 & wait"]
docker run -d --name sig signalli >/dev/null
sleep 1
docker stop -t 5 sig >/dev/null
docker logs sig
echo "kod: $(docker inspect -f '{{.State.ExitCode}}' sig)"
INT keldi
kod: 0
docker stop endi SIGTERM emas, SIGINT yubordi.
Xulosa #
- Exec shakl (
["sleep","300"]) dasturni to'g'ridan-to'g'ri ishga tushiradi; shell shakl (sleep 300) uni/bin/sh -cga uzatadi. - Shell shaklda muhit o'zgaruvchisi kengayadi, exec shaklda
esa
$NOModdiy matn bo'lib qoladi. - "Shell shakl doim
shni PID 1 qiladi" - noto'g'ri: qobiq boshqa ishi qolmasa o'z o'rnini beradi. - Qobiq PID 1 bo'lib qoladigan holat - buyruqda
&&,;yoki quvur bo'lganda. - Muhimi shakl emas, PID 1 signalni ushlaydimi: uni
docker exec <konteyner> ps -o pid,argsbilan tekshiring. - SIGTERM ni ushlamaydigan PID 1 - 137 va 10 soniya kutish;
trapbilan to'g'ri yozilgani - 0 va bir zumda. - Fon jarayonini
&bilan ishga tushiribwaitqilish kerak, aks holdatrapsignalni o'z vaqtida ko'rmaydi. ENTRYPOINT+CMDqo'shiladi: birinchisi buyruq, ikkinchisi standart argument; buyruq satriCMDni almashtiradi.ENTRYPOINTni faqat--entrypointbayrog'i almashtiradi.--initkonteynerga to'g'ri PID 1 qo'shadi - zombi jarayonlar to'planganda kerak bo'ladi.
- Bir xil buyruqni exec va shell shaklda yozib,
psbilan PID 1 ni solishtiring. - Shell shaklga
&& echo tugadiqo'shib, PID 1 o'zgarishini kuzating. ENVo'zgaruvchisini ikkala shaklda chop etib, farqni ko'ring.- SIGTERM ni ushlamaydigan konteynerni to'xtatib, vaqtni o'lchang.
trapbilan to'g'ri yozilgan skript yarating va vaqtni yana o'lchang.ENTRYPOINTvaCMDni birga ishlatib, argument almashtiring.--entrypointbilan obraz buyrug'ini butunlay almashtiring.--initbilan va usiz PID 1 ni solishtiring.STOPSIGNALniSIGINTga o'zgartirib, natijani tekshiring.- O'z ilovangizda SIGTERM ishlovchisi bormi - tekshiring va bo'lmasa qo'shing.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.