Docker Compose లో command vs entrypoint తేడా ఏమిటి?
ENTRYPOINT ప్రోగ్రామ్ను నడుపుతుంది, command దాని argumentsను అందిస్తుంది. Composeలోని నాలుగు override కలయికలు, entrypoint సెట్ చేస్తే CMD ఎందుకు తొలగుతుందో చూడండి.
Docker Compose command మరియు entrypoint: ఒకే నియమంలో
Docker Compose లో entrypoint: నడిచే ప్రోగ్రామ్ను నిర్దేశిస్తుంది. command: ఆ ప్రోగ్రామ్కు అందించే arguments ను నిర్దేశిస్తుంది. Container process అనేది entrypoint list కు command list చివర జోడించిన రూపం. ఈ పేజీలోని మిగతా ప్రవర్తన అంతా ఈ ఒక్క వాక్యం నుంచే వస్తుంది.
ఈ రెండు keys రెండు Dockerfile instructions కు అనుసంధానమై ఉంటాయి. entrypoint: image లోని ENTRYPOINT ను భర్తీ చేస్తుంది. command: image లోని CMD ను భర్తీ చేస్తుంది. ఇవి స్వతంత్రంగా పనిచేయవు. ఇక్కడే చాలామందికి సమస్య వస్తుంది: entrypoint: సెట్ చేస్తే image లోని CMD కూడా తొలగిపోతుంది. Compose specification దీన్ని స్పష్టంగా పేర్కొంటుంది. entrypoint non-null గా ఉంటే, image నుంచి వచ్చే default command ను Compose విస్మరిస్తుంది.
ఇమేజ్లో ఇప్పటికే నిర్వచించిన విషయాలను పరిశీలించండి
ఏదైనా override చేయడానికి ముందు, ఇమేజ్లో విడుదలైన నిర్వచనాలను పరిశీలించండి.
docker image inspect --format '{{json .Config.Entrypoint}}' postgres:16
docker image inspect --format '{{json .Config.Cmd}}' postgres:16మీకు ["docker-entrypoint.sh"] మరియు ["postgres"] కనిపిస్తాయి. అందువల్ల container docker-entrypoint.sh postgres ను నడుపుతుంది. ఆ script మొదటి boot సమయంలో data directoryని సృష్టిస్తుంది, POSTGRES_* variablesను చదువుతుంది, privilegesను postgres userకు తగ్గిస్తుంది, చివరగా దానికి అందించిన argumentsను exec చేస్తుంది. మీరు మార్చాలనుకుంటున్న భాగం ఏదో గుర్తించడం అత్యంత ముఖ్యమైన నిర్ణయం. Databaseకు flag పంపాలంటే command: ను replace చేయండి. entrypoint: ను replace చేస్తే, ఆ setupలో ఏదీ అమలు కాదు.
చిన్న చిత్రంలో చూపిన నాలుగు కలయికలు
ప్రారంభించినప్పుడు అందుకున్న argument list ను మాత్రమే ప్రింట్ చేసే పని ఉన్న image ను రూపొందించండి.
FROM alpine:3.20
ENTRYPOINT ["/bin/echo", "ep"]
CMD ["cmd"]docker build -t argdemo .services:
demo:
image: argdemoప్రతి మార్పు తర్వాత docker compose up ను అమలు చేసి, అది log చేసిన ఒక్క వరుసను చదవండి.
- ఏ key కూడా సెట్ చేయలేదు. Process
/bin/echo ep cmdగా ఉంటుంది, మరియు log లోep cmdకనిపిస్తుంది. command: ["cmd2"]మాత్రమే సెట్ చేశారు. Process/bin/echo ep cmd2గా ఉంటుంది. Entrypoint లో ఎలాంటి మార్పు ఉండదు; arguments మాత్రమే మారతాయి.entrypoint: ["/bin/echo", "ep2"]మాత్రమే సెట్ చేశారు. Process/bin/echo ep2గా ఉంటుంది, మరియు log లోep2కనిపిస్తుంది. Image లోనిcmdతొలగిపోతుంది; దీనిపై ఎలాంటి హెచ్చరిక కూడా కనిపించదు.- రెండు keys సెట్ చేశారు. Process
/bin/echo ep2 cmd2గా ఉంటుంది. మొత్తం argument list పై మీకు నియంత్రణ ఉండే ఏకైక సందర్భం ఇదే.
entrypoint సెట్ చేస్తే image CMD ఎందుకు తొలగిపోతుంది
ఒక image యొక్క CMD, ఆ image యొక్క ENTRYPOINT కు default argument list గా వ్రాయబడుతుంది. entrypoint ను మార్చినప్పుడు, ఆ arguments ఇక నడవని program కు సంబంధించినవిగా మారతాయి. అందువల్ల, image రచయిత ఉద్దేశించని command line ను నిర్మించకుండా Compose వాటిని తొలగిస్తుంది. docker run --entrypoint కూడా ఇదే విధంగా పనిచేస్తుంది. కాబట్టి ఇది Compose ప్రత్యేక ప్రవర్తన కాదు; ఇది Docker ప్రవర్తన.
దీని ప్రభావం స్పష్టంగా ఉంటుంది. nginx:1.27 లో ENTRYPOINT ["/docker-entrypoint.sh"] మరియు CMD ["nginx", "-g", "daemon off;"] నిర్వచించబడ్డాయి. entrypoint: /custom-init.sh సెట్ చేస్తే, మీ script ఖాళీ argument list తో ప్రారంభమవుతుంది. సాధారణంగా exec "$@" తో ముగిసే script కు exec చేయడానికి ఏదీ ఉండదు. అందువల్ల exec ఏ చర్యా చేయదు. script చివరి line కు చేరుతుంది. container code 0 తో, ఎక్కడా error message లేకుండా నిష్క్రమిస్తుంది. Arguments ను మీరే తిరిగి ఇవ్వండి:
services:
web:
image: nginx:1.27
entrypoint: /custom-init.sh
command: ["nginx", "-g", "daemon off;"]గుర్తుంచుకోవాల్సిన నియమం: మీరు entrypoint: సెట్ చేసిన ప్రతిసారి, అదే మార్పులో command: ఎలా ఉండాలో నిర్ణయించండి.
exec రూపం మరియు shell రూపం, అలాగే Compose ఎలా భిన్నంగా ఉంటుందో
Dockerfile రెండు syntax రూపాలను అంగీకరిస్తుంది. CMD ["nginx", "-g", "daemon off;"] exec రూపం: ఎటువంటి shell లేకుండా binary నేరుగా నడుస్తుంది. CMD nginx -g "daemon off;" shell రూపం: Docker దాన్ని /bin/sh -c 'nginx -g "daemon off;"' గా తిరిగి రాస్తుంది. అందువల్ల ముందుగా shell నడుస్తుంది, మీ ప్రోగ్రామ్ దాని child process అవుతుంది.
Compose ఇదే నియమాన్ని అనుసరించదు. దీనివల్ల చాలామంది గందరగోళానికి గురవుతారు. command: లోని string arguments గా విభజించి నేరుగా అమలు చేస్తుంది. ఇందులో /bin/sh -c wrapper ఉండదు. Compose reference దీనిని స్పష్టంగా చెబుతుంది: command field imageలో నిర్వచించిన SHELL context లో నడవదు. కాబట్టి shell features అవసరమైతే మీరు స్వయంగా shell ను invoke చేయాలి.
అందుకే command: echo "hello $$HOSTNAME" literal text hello $HOSTNAME ను ప్రింట్ చేస్తుంది. ఆ string ను ఏ shell కూడా చదవలేదు. కాబట్టి దానిలోని విలువను ఏదీ expand చేయలేదు. Shell కావాలంటే దాన్ని స్పష్టంగా అడగాలి:
services:
demo:
image: alpine:3.20
command: /bin/sh -c 'echo "hello $$HOSTNAME"'Signals, PID 1, మరియు శుభ్రమైన docker compose down
docker compose stop మరియు docker compose down ప్రతి container లోని PID 1 కు SIGTERM ను పంపి, stop_grace_period కోసం వేచి ఉండి, తరువాత SIGKILL ను పంపుతాయి. Default grace period 10 seconds.
Linux లో PID 1 ప్రత్యేకమైనది. Kernel, signal యొక్క default action ను PID 1 కు వర్తింపజేయదు. అందువల్ల SIGTERM handler ను అమలు చేయని process, PID 1 గా నడుస్తున్నప్పుడు SIGTERM ను విస్మరిస్తుంది. అది మొత్తం grace period పాటు అలాగే ఉంటుంది. తరువాత దాన్ని నేరుగా kill చేస్తారు. దాంతో తెరిచి ఉన్న connection లేదా commit కాని transaction నిలిచిపోవచ్చు.
మీ program ముందు shell ఉంటే ఈ సమస్య మరింత సంభవించే అవకాశం ఉంది. ఎందుకంటే shell PID 1 గా ఉంటుంది. చాలా shells తమ child కు signals ను forward చేయవు. కొన్ని shells, -c string లోని చివరి command కు తమను తాము replace చేసుకుంటాయి. అందువల్ల కొన్ని సందర్భాల్లో మీ program PID 1 గా మారవచ్చు. ఇది shell మరియు ఖచ్చితమైన string పై ఆధారపడి ఉంటుంది. కాబట్టి ఊహించవద్దు. దీన్ని పరిశీలించండి:
docker compose exec -T web cat /proc/1/cmdline | tr '\0' ' '; echoPID 1 గా మీ program కాకుండా /bin/sh -c ... కనిపిస్తే, రెండు పరిష్కారాలు ఉన్నాయి. Image లో exec form ఉపయోగించండి. లేదా shell ను ఉంచి, exec తో process ను అప్పగించండి:
services:
web:
image: myapp:1.4
command: /bin/sh -c 'exec myapp --config /etc/myapp.toml'exec child ను fork చేయకుండా shell process ను మీ program తో replace చేస్తుంది. అందువల్ల మీ program PID 1 ను స్వీకరించి signal ను అందుకుంటుంది.
కొన్ని programs child processes ను సృష్టించి, వాటిని ఎప్పుడూ reap చేయవు. దాంతో zombie processes మిగిలిపోతాయి. ఎందుకంటే PID 1 reaper గా కూడా పనిచేస్తుంది. దీనికి Compose లో ఒక switch ఉంది:
services:
web:
image: myapp:1.4
init: true
stop_grace_period: 30sinit: true ఒక చిన్న init process ను PID 1 గా నడుపుతుంది. ఇది signals ను మీ process కు forward చేసి, child processes ను reap చేస్తుంది. నిజంగా నెమ్మదిగా జరిగే shutdown కు stop_grace_period మరింత సమయం ఇస్తుంది. మీ program వేరే signal ను ఆశిస్తే, Compose పంపే signal ను stop_signal: SIGQUIT మారుస్తుంది. Image ఇప్పటికే ఏది కోరుకుంటుందో docker image inspect --format '{{.Config.StopSignal}}' nginx:1.27 తో పరిశీలించండి.
ఒక stack లో ప్రతి service కోసం docker compose down ఎల్లప్పుడూ పది seconds తీసుకుంటే, SIGTERM ను ఏదీ handle చేయడం లేదని అర్థం. Tooling ను నిందించే ముందు దీన్ని సరిచేయండి. ప్రతి subcommand ఏమి remove చేస్తుందో తెలుసుకోవడానికి docker compose down మరియు stop మధ్య తేడా చూడండి.
ఇదే exec-versus-shell విభజన మరో చోట కూడా కనిపిస్తుంది. test: ["CMD", "curl", "-f", "http://localhost/"] గా రాసిన healthcheck binary ను నేరుగా నడుపుతుంది. అయితే test: ["CMD-SHELL", "curl -f http://localhost/ || exit 1"] shell ద్వారా నడుస్తుంది. అందువల్ల || కు అర్థం ఉంటుంది. ఆ field కు సంబంధించిన మిగతా విషయాలను నిజాయితీగా విఫలమయ్యే Compose healthchecks రాయడం లో చూడండి.
అధికారిక image కు ఒక flag జోడించడం
చాలా మంది పాఠకులు ఈ విషయం కోసం వచ్చారు. మీరు postgres కు ఒక అదనపు flag ఇవ్వాలి. కానీ initialization script కు అంతరాయం కలగకూడదు.
services:
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql/data
command: postgres -c max_connections=200 -c shared_buffers=256MB
volumes:
pgdata:command: మాత్రమే మారింది. అందువల్ల docker-entrypoint.sh ఇప్పటికీ అమలవుతుంది. మీరు ఇచ్చిన command ను అది ఇప్పటికీ exec చేస్తుంది. ఊహించకుండా ఫలితాన్ని పరిశీలించండి:
docker compose up -d db
docker compose exec -T db psql -U postgres -c 'show max_connections;'Output లో 200 కనిపించాలి. ఇంకా 100 కనిపిస్తే, docker compose config ను అమలు చేసి, మీరు ఆశిస్తున్న command merged output లో ఉందో నిర్ధారించండి. Compose override files ను merge చేసేటప్పుడు command ను పూర్తిగా replace చేస్తుంది; దానికి append చేయదు. అందువల్ల command: ను కూడా సెట్ చేసే రెండో file ఉంటే, అది ఎలాంటి హెచ్చరిక లేకుండా ముందున్న విలువను భర్తీ చేస్తుంది.
పై ${POSTGRES_PASSWORD} ను container ఉనికిలోకి రాకముందే, host పై ఉన్న మీ .env file నుంచి Compose విస్తరిస్తుంది. ఆ విలువను సురక్షితంగా ఎక్కడ ఉంచాలో Compose లో Env files మరియు secrets వివరిస్తుంది.
docker compose run తో ఒకసారి మాత్రమే migration అమలు చేయడం
docker compose run అదే service definition ఆధారంగా కొత్త container ను నిర్మించి, service name తర్వాత మీరు ఇచ్చిన command తో దాని command ను భర్తీ చేస్తుంది. Image యొక్క entrypoint మాత్రం అమలవుతుంది. అందువల్ల container, దీర్ఘకాలం నడిచే container సిద్ధమయ్యే విధంగానే సిద్ధమవుతుంది.
docker compose run --rm app python manage.py migrate- command ముగిసినప్పుడు
--rmcontainer ను తొలగిస్తుంది. ఇది లేకపోతే ప్రతి run తర్వాత ఆగిపోయిన container మిగిలిపోతుంది. అదిdocker compose ps -aలో కనిపిస్తుంది. - Ports publish కావు. మీరు
--service-portsజోడించకపోతే,runcontainer service యొక్కports:ను పట్టించుకోదు. అందువల్ల ఇప్పటికే నడుస్తున్న service తో port collision జరగదు. - Dependencies ముందుగా start అవుతాయి.
depends_onలో ఉన్న ప్రతిదీ మీ command కు ముందు ప్రారంభమవుతుంది.--no-depsదీనిని దాటవేస్తుంది. - Container కు
myproject-app-run-9f2c1aవంటి generated name వస్తుంది. అందువల్ల service container తో name clash ఎప్పుడూ జరగదు.
Entrypoint ను కూడా భర్తీ చేయాలంటే, దానికి ఒక flag ఉంది:
docker compose run --rm --entrypoint /bin/sh app -c 'python manage.py migrate'ఫలితంగా argument list /bin/sh -c 'python manage.py migrate' అవుతుంది. ఎందుకంటే service name తర్వాత ఉన్న పదాలు command గానే ఉంటాయి. docker compose exec మరో tool, ఇది భిన్నంగా పనిచేస్తుంది. ఇది ఇప్పటికే నడుస్తున్న container లోపల process ను అమలు చేస్తుంది. అలాగే ఇది entrypoint: మరియు command: రెండింటినీ పూర్తిగా పట్టించుకోదు. కొత్త container అవసరమైన task కోసం run ను ఉపయోగించండి. ఇప్పటికే నడుస్తున్న container లోపల చూడటానికి exec ను ఉపయోగించండి. మిగిలిన subcommands ను Compose command cheat sheet పక్కపక్కన చూపిస్తుంది.
నా container వెంటనే ఎందుకు exit అవుతోంది?
కారణాన్ని త్వరగా పరిమితం చేయడానికి ముందుగా exit code ను పరిశీలించండి.
docker compose ps -a
docker compose logs appExit code 0 మరియు ఎలాంటి output లేదు. Command నడిచి పూర్తయింది. అత్యంత సాధారణ కారణం entrypoint: override image లోని CMD ను కూడా భర్తీ చేయడం. దాంతో entrypoint ఖాళీ argument list తో నడిచి, hand off చేయడానికి ఏమీ లేకుండా పోయింది.
permission denied తో ముగిసే error. Image లో script కు executable bit లేదు. సాధారణంగా repository లోని file పై ఆ bit ఎప్పుడూ సెట్ చేయకపోవడం వల్ల ఇది జరుగుతుంది. Build సమయంలో COPY --chmod=0755 entrypoint.sh /entrypoint.sh తో దాన్ని సెట్ చేయండి.
Image లో file స్పష్టంగా కనిపిస్తున్నప్పటికీ no such file or directory తో ముగిసే error. Script లో Windows line endings ఉన్నాయి. అందువల్ల దాని మొదటి line #!/bin/sh తో పాటు carriage return byte గా చదవబడుతుంది. Kernel ఆ byte ను పేరులో కలిగిన interpreter కోసం చూస్తుంది, కానీ అలాంటిది కనుగొనలేకపోతుంది. dos2unix entrypoint.sh ను అమలు చేసి, ఇది మళ్లీ జరగకుండా * text eol=lf ను .gitattributes కు జోడించండి.
executable file not found in $PATH. command: లో పేర్కొన్న binary image లో లేదు. లేదా నిజమైన program మాత్రమే అంగీకరించే చోట cd వంటి shell built-in ను రాశారు.
entrypoint విఫలమయ్యే image లో shell పొందడం
ఏదైనా పరిశీలించేలోపే entrypoint ఆగిపోతే, దాని స్థానంలో వేరొకదాన్ని ఉపయోగించండి:
docker compose run --rm --entrypoint /bin/sh appఅది executable file not found in $PATH ను తిరిగి ఇస్తే, ఆ image లో shell అసలు లేదు. Distroless మరియు scratch ఆధారిత images లో తరచుగా shell ఉండదు. entrypoint ను ప్రారంభించకుండా బయట నుంచి filesystem ను చదవవచ్చు:
docker create --name probe myapp:1.4
docker export probe | tar -tv | head -40
docker rm probeమీరు container కు పదేపదే attach కావాలంటే, అది నడుస్తూనే ఉండేలా ఎప్పటికీ ముగియని process పై ఉంచండి. దీన్ని commit చేయని override file లో చేర్చండి:
services:
app:
entrypoint: ["tail", "-f", "/dev/null"]
command: []command: [] తప్పనిసరి కాదు, ఎందుకంటే entrypoint: సెట్ చేయడం ద్వారా image లోని CMD ఇప్పటికే తొలగించబడింది. అయితే దీన్ని రాయడం ద్వారా, తరువాత file చదివే వ్యక్తికి ఉద్దేశం స్పష్టంగా నమోదవుతుంది. దీన్ని ప్రారంభించి లోపలికి వెళ్లండి:
docker compose -f compose.yaml -f compose.debug.yaml up -d app
docker compose exec app /bin/shఇప్పుడు నిజమైన entrypoint ను చేతితో నడిపి, అది ఎక్కడ ఆగుతుందో గమనించండి. కొద్దిసేపటి క్రితం ఆగిపోయిన container లో కాకుండా, error message మీ terminal లోనే కనిపిస్తుంది. మీరు ఇంకా మీ మొదటి stack ను సిద్ధం చేస్తుంటే, VPS పై మొదటి Compose stack పై మార్గదర్శకంలో పైన పేర్కొన్న file layout వివరించబడింది.
FAQ
నా container docker compose up తర్వాత వెంటనే ఎందుకు exit అవుతుంది?
Exit code కోసం docker compose ps -a ను పరిశీలించండి. ఎలాంటి output లేకుండా Exit 0 వస్తే, సాధారణంగా మీరు service పై entrypoint: సెట్ చేసి ఉంటారు. దాంతో image యొక్క CMD కూడా తొలగిపోతుంది. అందువల్ల entrypoint ఖాళీ argument list తో నడిచి ముగుస్తుంది. command: ద్వారా arguments ను మళ్లీ జోడించండి. permission denied తో ముగిసే error వస్తే, entrypoint script పై executable bit లేదు. ఉన్న file కోసం no such file or directory తో ముగిసే error వస్తే, ఆ script లో Windows line endings ఉన్నాయి. అందువల్ల దాని shebang line లేని interpreter పేరును సూచిస్తోంది.
Compose లో entrypoint సెట్ చేస్తే image యొక్క CMD తొలగిపోతుందా?
అవును. entrypoint non-null గా ఉంటే, image ప్రకటించిన default command ను Compose విస్మరిస్తుంది. ఇది documented behaviour. ఇది docker run --entrypoint కు అనుగుణంగా ఉంటుంది. కారణం, image యొక్క CMD ఆ image యొక్క ENTRYPOINT కు arguments గా వ్రాయబడుతుంది. కాబట్టి entrypoint ను మార్చిన తర్వాత పాత arguments ఏదికీ సంబంధించినవి కావు. కొత్త entrypoint కు ఇంకా arguments అవసరమైతే, అదే service లో command: సెట్ చేయండి.
Compose లో string రూపంలోని command shell ద్వారా నడుస్తుందా?
లేదు. Dockerfile లోని CMD కు భిన్నంగా, Compose లోని string రూపంలోని command: arguments గా విభజించి నేరుగా execute చేయబడుతుంది. ఇందులో /bin/sh -c wrapper ఉండదు. అందువల్ల container లోని shell $VARIABLE ను ఎప్పటికీ expand చేయదు. Shell అవసరమైనప్పుడు command: /bin/sh -c 'echo "hello $$HOSTNAME"' లో చూపిన విధంగా దాన్ని మీరు స్వయంగా call చేయాలి. రెట్టింపు $$ dollar sign ను escape చేస్తుంది. అందువల్ల Compose దాన్ని host పై expand చేయకుండా container కు పంపుతుంది.
ఒక container కోసం docker compose down పది seconds ఎందుకు తీసుకుంటుంది?
Compose PID 1 కు SIGTERM పంపుతుంది. తరువాత stop_grace_period వరకు వేచి ఉంటుంది (default గా 10 seconds). ఆ తర్వాత SIGKILL పంపుతుంది. PID 1 కు kernel default signal actions ను వర్తింపజేయదు. కాబట్టి SIGTERM handler లేని program ఆ signal ను పట్టించుకోదు. ఫలితంగా పూర్తి వ్యవధి ముగిసే వరకు వేచి ఉంటుంది. docker compose exec -T app cat /proc/1/cmdline | tr '\0' ' ' ద్వారా PID 1 వాస్తవంగా ఏమిటో తెలుసుకోండి. అది shell అయితే, image ను exec form కు మార్చండి లేదా shell string లో exec వ్రాయండి. Process సృష్టించిన child processes ను reap చేయకపోతే, service పై init: true సెట్ చేయండి.