Docker Compose exec ने interactive shell कसा उघडावा
चालू Compose service मध्ये shell उघडण्यासाठी docker compose exec वापरा. सेवा थांबलेली असल्यास किंवा तिला न छेडता काम करायचे असल्यास run --rm वापरा.
docker compose exec सह परस्परसंवादी shell मिळवा
docker compose exec web bash आधीपासून web सेवा म्हणून चालू असलेल्या कंटेनरमध्ये परस्परसंवादी shell उघडते. exec नंतरचे नाव हे तुमच्या compose.yaml मधील सेवा-नाव असते; ते कंटेनरचे नाव नसते. image मध्ये bash नसल्यास त्याऐवजी sh मागवा.
docker compose ps
docker compose exec web bashसर्वप्रथम docker compose ps चालवा. त्यात web ची स्थिती running असल्याचे दिसले पाहिजे. त्यानंतर दुसरी command तुम्हाला कंटेनरमधील prompt वर नेते. exit किंवा Ctrl-D दाबल्यावर तुम्ही host वर परतता. तुम्ही बाहेर पडल्यानंतरही सेवा चालू राहते, कारण exec ने मुख्य प्रक्रियेच्या बाजूला दुसरी process सुरू केलेली असते. तुमचा shell बंद केल्याने PID 1 (process id 1) वर परिणाम होत नाही. कंटेनर ज्या process साठी तयार केला आहे, तीच process PID 1 असते.
कंटेनरमध्ये जाण्याचे हे दोन मार्गांपैकी एक आहे. exec आधीपासून अस्तित्वात असलेल्या कंटेनरमध्ये प्रवेश करते. docker compose run त्याच service definition वरून नवीन कंटेनर तयार करते. या मार्गदर्शकातील जवळपास सर्व पुढील माहिती या एका फरकावर आधारित आहे.
Compose मध्ये -it ऐच्छिक का आहे, पण साध्या docker मध्ये ते आवश्यक का आहे
दोन flags सत्राचा interactive भाग नियंत्रित करतात. -i stdin उघडे ठेवतो, त्यामुळे तुम्ही टाइप केलेला मजकूर process पर्यंत पोहोचतो. -t pseudo terminal allocate करतो. त्याला TTY म्हणतात. त्यामुळे shell prompt दाखवतो आणि arrow keys हाताळतो. साधा docker exec हे दोन्ही flags default ने बंद ठेवतो. म्हणून तुम्ही पाहिलेल्या प्रत्येक उदाहरणात docker exec -it लिहिलेले आहे. docker compose exec हे दोन्ही flags तुमच्यासाठी सुरू करतो. त्यामुळे docker compose exec -it web bash आणि docker compose exec web bash यांचा परिणाम समान असतो. जुन्या वापराची सवय कायम राहावी म्हणून Compose -it देखील स्वीकारतो.
TTY उपलब्ध नसल्याचे काही सेकंदांत लक्षात येते. Shell चालतो, पण prompt दाखवत नाही आणि Ctrl-C process पर्यंत पोहोचत नाही. उलट परिस्थितीत, म्हणजे Compose ने TTY allocate करू नये असे सांगायचे असल्यास, त्यासाठी स्वतंत्र flag आणि पुढील भागात स्वतंत्र section आहे.
bash नसलेल्या image साठी काय करावे
Alpine-आधारित image कडे bash मागितल्यास exec अशा प्रकारे अयशस्वी होते:
OCI runtime exec failed: exec failed: unable to start container process: exec: "bash": executable file not found in $PATH: unknownहा संदेश exec मधील समस्या दर्शवत नाही. तुम्ही मागितलेली binary image मध्ये नाही, असे तो सांगतो. Alpine मध्ये BusyBox समाविष्ट असतो. तो ash ला /bin/sh म्हणून उपलब्ध करून देतो आणि bash मुळीच देत नाही. त्यामुळे sh मागा:
docker compose exec web sh-slim tags सह Debian आणि Ubuntu-आधारित images मध्ये bash उपलब्ध असतो. bash मुळे command history आणि अधिक चांगले completion मिळते. त्यामुळे प्रथम bash वापरून पाहा आणि अयशस्वी झाल्यास sh वापरा. sh जवळपास प्रत्येक general purpose image मध्ये उपलब्ध असतो.
काही images मध्ये कोणताही shell नसतो. Distroless images आणि FROM scratch तयार केलेल्या images मध्ये जाणीवपूर्वक application binary आणि तिच्या libraries शिवाय दुसरे काहीही ठेवलेले नसते. कारण उपलब्ध नसलेला shell तुमच्याविरुद्ध वापरता येत नाही. अशा images मध्ये sh त्याच संदेशासह अयशस्वी होते आणि प्रयत्न करण्यासाठी दुसरे काही उरत नाही. दोन पद्धती उपयोगी ठरतात. Google's distroless images मध्ये BusyBox shell जोडणारे :debug tags उपलब्ध असतात. त्यामुळे tag तात्पुरता बदलून तुम्ही image मध्ये प्रवेश करू शकता. किंवा target च्या namespaces मध्ये स्वतंत्र container सुरू करा:
CID=$(docker compose ps -q web)
docker run --rm -it --network "container:$CID" --pid "container:$CID" nicolaka/netshootआता netshoot ची tools application च्या network कडे निर्देशित आहेत. त्यामुळे curl localhost:8080 आणि ss -lntp तुम्ही application च्या आत असल्याप्रमाणे कार्य करतात. तुम्हाला दिसणारी filesystem netshoot ची आहे, app ची नाही. Process namespace shared असल्यामुळे तुम्ही root असताना ls /proc/1/root/ target च्या स्वतःच्या files पर्यंत पोहोचते.
सेवा चालू नसताना docker compose run --rm वापरा
exec साठी चालू कंटेनर आवश्यक असतो. थांबवलेल्या सेवेकडे निर्देश केल्यास ते नकार देते:
service "web" is not runningते तुमच्यासाठी काहीही सुरू करणार नाही. docker compose run हे काम करेल:
docker compose run --rm web bashrun web सेवा-व्याख्येवरून नवीन कंटेनर तयार करते. त्यात तीच image, environment, volumes आणि networks असतात. तुम्ही टाइप केलेल्या command ने ते सेवेची मूळ command बदलते. तुम्ही बाहेर पडल्यावर --rm तो कंटेनर हटवते. --rm वगळल्यास उरलेले कंटेनर myproject-web-run-4f1c2b सारख्या नावांखाली जमा होतात. docker compose ps -a ते दाखवेल, परंतु इतर कोणतीही प्रक्रिया त्यांची स्वच्छता करणार नाही.
run चे दोन वर्तन अनेकांना अनपेक्षित वाटते. तुम्ही --service-ports जोडल्याशिवाय ते सेवेचे ports publish करत नाही. हे जाणीवपूर्वक केलेले आहे. पहिला कंटेनर host port 8080 वापरत असताना दुसरा कंटेनर तोच port bind करण्याचा प्रयत्न करेल आणि bind: address already in use मुळे अपयशी ठरेल. तुमचा shell दिसण्यापूर्वी ते depends_on अंतर्गत सेवेने सूचीबद्ध केलेल्या सर्व सेवा सुरू करते. त्यामुळे फक्त आत पाहण्यासाठी केलेल्या प्रयत्नात database आणि cache सुरू होऊ शकतात. --no-deps हे टाळते.
run image च्या ENTRYPOINT मधून जाते, परंतु exec तसे करत नाही. exec विद्यमान कंटेनरमध्ये तुमची command थेट सुरू करते. त्यामुळे entrypoint script ला ती command दिसत नाही. run अंतर्गत तुमची bash त्या script कडे arguments म्हणून पोहोचते. अनेक अधिकृत images त्यांच्या entrypoint च्या शेवटी exec "$@" ठेवतात. त्यामुळे command थेट पुढे पाठवली जाते आणि तुमचा shell सुरू होतो. स्वतःचे arguments समजून घेणारी script त्यांच्यावर वेगळी प्रक्रिया करू शकते. अशा वेळी त्या एका run साठी entrypoint बदला:
docker compose run --rm --entrypoint sh webexec अंतर्गत चालणारी command run अंतर्गत वेगळी का वागते, याचे हे सर्वात सामान्य कारण आहे. command आणि entrypoint मधील विभाजन प्रत्येक वेळी image configuration च्या कोणत्या भागाची जागा तुम्ही घेत आहात हे स्पष्ट करते.
exec किंवा run: कोणता वापरायचा
- exec साठी container चालू असणे आवश्यक आहे. run साठी ते आवश्यक नाही आणि run dependencies सुरू करू शकतो.
- exec मध्ये सध्या चालू असलेली process list आणि त्या क्षणीच्या files दिसतात. सेवा सुरू झाल्यानंतर application ने लिहिलेल्या सामग्रीचाही त्यात समावेश असतो. run ला image ची स्वच्छ प्रत मिळते. त्यामुळे यापैकी काहीही त्यात उपलब्ध नसते.
- exec entrypoint वगळतो. run तो चालवतो.
--rmदिले नाही, तर run नंतर container शिल्लक ठेवतो.
प्रत्यक्षात काय घडत आहे हे पाहण्यासाठी exec वापरा. त्याच environment ची तात्पुरती प्रत, one-off migration command किंवा वास्तविक सेवा exec करण्याइतका वेळ चालू राहत नसेल, तर run --rm वापरा.
उपयुक्त exec flags: user, working directory आणि replicas
बहुतेक images non-root user वर switch होतात. त्यामुळे तुमच्या exec shell मध्ये diagnostic tool install करण्याचा प्रयत्न येथे थांबतो:
E: Could not open lock file /var/lib/dpkg/lock-frontend - open (13: Permission denied)-u root तुम्हाला त्याच container मध्ये root shell देते:
docker compose exec -u root web sh-w /srv/app फक्त त्या command साठी working directory सेट करते. -e KEY=value तुमच्या session मध्ये environment variable जोडते; service मध्ये नाही. एखादी service एकापेक्षा अधिक replica चालवत असेल, तर --index 2 तुम्ही कोणत्या container मध्ये प्रवेश कराल हे ठरवते. Mounted directory वरील file ownership चे कारण शोधत असल्यास, container images मधील PUID आणि PGID मध्ये numeric ids वापरकर्त्यांची नावे नव्हे, तर त्या directory मध्ये कोण लिहू शकते हे का ठरवतात, याचे स्पष्टीकरण दिले आहे.
डेटाबेस कंटेनरमध्ये psql किंवा mysql शेल मिळवा
क्लायंट आधीपासूनच डेटाबेस image मध्ये आहे. त्यामुळे host वर क्लायंट ठेवण्याची किंवा port publish करण्याची गरज नाही:
docker compose exec db psql -U postgres -d app
docker compose exec db mariadb -u root -pPostgres images मध्ये psql, MySQL images मध्ये mysql आणि MariaDB images मध्ये mariadb उपलब्ध असतात. Connection कंटेनरच्या आतून केला जातो. त्यामुळे compose file मध्ये कोणताही database port publish केलेला नसला तरी हे कार्य करते. ही अधिक सुरक्षित रचना आहे: publish न केलेल्या port पर्यंत इंटरनेटवरून कोणीही पोहोचू शकत नाही.
एका चुकीमुळे लोकांचा बराच वेळ वाया जातो. Docker ला command दिसण्यापूर्वीच तुमचा shell host वरील variables expand करतो. त्यामुळे एखादा variable फक्त कंटेनरमध्ये उपलब्ध असल्यास -U "$POSTGRES_USER" रिकामी string पाठवते. Single quotes आणि कंटेनरमधील shell वापरल्यास variable योग्य ठिकाणी expand होते:
docker compose exec db sh -c 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB"'येथे कोणत्याही command शिवाय docker compose run --rm db वापरू नका. त्यामुळे त्याच data volume वर दुसरा Postgres server सुरू होतो आणि तो सुरू होण्यास नकार देतो:
FATAL: lock file "postmaster.pid" already existsLock file योग्य प्रकारे काम करत आहे. एकाच data directory मध्ये दोन servers लिहिल्यास data corrupt होऊ शकतो. Database सुरू असताना चालू container मध्ये exec करा. Database Compose मध्ये ठेवायचा की नाही हा स्वतंत्र निर्णय आहे. Docker मध्ये किंवा host वर database चालवणे या पर्यायांमधील तडजोडी स्पष्ट करते.
स्टार्टअपच्या वेळी console आवश्यक असलेल्या सेवा: stdin_open आणि tty
exec आणि run ही commands तुम्ही manually उघडलेल्या shell साठी आहेत. मुख्य process स्वभावतः interactive असलेल्या सेवेसाठी compose file मध्ये दोन keys आवश्यक असतात:
services:
console:
image: python:3.12-slim
command: python
stdin_open: true
tty: truestdin_open: true हे docker run -i आहे आणि tty: true हे docker run -t आहे. या keys नसतील, तर container लगेच सुरू होऊन code 0 सह बंद होतो आणि docker compose ps -a मध्ये Exited (0) दिसते. काहीही crash झालेले नसते. stdin वर terminal नसताना python ला end of file त्वरित मिळतो आणि ते सामान्यपणे बंद होते. वापरकर्ता input देत नसलेल्या program साठी हेच योग्य वर्तन आहे.
दोन्ही keys set केल्यानंतर चालू process ला attach करा:
docker attach $(docker compose ps -q console)Ctrl-P आणि त्यानंतर Ctrl-Q दाबून detach करा. यामुळे process चालू राहतो. ही sequence फक्त container मध्ये TTY आणि stdin दोन्ही open असतील तेव्हाच कार्य करते. त्याऐवजी Ctrl-C दाबल्यास PID 1 ला interrupt पाठवला जातो आणि सेवा बंद होते.
सामान्य सेवांसाठी दोन्ही keys off ठेवा. Web server stdin कधीही वाचत नाही. तसेच tty: true मुळे अनेक programs वापरकर्ता output पाहत आहे असे समजून colour output आणि line buffering सुरू करतात. त्यामुळे docker compose logs मध्ये escape codes भरतात.
क्रॉन आणि CI मध्ये scripted exec का अयशस्वी होते: -T flag
तुमच्या terminal मध्ये चालणारी exec command cron job किंवा continuous integration (CI) runner मध्ये अयशस्वी होते:
the input device is not a TTYCompose डीफॉल्टनुसार pseudo terminal मागते. मात्र cron job ला terminal मिळत नाही. त्यामुळे तुमची command चालण्यापूर्वीच विनंती अयशस्वी होते. -T ही विनंती बंद करते:
0 3 * * * docker compose -f /srv/app/compose.yaml exec -T db pg_dump -U postgres -Fc app > /srv/backups/app.dump-T दुसऱ्या कारणासाठीही महत्त्वाचे आहे. TTY बाहेर जाताना byte stream चे रूपांतर करते. त्यामुळे TTY मधून जाणारा compressed dump खराब होऊन पोहोचतो. Redirect केलेल्या किंवा pipe केलेल्या output साठी -T आवश्यक आहे.
cron संदर्भातील आणखी दोन बाबी लक्षात ठेवा. -f absolute path सह द्या, कारण cron job home directory मधून चालवते. त्या directory मध्ये compose file नसते. त्यामुळे Compose no configuration file provided: not found दाखवून थांबते. तसेच exec ने चालवलेल्या command चा exit code exec परत करते. त्यामुळे pg_dump अयशस्वी झाल्यास set -e अंतर्गत तुमची script देखील अयशस्वी होते. रिकामा backup तयार करून यशस्वी झाल्याचे दाखवले जात नाही. दैनंदिन वापरातील उर्वरित commands Compose command cheat sheet मध्ये दिल्या आहेत. ती cheat sheet या scripts जवळ ठेवणे उपयुक्त ठरते.
कंटेनरमध्ये केलेले बदल का नाहीसे होतात
तुम्ही exec वापरून एखादे साधन install करता, configuration file संपादित करता, समस्या दूर करता आणि आठवड्यानंतर तो बदल नाहीसा झालेला दिसतो. कंटेनरचा writable layer अपेक्षेप्रमाणेच कार्य करत असतो. docker compose up -d image tag किंवा service definition मध्ये केलेल्या कोणत्याही बदलानंतर जुना कंटेनर नष्ट करून image पासून नवीन कंटेनर तयार करतो. त्यामुळे प्रत्येक हस्ते केलेला बदल जुन्या कंटेनरसह नाहीसा होतो.
docker compose restart यापेक्षा वेगळे आहे. ते त्याच कंटेनरला stop करून पुन्हा start करते. त्यामुळे हस्ते केलेले बदल टिकून राहतात. म्हणून एखादा manual fix काही आठवडे लागू असल्यासारखा दिसू शकतो आणि नंतर असंबंधित update दरम्यान नाहीसा होऊ शकतो. Named volumes आणि bind mounts या दोन्ही प्रक्रियांनंतर टिकून राहतात, कारण त्यांचा data कंटेनरच्या बाहेर साठवला जातो. Data टिकवून ठेवण्यासाठी कोणता पर्याय निवडावा हे bind mounts आणि named volumes येथे स्पष्ट केले आहे.
म्हणून exec shell चा वापर वाचण्यासाठी आणि चाचणी करण्यासाठी करा. Fix समजल्यानंतर तो टिकून राहील अशा ठिकाणी लिहा: package Dockerfile मध्ये आणि setting compose file मध्ये. त्यानंतर docker compose up -d वापरून ते लागू करा आणि नवीन कंटेनरमध्ये तो बदल प्रत्यक्षात आहे याची दुसऱ्या exec ने खात्री करा.
FAQ
docker compose exec आणि docker compose run यांच्यात काय फरक आहे?
exec आधीपासून सुरू असलेल्या कंटेनरमध्ये मुख्य प्रक्रियेच्या बाजूने command चालवते आणि image entrypoint वगळते. run त्याच service definition मधून, त्याच image, environment, volumes आणि networks सह नवीन कंटेनर तयार करते, तुमचा command entrypoint मधून पाठवते आणि प्रथम कोणत्याही depends_on services सुरू करते. --service-ports जोडले नाही, तर run service चे ports प्रकाशित करत नाही. Live service तपासण्यासाठी exec वापरा. Service थांबलेली असेल किंवा तिच्या कामात व्यत्यय आणायचा नसेल, तेव्हा run --rm वापरा.
docker compose exec service सुरू नाही असे का सांगते?
exec विद्यमान कंटेनरशी जोडते आणि नवीन कंटेनर तयार करू शकत नाही. त्यामुळे service थांबलेली किंवा crash झालेली असल्यास service "web" is not running मिळते. docker compose ps -a तपासा. हे Exited (1) सारख्या स्थितीसह exited containers ची यादी दाखवते. Service का थांबली हे जाणून घेण्यासाठी docker compose logs web वाचा. तरीही shell मिळवायचा असल्यास docker compose run --rm --entrypoint sh web चालवा. यामुळे त्याच service definition मधून नवीन कंटेनर तयार होतो आणि अयशस्वी start command चालू दिला जात नाही.
image मध्ये bash नसल्यास shell कसा उघडायचा?
docker compose exec web bash चालवताना exec: "bash": executable file not found in $PATH मिळत असल्यास image मध्ये bash उपलब्ध नाही. Alpine वर आधारित image साठी हे सामान्य आहे. docker compose exec web sh वापरा, कारण BusyBox /bin/sh उपलब्ध करून देते. Distroless आणि scratch images मध्ये कोणताही shell नसतो. त्यामुळे कोणतीही exec command कार्य करणार नाही. Publisher ने उपलब्ध करून दिल्यास image च्या :debug tag वर switch करा. अन्यथा docker run --rm -it --network "container:$CID" --pid "container:$CID" nicolaka/netshoot वापरून target च्या namespaces मध्ये debug container सुरू करा. येथे $CID हे docker compose ps -q web मधून येते.
cron मध्ये माझी exec command "the input device is not a TTY" या संदेशासह का अयशस्वी होते?
docker compose exec default ने pseudo terminal मागते, परंतु cron कोणतेही pseudo terminal देत नाही. त्यामुळे तुमचा command चालण्यापूर्वीच request अयशस्वी होते. ते बंद करण्यासाठी -T जोडा: docker compose exec -T db pg_dump -U postgres app. Redirect केलेल्या किंवा piped output साठीही -T वापरा, कारण TTY byte stream मध्ये बदल करते आणि binary dump खराब करू शकते. cron मध्ये compose file चा absolute path देऊन -f देखील pass करा. अन्यथा Compose no configuration file provided: not found सह exit होते.
exec वापरून कंटेनरमध्ये केलेले बदल restart नंतर टिकतात का?
समान कंटेनर पुन्हा वापरला जात असल्याने ते docker compose restart पर्यंत टिकतात. मात्र image किंवा configuration बदलल्यानंतर docker compose up -d वेळी ते नष्ट होतात. कारण त्या वेळी image मधून कंटेनर पुन्हा तयार केला जातो आणि त्याचा writable layer टाकून दिला जातो. Named volumes किंवा bind mounts मध्ये लिहिलेला data दोन्ही परिस्थितींमध्ये टिकतो, कारण तो कंटेनरच्या बाहेर साठवला जातो. Diagnostic बदल exec वापरून करा. कायमस्वरूपी आवृत्ती Dockerfile किंवा compose file मध्ये नोंदवा.