Dockerfile CMD Explained: Build-Time vs Runtime and How CMD Override Works
Dockerfile শেখার সময় FROM , RUN , WORKDIR , এবং COPY নিয়ে কাজ করার পর খুব স্বাভাবিকভাবেই একটি প্রশ্ন আসে: Container start হলে application automatically কীভাবে run করবে? আমরা যদি শুধু এই ধরনের Dockerfile লিখি- FROM ubuntu:24.04 RUN apt update RUN apt install -y golang WORKDIR /app COPY ./server.go ./server.go তাহলে image তৈরি হবে ঠিকই। Go-ও install হবে। server.go -ও image-এর মধ্যে চলে যাবে। কিন্তু container start করলে কি আমাদের Go server automatically চালু হবে? না। আমাদের আবার container-এর ভিতরে ঢুকে manually লিখতে হবে: go run server.go এটাই সেই জায়গা যেখানে Dockerfile-এর একটি অত্যন্ত গুরুত্বপূর্ণ instruction সামনে আসে: CMD CMD আমাদের image-এর default runtime command নির্ধারণ করে। এই article-এ আমরা দেখব: - কেন container immediately exit করতে পারে - CMD কী - RUN এবংCMD -এর পার্থক্য - build time বনাম runtime - CMD কীভাবে Docker image-এর সঙ্গে থাকে - কীভাবে CMD override করা যায় - এবং একটি real Go server দিয়ে পুরো বিষয়টি hands-onভাবে বোঝা এই distinction বোঝা Docker-এর fundamental concepts-এর একটি। 1. The Problem: Why Does the Container Exit? ধরুন আমাদের image তৈরি হয়ে গেছে: new_go_server:1.0.0 এখন আমরা চালালাম: docker run new_go_server:1.0.0 কিন্তু কিছুক্ষণ পরেই container বন্ধ হয়ে গেল। docker ps -এ কিছু নেই। তখন: docker ps -a দিলে দেখা যাবে container-এর status: Exited কেন? কারণ container কোনো GUI application নয় যে শুধু "open" হয়ে থাকবে। একটি Docker container-এর lifecycle মূলত তার primary process-এর সঙ্গে সম্পর্কিত। যে process container-এর প্রধান process হিসেবে চলছে সেটি শেষ হয়ে গেলে container-ও শেষ হয়ে যায়। Reference material-এও এই কারণেই default command/process না থাকলে container start হয়ে immediately exit করার বিষয়টি দেখানো হয়েছে। আমাদের Go application-এর ক্ষেত্রে আমরা চাই: docker run ↓ Container starts ↓ Go server starts ↓ Server keeps running ↓ Container stays alive কিন্তু Docker-কে তো আমরা বলিইনি যে server কীভাবে start করবে। এখানেই CMD প্রয়োজন। 2. What Does CMD Actually Do? সহজ ভাষায়: CMD বলে দেয়-কোনো image থেকে container start হলে default হিসেবে কোন command চালানো হবে। আমাদের ক্ষেত্রে: CMD ["go", "run", "server.go"] এর অর্থ: Container starts ↓ Run: go run server.go ফলে: docker run new_go_server:1.0.1 দিলেই Go server automatically start হবে। আর manually: go run server.go লিখতে হবে না। এটাই CMD -এর মূল purpose। 3. Our Complete Dockerfile এখন আগের Dockerfile-এ CMD যোগ করি: FROM ubuntu:24.04 RUN apt update RUN apt install -y golang WORKDIR /app COPY ./server.go ./server.go CMD ["go", "run", "server.go"] এখন আমাদের Dockerfile-এর responsibilities পরিষ্কার: FROM ↓ Base Image RUN ↓ Install Dependencies WORKDIR ↓ Set Working Directory COPY ↓ Bring Application Code CMD ↓ Define Default Runtime Command এটি Dockerfile-এর একটি very useful mental model। 4. The Most Important Concept: RUN vs CMD Dockerfile শেখার সময় সবচেয়ে common confusion: " RUN আরCMD -দুটোই তো command চালায়। তাহলে difference কী?" Difference হলো কখন এবং কেন command চালানো হচ্ছে। RUN RUN execute হয়: docker build এর সময়। CMD CMD execute হয়: docker run এর সময়। অর্থাৎ: docker build │ ▼ ┌─────────────┐ │ RUN │ └─────────────┘ │ ▼ IMAGE │ │ docker run ▼ ┌─────────────┐ │ CMD │ └─────────────┘ │ ▼ CONTAINER Reference material-এও RUN -কে build phase এবং CMD -কে run phase-এর instruction হিসেবে আলাদা করা হয়েছে। 5. What Happens During docker build ? ধরুন আমরা চালালাম: docker build -t new_go_server:1.0.1 . Dockerfile: FROM ubuntu:24.04 RUN apt update RUN apt install -y golang WORKDIR /app COPY ./server.go ./server.go CMD ["go", "run", "server.go"] Build-এর সময় Docker: FROM ubuntu:24.04 ↓ RUN apt update ↓ RUN apt install -y golang ↓ WORKDIR /app ↓ COPY server.go ↓ Create Image কিন্তু এখানে একটি গুরুত্বপূর্ণ বিষয়: CMD ["go", "run", "server.go"] এই command build-এর সময় execute হয় না। এটি image-এর configuration/metadata-এর অংশ হিসেবে রাখা হয়। Reference build flow-এও CMD build step হিসেবে execute না হয়ে image-এর সঙ্গে default runtime instruction হিসেবে সংরক্ষিত হওয়ার বিষয়টি দেখানো হয়েছে। 6. Then What Happens During docker run ? Build শেষ। আমাদের image: new_go_server:1.0.1 এখন: docker run new_go_server:1.0.1 চালালাম। Docker image থেকে একটি container তৈরি করবে। তারপর image-এর মধ্যে থাকা default CMD দেখবে: CMD ["go", "run", "server.go"] এবং container-এর ভিতরে সেটি execute করবে। ফলে: docker run ↓ Create Container ↓ Start Container ↓ Execute CMD ↓ go run server.go ↓ Go Server :8080 Output: Server is running on :8080 এখন container আর সঙ্গে সঙ্গে exit করবে না, কারণ Go server foreground-এ চলমান process হিসেবে container-কে active রাখছে। Reference hands-on test-এও docker run new_go_server:1.0.1 -এর পর CMD থেকে Go server automatically start হওয়ার বিষয়টি দেখানো হয়েছে। 7. Understanding the Exec Form আমরা লিখেছি: CMD ["go", "run", "server.go"] এটাকে বলা হয় Exec Form। এখানে প্রতিটি argument আলাদা string: "go" "run" "server.go" এবং comma দিয়ে আলাদা করা হয়েছে। Conceptually এটি: go run server.go command-টির equivalent। Reference material-এ Dockerfile-এর জন্য এই JSON-array/Exec Form syntax-টিকেই ব্যবহার করা হয়েছে। 8. A Critical Mental Model এখন এই দুইটি statement মনে রাখুন: RUN Build the image. CMD Run the application when the container starts. আরও সহজভাবে: RUN → Image তৈরির সময় CMD → Container চালুর সময় এই একটি distinction Dockerfile-এর অনেক confusion দূর করে। 9. CMD Does NOT Run During Build এটি beginner-দের একটি common misunderstanding। ধরুন: CMD ["go", "run", "server.go"] লিখেছি। তারপর: docker build -t go-server:1.0.1 . চালালাম। এখানে Go server start হবে না। আপনি build output-এ: Server is running on :8080 দেখবেন না। কারণ CMD তখন execute হয়নি। Image তৈরি হয়েছে এবং default command হিসেবে CMD image-এর সঙ্গে সংরক্ষিত হয়েছে। তারপর: docker run go-server:1.0.1 দিলে CMD execute হবে। 10. The Magic of Default Commands এখন সবচেয়ে useful part। আমাদের image: new_go_server:1.0.1 এর default command: CMD ["go", "run", "server.go"] তাই: docker run new_go_server:1.0.1 মানে effectively: Run container + Use the image's default command ফলে server automatically start হয়। এটাই containerized application-এর expected behaviour: docker run image ↓ Application starts ↓ Application keeps running User-কে container-এর ভিতরে ঢুকে application manually start করতে হয় না। 11. But What If I Want Another Command? এখানে Docker-এর আরেকটি powerful feature আছে। ধরুন image-এর default: CMD ["go", "run", "server.go"] কিন্তু debugging-এর জন্য আমরা container-এর ভিতরে bash shell চাই। তাহলে: docker run -it new_go_server:1.0.1 bash এখানে কী হলো? আমরা bash command দিয়েছি। Docker default CMD ব্যবহার না করে এই command execute করবে। অর্থাৎ: Dockerfile CMD │ │ override ▼ docker run ... bash │ ▼ bash Reference material-এ এই exact behaviour দেখানো হয়েছে-docker run ব্যবহার করলে Dockerfile-এর CMD override হয়ে custom command execute হয়। 12. CMD Override: A Practical Example Default behaviour: docker run new_go_server:1.0.1 Result: go run server.go কিন্তু: docker run -it new_go_server:1.0.1 bash Result: bash অর্থাৎ CMD override হয়েছে। এটি বিশেষ করে debugging-এর সময় useful। ধরুন application start হচ্ছে না। তখন: docker run -it new_go_server:1.0.1 bash দিয়ে container-এর ভিতরে ঢুকে manually inspect করতে পারি: ls go version go run server.go অর্থাৎ production-এ default command ব্যবহার করা হবে, আর troubleshooting-এর সময় custom command দিয়ে override করা যেতে পারে। 13. CMD Override মানে Image পরিবর্তন নয় এখানে আরেকটি subtle point আছে। যখন আমরা: docker run -it new_go_server:1.0.1 bash দিই, তখন আমরা Docker image-এর CMD permanently পরিবর্তন করছি না। শুধু এই particular container-এর জন্য default command-এর পরিবর্তে bash চালাচ্ছি। পরেরবার: docker run new_go_server:1.0.1 দিলে আবার: CMD ["go", "run", "server.go"] execute হবে। অর্থাৎ: Image │ ├── Default CMD → go run server.go │ ├── Container A → default CMD │ └── Container B → bash override Image-এর default configuration unchanged থাকে। 14. Hands-On: Build the New Image এখন complete Dockerfile দিয়ে নতুন image build করি: docker build -t new_go_server:1.0.1 . Build-এর সময়: FROM RUN RUN WORKDIR COPY এর instructions process হবে। কিন্তু: CMD ["go", "run", "server.go"] run হবে না। এটি image-এর default runtime command হিসেবে save হবে। 15. Run Without -it এবার: docker run new_go_server:1.0.1 কোনো: -it নেই। কোনো: bash নেই। শুধু: docker run + image এবং তারপরও Go server start হয়ে যাবে। কারণ Docker image-এর মধ্যে আমরা already define করেছি: CMD ["go", "run", "server.go"] Output: Server is running on :8080 এটাই আমাদের desired behaviour। 16. Verify the Running Container অন্য terminal খুলে: docker ps চালালে running container দেখা যাবে। তারপর container-এর ভিতরে প্রবেশ করতে: docker exec -it bash এবং: curl http://localhost:8080 Expected: Hello World! Reference hands-on workflow-এ docker exec দিয়ে running container-এ ঢুকে curl http://localhost:8080 ব্যবহার করে Hello World! response verify করা হয়েছে। 17. docker run বনাম docker exec এই example-এ আরেকটি important distinction পাওয়া যায়। docker run নতুন container তৈরি করে এবং তার default command বা supplied command চালায়। docker run new_go_server:1.0.1 docker exec Already running container-এর ভিতরে নতুন command চালায়। docker exec -it bash অর্থাৎ: docker run → Start a new container docker exec → Execute inside an existing container এই distinction debugging-এর সময় খুব গুরুত্বপূর্ণ। 18. Complete Lifecycle এখন পুরো lifecycle-টা একসঙ্গে দেখি: Dockerfile │ │ docker build ▼ Docker Image │ ┌──────┴──────┐ │ │ │ docker run │ │ │ ▼ ▼ Default CMD Custom Command │ │ ▼ ▼ go run server.go bash │ ▼ Go HTTP Server │ ▼ :8080 এখানে Dockerfile থেকে image, image থেকে container, এবং container start হওয়ার সময় CMD execution-পুরো chain-টি পরিষ্কার হয়ে যায়। 19. RUN vs CMD : Final Comparison | বিষয় | RUN | CMD | |---|---|---| | কখন execute হয়? | docker build | docker run | | মূল উদ্দেশ্য | Image তৈরি/configure করা | Default runtime command | | Image layer তৈরি করে? | হ্যাঁ | Command নিজে build layer তৈরি করে না | | Build-এর সময় application চালায়? | হতে পারে | না | | Container start হলে automatically execute? | না | হ্যাঁ, যদি override না করা হয় | | Override করা যায়? | Runtime command হিসেবে নয় | হ্যাঁ | | Example | RUN apt install -
Comments
No comments yet. Start the discussion.