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-এর সঙ্গে থাকে - কীভাবে
CMDoverride করা যায় - এবং একটি 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 <image> <custom_command> ব্যবহার করলে 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 <CONTAINER_ID> 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 <CONTAINER_ID> 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 -y golang |
CMD ["go", "run", "server.go"] |
Reference material-এও execution phase, purpose এবং image-এর সঙ্গে persistence-এর ভিত্তিতে RUN ও CMD-কে এভাবেই আলাদা করা হয়েছে।
20. The Three Most Important Commands
এই lesson-এর core workflow মাত্র কয়েকটি command-এ:
Build
docker build -t new_go_server:1.0.1 .
Normal Run
docker run new_go_server:1.0.1
→ CMD automatically execute হবে।
Debug / Override
docker run -it new_go_server:1.0.1 bash
→ CMD override হয়ে bash execute হবে।
এই তিনটি command-এর relationship বুঝলেই CMD অনেক সহজ হয়ে যায়।
21. The Most Important Mental Model
Dockerfile-এর ক্ষেত্রে এই flow-টি মনে রাখুন:
BUILD TIME
│
▼
┌────────────────────────┐
│ FROM │
│ RUN │
│ WORKDIR │
│ COPY │
└────────────────────────┘
│
▼
Docker Image
│
│ docker run
▼
RUNTIME
│
▼
CMD
│
▼
Application Process
অর্থাৎ:
RUNprepares the image.CMDstarts the application.
এই এক লাইনের mental model-টি Dockerfile-এর অনেক confusion দূর করতে পারে।
22. Why This Matters Beyond This Example
আমাদের example একটি simple Go server।
কিন্তু একই principle practically সব ধরনের containerized application-এর ক্ষেত্রে দেখা যায়।
একটি application image তৈরি করার সময়:
Dependencies
Configuration
Application Files
image-এর মধ্যে prepare করা হয়।
আর container start হওয়ার সময়:
Application Process
start করা হয়।
তাই একটি well-designed container-এর ক্ষেত্রে user experience ideally এমন:
docker run <image>
এবং application নিজে থেকেই start করবে।
User-কে container-এর ভিতরে গিয়ে manually setup করতে হবে না।
এটাই containerization-এর বড় সুবিধাগুলোর একটি।
23. One Last Look at Our Go Server
আমাদের server.go:
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello World!")
})
fmt.Println("Server is running on :8080")
http.ListenAndServe(":8080", nil)
}
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 build -t new_go_server:1.0.1 .
Run:
docker run new_go_server:1.0.1
Debug:
docker run -it new_go_server:1.0.1 bash
Test:
curl http://localhost:8080
Response:
Hello World!
এই ছোট example-এর মধ্যেই Dockerfile-এর একটি complete lifecycle দেখা যাচ্ছে।
Final Takeaway
আজকের lesson-এ মূলত একটি প্রশ্নের উত্তর খুঁজেছি:
How do we make a Docker container automatically start our application?
উত্তর:
CMD ["go", "run", "server.go"]
কিন্তু শুধু syntax মনে রাখলে হবে না।
বোঝা দরকার কখন এটি execute হয়।
docker build
FROM
RUN
WORKDIR
COPY
এগুলো image তৈরি করে।
CMD তখন execute হয় না।
তারপর:
docker run
Container Created
↓
CMD Executed
↓
Go Server Started
↓
Container Keeps Running
আর যদি debugging করতে চাই:
docker run -it new_go_server:1.0.1 bash
তাহলে default CMD override হয়ে bash চালু হবে।
শেষ পর্যন্ত Docker-এর এই simple mental model-টি মনে রাখুন:
Build the environment with
RUN.
Define the default application process withCMD.
Start it withdocker run.
Override it when you need to debug.
একটি ছোট CMD instruction আসলে Docker image-কে একটি static filesystem থেকে একটি runnable application environment-এ পরিণত করার গুরুত্বপূর্ণ অংশ।
আর Docker শেখার পরবর্তী ধাপে এই concept থেকেই naturally আসে ENTRYPOINT, CMD বনাম ENTRYPOINT, environment variables, ports, volumes এবং production-grade container design।
Understand the lifecycle, not just the command. 🐳
Top comments (0)