Docker শিখতে গেলে সবচেয়ে গুরুত্বপূর্ণ জিনিসগুলোর একটি হলো Dockerfile।
অনেকে Dockerfile-কে শুধু কয়েকটি command-এর file হিসেবে দেখে:
FROM node:22
COPY . .
RUN npm install
CMD ["npm", "start"]
কিন্তু আসলে Dockerfile-এর প্রতিটি instruction-এর পেছনে একটি নির্দিষ্ট ধারণা আছে।
কেন FROM লাগবে?
COPY আর ADD-এর পার্থক্য কী?
RUN আর CMD কি একই জিনিস?
CMD এবং ENTRYPOINT কখন ব্যবহার করব?
ARG আর ENV কখন?
কেন COPY package*.json ./ আগে লিখলে build অনেক দ্রুত হয়?
.dockerignore কেন গুরুত্বপূর্ণ?
Production-এ কেন multi-stage build ব্যবহার করা হয়?
এই blog-এর শেষে তুমি শুধু Dockerfile পড়তে পারবে না—নিজে requirement দেখে Dockerfile design করতে পারবে।
1. Dockerfile আসলে কী?
সহজ ভাষায়:
Dockerfile হলো একটি text file যেখানে Docker image কীভাবে তৈরি হবে তার instructions লেখা থাকে।
উদাহরণ:
FROM python:3.12
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
Docker এই instructions-গুলো উপর থেকে নিচে execute করে image তৈরি করে। Docker-এর documentation অনুযায়ী Dockerfile একটি ordered set of instructions, এবং প্রতিটি instruction build-এর অংশ তৈরি করে।
একটি সাধারণ flow:
Dockerfile
↓
docker build
↓
Docker Image
↓
docker run
↓
Container
2. Dockerfile এবং Docker Image-এর সম্পর্ক
ধরো তোমার কাছে একটি Python application আছে।
তুমি Dockerfile লিখলে:
FROM python:3.12
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
তারপর:
docker build -t my-python-app .
এখানে Docker:
Dockerfile
↓
FROM
↓
WORKDIR
↓
COPY
↓
RUN
↓
CMD
↓
Image
তৈরি করবে।
তারপর:
docker run my-python-app
Image থেকে container তৈরি হবে।
3. Dockerfile-এর basic structure
একটি সাধারণ Dockerfile-এর structure:
FROM base-image
WORKDIR /app
COPY files .
RUN commands
ENV VARIABLE=value
EXPOSE 8000
USER appuser
CMD ["command"]
সব Dockerfile-এ সব instruction থাকতে হবে—এমন নয়।
4. Dockerfile-এর সবচেয়ে গুরুত্বপূর্ণ instructions
Dockerfile-এ অনেক instruction আছে। সবচেয়ে বেশি যেগুলো ব্যবহার করবে:
FROM
RUN
COPY
ADD
WORKDIR
ENV
ARG
EXPOSE
USER
CMD
ENTRYPOINT
HEALTHCHECK
VOLUME
LABEL
SHELL
ONBUILD
STOPSIGNAL
Docker-এর official reference-এ এসব instruction-এর পাশাপাশি তাদের syntax ও behaviour বিস্তারিতভাবে দেওয়া আছে।
শেখার priority হিসেবে:
FROM
↓
WORKDIR
↓
COPY
↓
RUN
↓
ENV / ARG
↓
EXPOSE
↓
CMD
↓
ENTRYPOINT
↓
USER
↓
HEALTHCHECK
↓
Multi-stage build
5. FROM — Dockerfile-এর starting point
প্রায় সব সাধারণ Dockerfile শুরু হয়:
FROM image
উদাহরণ:
FROM ubuntu:24.04
অথবা:
FROM python:3.12
অথবা:
FROM node:22-alpine
FROM বলে:
"আমার image কোন existing image-এর উপর তৈরি হবে?"
Docker-এর নিয়ম অনুযায়ী FROM একটি নতুন build stage শুরু করে এবং সাধারণ Dockerfile-এ এটিই প্রথম মূল instruction। একাধিক FROM ব্যবহার করেও multi-stage build করা যায়।
6. Image tag কেন গুরুত্বপূর্ণ?
এটি দেখো:
FROM python
এখানে version নির্দিষ্ট করা হয়নি।
তার বদলে:
FROM python:3.12
আরও predictable।
আরও specific:
FROM python:3.12.6
তাহলে কোন version ব্যবহার হচ্ছে তা নির্দিষ্ট থাকে।
আরও reproducible build-এর জন্য image digest-ও ব্যবহার করা যায়:
FROM python:3.12@sha256:...
তবে beginner হিসেবে শুরু করো:
FROM python:3.12
7. Alpine image কী?
অনেক language-এর Alpine variant পাওয়া যায়:
FROM node:22-alpine
FROM python:3.12-alpine
Alpine সাধারণত ছোট base image হিসেবে ব্যবহৃত হয়।
কিন্তু একটা গুরুত্বপূর্ণ বিষয়:
"ছোট image" মানেই সব ক্ষেত্রে "best image" নয়।
কিছু package বা native dependency-এর ক্ষেত্রে Debian/Ubuntu-based image ব্যবহার করা সহজ হতে পারে।
তাই blindly alpine ব্যবহার না করে application compatibility পরীক্ষা করতে হবে।
8. WORKDIR — container-এর working directory
ধরো তুমি লিখলে:
WORKDIR /app
এর পরে পরবর্তী অনেক instruction-এর জন্য working directory হবে:
/app
উদাহরণ:
FROM python:3.12
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
এখানে:
WORKDIR /app
এর কারণে:
COPY . .
মানে বর্তমান working location হবে /app.
Docker-এর documentation-ও unintended directory-তে কাজ এড়াতে explicit WORKDIR ব্যবহারের best practice উল্লেখ করে।
9. WORKDIR path manually mkdir করতে হয়?
সাধারণত না।
এটি:
WORKDIR /app
প্রয়োজনে directory তৈরি করে ব্যবহার করে।
তাই সাধারণত:
RUN mkdir /app
WORKDIR /app
লেখার দরকার নেই।
10. COPY — local files image-এ নেওয়া
সবচেয়ে বেশি ব্যবহৃত instruction:
COPY source destination
উদাহরণ:
COPY . .
মানে:
build context-এর files বর্তমান working directory-তে copy করো।
আরেকটি উদাহরণ:
COPY app.py /app/
অথবা:
COPY requirements.txt .
11. COPY . . মানে কী?
এই line:
COPY . .
অনেক beginner-কে confuse করে।
ধরো project:
my-project/
├── Dockerfile
├── app.py
├── requirements.txt
└── config/
└── settings.json
তুমি run করছ:
docker build -t myapp .
শেষের . হলো:
build context = current directory
তারপর Dockerfile-এ:
WORKDIR /app
COPY . .
ফলে image-এ হতে পারে:
/app/
├── Dockerfile
├── app.py
├── requirements.txt
└── config/
└── settings.json
তবে .dockerignore থাকলে কিছু file বাদ যাবে।
12. Build context বুঝতেই হবে
এই command:
docker build -t myapp .
এখানে শেষের:
.
খুব গুরুত্বপূর্ণ।
এটি Docker-কে বলে:
"এই directory-কে build context হিসেবে ব্যবহার করো।"
তুমি যদি চালাও:
docker build -t myapp ./backend
তাহলে ./backend build context হবে।
সুতরাং Dockerfile-এ:
COPY . .
লিখলে . বলতে সেই build context-কে বোঝাবে।
13. .dockerignore
ধরো project directory-তে আছে:
node_modules/
.git/
.env
logs/
dist/
Dockerfile
README.md
সবকিছু Docker build context-এ পাঠানোর দরকার নেই।
তাই:
.dockerignore
file তৈরি করো।
উদাহরণ:
node_modules
.git
.env
*.log
dist
coverage
Docker-এর documentation অনুযায়ী .dockerignore build context থেকে files/directories বাদ দিতে ব্যবহার করা হয়।
14. কেন .dockerignore এত গুরুত্বপূর্ণ?
কারণ build context-এ unnecessary file পাঠালে:
Build slow
+
Large context
+
Potential secret exposure
+
Unnecessary data
ধরো:
node_modules = 500 MB
কিন্তু application build করতে এটি context-এ পাঠানোরই দরকার নেই, কারণ container-এর ভেতরে dependency install করা যেতে পারে।
তাই:
.dockerignore
node_modules
.git
.env
খুব সাধারণ এবং গুরুত্বপূর্ণ setup।
15. RUN — image build করার সময় command চালানো
RUN Dockerfile-এর অন্যতম গুরুত্বপূর্ণ instruction।
উদাহরণ:
RUN apt-get update
অথবা:
RUN pip install -r requirements.txt
অথবা:
RUN npm install
এগুলো image build-এর সময় execute হয়।
অর্থাৎ:
docker build .
চালানোর সময় RUN execute হবে।
16. RUN বনাম CMD
এখানে beginners-এর সবচেয়ে common confusion।
RUN
RUN npm install
মানে:
image build করার সময় npm install করো।
CMD
CMD ["npm", "start"]
মানে:
container চালু হলে default হিসেবে npm start execute করো।
অর্থাৎ:
docker build
↓
RUN
↓
Image তৈরি
docker run
↓
CMD / ENTRYPOINT
↓
Application start
17. RUN দিয়ে application start করা উচিত?
সাধারণত না।
খারাপ:
RUN npm start
কারণ এটি build-এর সময় application start করবে।
সঠিক:
RUN npm install
CMD ["npm", "start"]
18. RUN-এর command combine করা
ধরো:
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y git
করা যায়:
RUN apt-get update && \
apt-get install -y curl git
এর ফলে Dockerfile clean থাকে এবং package-manager সম্পর্কিত state একই build step-এ handle করা যায়।
Debian/Ubuntu package installation-এর ক্ষেত্রে stale package index রেখে যাওয়ার বদলে update/install একসাথে করা সাধারণত ভালো practice:
RUN apt-get update && \
apt-get install -y --no-install-recommends curl git && \
rm -rf /var/lib/apt/lists/*
19. Shell form এবং Exec form
Dockerfile-এ command লেখার দুটি গুরুত্বপূর্ণ style আছে।
Shell form
RUN echo hello
CMD npm start
এগুলো shell-এর মাধ্যমে execute হতে পারে।
Exec form
CMD ["npm", "start"]
এখানে JSON-array style ব্যবহার করা হয়েছে।
বিশেষ করে CMD এবং ENTRYPOINT-এর ক্ষেত্রে exec form খুব গুরুত্বপূর্ণ।
Docker-এর official reference shell form ও exec form দুটোই আলাদা করে ব্যাখ্যা করে।
20. CMD — container-এর default command
উদাহরণ:
FROM python:3.12
WORKDIR /app
COPY . .
CMD ["python", "app.py"]
এখন:
docker run myapp
করলে:
python app.py
চলবে।
21. CMD overwrite করা যায়
ধরো:
CMD ["python", "app.py"]
কিন্তু তুমি চালালে:
docker run myapp python test.py
তাহলে default CMD পরিবর্তিত হয়ে নতুন command execute হতে পারে।
এই কারণেই CMD-কে সাধারণত:
default command
হিসেবে ভাবতে পারো।
22. ENTRYPOINT — container-এর executable
উদাহরণ:
ENTRYPOINT ["python", "app.py"]
এখন container-এর primary executable হিসেবে এটিকে ধরা হচ্ছে।
ENTRYPOINT এবং CMD একসঙ্গেও ব্যবহার করা যায়।
উদাহরণ:
ENTRYPOINT ["python"]
CMD ["app.py"]
এখন effectively:
python app.py
চলবে।
আর user command-line argument দিলে CMD অংশ replace হতে পারে।
23. CMD বনাম ENTRYPOINT
সহজ mental model:
ENTRYPOINT = আমি কী চালাব?
CMD = default argument / default command কী?
একটি practical example:
ENTRYPOINT ["python"]
CMD ["app.py"]
Default:
python app.py
আর:
docker run myapp test.py
দিলে:
python test.py
হতে পারে।
24. কখন শুধু CMD ব্যবহার করব?
Simple application হলে:
CMD ["python", "app.py"]
যথেষ্ট হতে পারে।
25. কখন ENTRYPOINT ব্যবহার করব?
যখন container-কে একটি নির্দিষ্ট executable/tool হিসেবে package করতে চাও।
উদাহরণ:
ENTRYPOINT ["python"]
CMD ["app.py"]
অথবা:
ENTRYPOINT ["./server"]
26. ENV — runtime environment variable
উদাহরণ:
ENV APP_ENV=production
Container-এর মধ্যে:
APP_ENV=production
থাকবে।
আরেকটি:
ENV PORT=8080
Application এটি ব্যবহার করতে পারে।
27. ENV আর ARG-এর পার্থক্য
এটি অবশ্যই বুঝতে হবে।
ARG
ARG VERSION=1.0
ARG মূলত build-time variable।
Build করার সময়:
docker build --build-arg VERSION=2.0 .
দেওয়া যায়।
ENV
ENV APP_ENV=production
ENV image/container environment-এর অংশ।
সহজভাবে:
ARG → build-time
ENV → runtime environment
Docker-এর documentation অনুযায়ী ARG build-time variable, এবং এটি final container environment-এ automatically available নয়; ENV আলাদা behaviour রাখে।
28. ARG-এর গুরুত্বপূর্ণ security warning
এটা অত্যন্ত গুরুত্বপূর্ণ।
এভাবে secret দেওয়া উচিত নয়:
docker build \
--build-arg API_KEY=secret123 \
.
কারণ Docker documentation অনুযায়ী build arguments secrets pass করার জন্য recommended নয়; এগুলো image history বা build provenance-এ প্রকাশিত হতে পারে। Secret-এর জন্য BuildKit secret mounts ব্যবহার করা উচিত।
অর্থাৎ:
ARG ≠ Secret storage
29. ENV-এও password রাখা উচিত?
এটিও avoid করা উচিত।
খারাপ:
ENV DB_PASSWORD=supersecret
Credentials management-এর জন্য environment variables, secret manager, Docker secrets অথবা orchestration platform-এর secret mechanism ব্যবহার করা উচিত—application ও deployment environment অনুযায়ী।
30. EXPOSE — port সম্পর্কে documentation
উদাহরণ:
EXPOSE 8080
এর মানে:
Application এই container port-এ listen করার কথা।
কিন্তু EXPOSE নিজে host port publish করে না।
এটি খুব গুরুত্বপূর্ণ।
31. EXPOSE বনাম -p
Dockerfile:
EXPOSE 8080
কিন্তু run:
docker run -p 8080:8080 myapp
এখানে:
Host:8080
↓
Container:8080
হচ্ছে।
অর্থাৎ:
EXPOSE = metadata/documentation
-p = actual port publishing
32. USER — container কোন user হিসেবে চলবে
Default ভাবে অনেক base image-এ root user থাকতে পারে।
Production-এর জন্য non-root user ব্যবহার করা security-এর দিক থেকে ভালো practice।
উদাহরণ:
RUN useradd -m appuser
USER appuser
এর পরে container-এর process appuser হিসেবে চলবে।
তবে application-এর file permission ঠিকভাবে configure করতে হবে।
33. LABEL — image metadata
উদাহরণ:
LABEL maintainer="example"
LABEL version="1.0"
অথবা:
LABEL org.opencontainers.image.source="https://github.com/example/project"
Metadata রাখতে useful।
34. HEALTHCHECK
Container process চলছে মানেই application healthy—এমন নয়।
ধরো application process চলছে:
PID exists ✅
কিন্তু HTTP server response দিচ্ছে না:
Application ❌
তাই HEALTHCHECK ব্যবহার করা যায়।
উদাহরণ:
HEALTHCHECK --interval=30s --timeout=5s \
CMD curl -f http://localhost:8080/health || exit 1
তখন Docker application-এর health যাচাই করতে পারে।
35. ADD — কেন আলাদা?
ADD এবং COPY দেখতে কাছাকাছি।
উদাহরণ:
COPY app.py /app/
সাধারণ local file copy-এর ক্ষেত্রে:
COPY-কে default choice হিসেবে ব্যবহার করো।
ADD কিছু অতিরিক্ত behaviour দেয়, যেমন archive extraction এবং remote URL-related capabilities। Docker-এর reference-এ ADD এবং COPY আলাদা instruction হিসেবে defined।
সাধারণ application-এর জন্য:
COPY
বেশিরভাগ সময় যথেষ্ট।
36. প্রথম একটি Python Dockerfile
ধরো project:
project/
├── Dockerfile
├── requirements.txt
└── app.py
app.py:
print("Hello Docker")
Dockerfile:
FROM python:3.12
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]
Build:
docker build -t hello-python .
Run:
docker run hello-python
Output:
Hello Docker
37. এই Dockerfile কীভাবে কাজ করল?
লাইন ধরে:
FROM python:3.12
Python environment নিলাম।
WORKDIR /app
working directory /app করলাম।
COPY requirements.txt .
শুধু dependency file copy করলাম।
RUN pip install --no-cache-dir -r requirements.txt
dependency install করলাম।
COPY . .
application code copy করলাম।
CMD ["python", "app.py"]
container start হলে application চালালাম।
এটাই Dockerfile-এর fundamental pattern:
Base
↓
Directory
↓
Dependencies
↓
Application
↓
Start command
38. Node.js Dockerfile
Project:
project/
├── Dockerfile
├── package.json
├── package-lock.json
└── src/
└── index.js
Dockerfile:
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["node", "src/index.js"]
39. কেন package.json আগে copy করা হলো?
এই pattern:
COPY package*.json ./
RUN npm ci
COPY . .
খুব গুরুত্বপূর্ণ।
কারণ Docker build cache reuse করতে পারে।
ধরো তুমি শুধু:
src/index.js
পরিবর্তন করেছ।
যদি dependency file অপরিবর্তিত থাকে, Docker cached dependency installation reuse করতে পারে।
Docker-এর build cache instruction/layer reuse করে, এবং একটি layer invalidated হলে পরবর্তী layers-ও rebuild হতে পারে।
তাই:
খারাপ pattern:
COPY . .
RUN npm ci
আর সাধারণভাবে ভালো pattern:
COPY package*.json ./
RUN npm ci
COPY . .
40. Docker layer কী?
Dockerfile:
FROM node:22
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
CMD ["npm", "start"]
এখানে প্রতিটি build instruction image-এর build process-এর একটি layer/cacheable step তৈরি করতে পারে।
ভাবতে পারো:
Layer 1 → FROM
Layer 2 → WORKDIR
Layer 3 → COPY package.json
Layer 4 → npm ci
Layer 5 → COPY source
Layer 6 → CMD
Docker cache ব্যবহার করে unchanged parts পুনরায় তৈরি না করে reuse করতে পারে।
41. Cache invalidation বুঝে Dockerfile লিখো
ধরো:
COPY . .
RUN npm install
তুমি code-এর একটি ছোট file পরিবর্তন করলেও:
COPY . .
layer পরিবর্তিত হবে।
তারপর পরের:
RUN npm install
এটিও আবার execute হতে পারে।
তাই dependency ও source code আলাদা করা ভালো:
COPY package*.json ./
RUN npm install
COPY . .
এতে source পরিবর্তন করলে dependency installation cache করা সম্ভব।
42. Dockerfile order কেন এত গুরুত্বপূর্ণ?
একটি ভালো Dockerfile সাধারণত:
Least-changing files
↓
Most-changing files
এই order অনুসরণ করে।
উদাহরণ:
COPY package.json package-lock.json ./
RUN npm ci
COPY src ./src
এখানে dependency file কম change হয়।
Source code বেশি change হয়।
তাই expensive dependency installation আগে রেখে cache benefit পাওয়া যায়।
43. Python dependency caching pattern
ভালো structure:
FROM python:3.12
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]
কারণ source code change হলেও:
requirements.txt
না বদলালে dependency install cache reuse হতে পারে।
44. Dockerfile-এ comments
Comment:
# Base image
FROM python:3.12
# Application directory
WORKDIR /app
Comments readability বাড়ায়।
45. Environment variable ব্যবহার
ধরো application:
import os
port = os.getenv("PORT", "8000")
print(port)
Dockerfile:
FROM python:3.12
WORKDIR /app
COPY . .
ENV PORT=8000
CMD ["python", "app.py"]
Run:
docker run myapp
অথবা runtime override:
docker run -e PORT=9000 myapp
46. Build ARG ব্যবহার
Dockerfile:
ARG PYTHON_VERSION=3.12
FROM python:${PYTHON_VERSION}
WORKDIR /app
COPY . .
CMD ["python", "app.py"]
Build:
docker build \
--build-arg PYTHON_VERSION=3.13 \
-t myapp .
এখানে build-time configuration পরিবর্তন করা যায়।
47. ARG এবং FROM
একটি বিশেষ case:
ARG VERSION=3.12
FROM python:${VERSION}
FROM-এর আগে globally scoped ARG ব্যবহার করা যায়। Docker-এর official reference-এ ARG এবং FROM interaction আলাদাভাবে documented।
48. Multi-stage build — production-এর জন্য অত্যন্ত গুরুত্বপূর্ণ
ধরো Go application build করতে compiler লাগবে।
Development stage:
Go compiler
Source code
Build tools
Dependencies
কিন্তু final application চালাতে শুধু:
Binary
দরকার।
তাহলে কেন final image-এ compiler রাখবে?
এখানেই multi-stage build।
49. Multi-stage build-এর basic structure
FROM golang:1.26 AS builder
WORKDIR /src
COPY . .
RUN go build -o app .
FROM alpine:3.22
WORKDIR /app
COPY --from=builder /src/app .
CMD ["./app"]
এখানে:
Stage 1
builder
↓
compile application
Stage 2
runtime
↓
copy only binary
Docker-এর official documentation অনুযায়ী multi-stage build-এ একাধিক FROM ব্যবহার করে build environment এবং final runtime environment আলাদা করা যায়; COPY --from দিয়ে আগের stage থেকে প্রয়োজনীয় artifact আনা যায়।
50. Multi-stage build কেন দরকার?
এতে final image-এ থাকতে পারে:
Only runtime dependencies
+
Application
এগুলো থাকে না:
Compiler
Source build tools
Development dependencies
Debug tools
ফলে:
Smaller image
+
Smaller attack surface
+
Cleaner production image
Docker-এর current guidance multi-stage builds-কে build বনাম runtime separation এবং final image optimization-এর জন্য recommended approach হিসেবে দেখায়।
51. Node.js production multi-stage example
একটি frontend application ধরো।
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
Flow:
Node image
↓
Install dependencies
↓
Build frontend
↓
dist/
↓
Nginx image
↓
Production
Final image-এ Node compiler/development dependencies রাখার দরকার নেই।
52. Python production multi-stage ধারণা
Python-এ multi-stage একটু application-dependent।
উদাহরণ হিসেবে:
FROM python:3.12 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --prefix=/install \
--no-cache-dir \
-r requirements.txt
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /install /usr/local
COPY . .
CMD ["python", "app.py"]
এখানে dependency install একটি builder stage-এ করা হচ্ছে এবং runtime image-এ তা copy করা হচ্ছে।
53. Development এবং production Dockerfile এক নয়
Development-এ তুমি চাইতে পারো:
Debugger
Hot reload
Source code
Development dependencies
CLI tools
Production-এ চাইতে পারো:
Small image
Only required dependencies
Non-root user
Healthcheck
Deterministic dependencies
No secrets
তাই development এবং production requirements আলাদা করে চিন্তা করতে হবে।
54. Dockerfile security-এর মূল ধারণা
একটি production Dockerfile-এর checklist:
Use trusted base image
Pin appropriate versions
Use .dockerignore
Do not bake secrets
Use non-root user
Use multi-stage builds
Keep image minimal
Remove unnecessary packages
Use vulnerability scanning
Define healthcheck where appropriate
55. Secret কখনো COPY কোরো না
এই project:
.env
থাকলে:
COPY . .
এর মাধ্যমে accidentally secret image-এর build context-এ ঢুকে যেতে পারে।
তাই:
.dockerignore
-এ অন্তত:
.env
*.pem
*.key
জাতীয় sensitive files বাদ দেওয়ার কথা বিবেচনা করো।
56. Secrets-এর জন্য ARG ব্যবহার না করা
খারাপ:
ARG SECRET_KEY
RUN echo "$SECRET_KEY" > secret.txt
বা:
docker build --build-arg SECRET_KEY=abc123 .
কারণ sensitive data build metadata/history-তে expose হওয়ার risk আছে। Docker সরাসরি build arguments-এর মাধ্যমে secrets pass না করার সতর্কতা দেয়।
57. BuildKit secret mount
Sensitive build-time secret প্রয়োজন হলে BuildKit-এর secret mount ব্যবহার করা যায়।
ধারণাগত example:
RUN --mount=type=secret,id=mysecret \
cat /run/secrets/mysecret
Build command environment অনুযায়ী secret:
docker build \
--secret id=mysecret,src=secret.txt \
.
এটি Docker-এর modern build tooling-এর secure secret mechanism-এর অংশ।
58. Non-root container
উদাহরণ:
FROM python:3.12-slim
WORKDIR /app
RUN useradd --create-home appuser
COPY --chown=appuser:appuser . .
USER appuser
CMD ["python", "app.py"]
এখানে application root হিসেবে চলছে না।
এটি security hardening-এর একটি গুরুত্বপূর্ণ layer।
59. HEALTHCHECK practical example
ধরো API server:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=5s \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')" \
|| exit 1
CMD ["python", "app.py"]
এখানে /health endpoint application-এর health report করবে।
60. একটি complete production-oriented example
ধরো FastAPI application:
project/
├── Dockerfile
├── .dockerignore
├── requirements.txt
└── app/
└── main.py
Dockerfile:
FROM python:3.12-slim
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
RUN useradd --create-home appuser
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY --chown=appuser:appuser ./app ./app
USER appuser
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
এখানে আমরা অনেক concept একসাথে ব্যবহার করেছি:
FROM
WORKDIR
ENV
RUN
COPY
USER
EXPOSE
CMD
61. CMD-এর একটি common ভুল
খারাপ:
CMD ["uvicorn app.main:app --host 0.0.0.0 --port 8000"]
এখানে পুরো command একটিমাত্র argument হয়ে যেতে পারে।
বরং:
CMD [
"uvicorn",
"app.main:app",
"--host",
"0.0.0.0",
"--port",
"8000"
]
অথবা single line:
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
62. Dockerfile-এ cd ব্যবহার করার প্রয়োজন কমাও
খারাপ:
RUN cd /app && npm install
ভালো:
WORKDIR /app
RUN npm install
WORKDIR Dockerfile-কে cleaner এবং predictable করে।
63. Relative path বনাম absolute path
যেমন:
WORKDIR /app
COPY app.py .
এখানে . মানে:
/app
আর:
COPY app.py /app/
explicit।
দুটিই valid, কিন্তু consistent style গুরুত্বপূর্ণ।
64. COPY . . সবসময় best নয়
এটি কাজ করে:
COPY . .
কিন্তু অনেক production Dockerfile-এ আরও precise হওয়া ভালো।
যেমন:
COPY package*.json ./
COPY src ./src
COPY public ./public
এর সুবিধা:
Clear
+
Less accidental files
+
Better control
তবে .dockerignore সঠিক থাকলে COPY . .-ও practical।
65. Dependency lock file ব্যবহার করো
Node:
package-lock.json
Python ecosystem-এ:
requirements.txt
Poetry:
poetry.lock
Modern dependency managers-এ lock file ব্যবহার reproducibility বাড়ায়।
উদাহরণ:
COPY package.json package-lock.json ./
RUN npm ci
সাধারণভাবে:
npm install
এর বদলে CI/production build-এ lockfile-respecting:
npm ci
ভালো choice হতে পারে।
66. Package install এবং cache
Python:
RUN pip install --no-cache-dir -r requirements.txt
এখানে pip-এর local package cache image-এ unnecessarily রেখে না দেওয়ার উদ্দেশ্য থাকে।
Node:
RUN npm ci
এবং multi-stage production build-এ dev dependencies final image থেকে বাদ দিতে পারো।
67. One process per container?
Docker-এর প্রচলিত design philosophy অনুযায়ী একটি container-কে একটি primary service/process-এর চারপাশে design করা সাধারণ এবং operationally সহজ।
উদাহরণ:
Container 1 → Nginx
Container 2 → API
Container 3 → PostgreSQL
Container 4 → Redis
একটি giant container-এর মধ্যে:
Nginx
+
API
+
Database
+
Redis
ঢোকানো সাধারণত ভালো architecture নয়।
Multi-container application-এর জন্য পরে Docker Compose/Kubernetes-এর মতো orchestration layer শেখা দরকার।
68. Dockerfile এবং Docker Compose এক জিনিস নয়
Dockerfile:
একটি image কীভাবে build হবে?
Compose:
একাধিক container/service কীভাবে একসাথে চলবে?
উদাহরণ:
Dockerfile
↓
Build API image
Compose:
API
↓
PostgreSQL
↓
Redis
একটি complete application stack manage করবে।
69. Dockerfile filename
Default filename:
Dockerfile
কোন extension লাগে না।
সাধারণভাবে:
Dockerfile.txt
ভুল।
70. Different Dockerfiles
তুমি চাইলে:
Dockerfile
Dockerfile.dev
Dockerfile.prod
Dockerfile.test
রাখতে পারো।
Build:
docker build -f Dockerfile.dev -t myapp:dev .
অথবা:
docker build -f Dockerfile.prod -t myapp:prod .
71. Build command পুরোপুরি বুঝে নাও
docker build -t myapp .
এখানে:
docker build
= image build
-t myapp
= image-এর name/tag
.
= build context
72. Tag ব্যবহার
docker build -t myapp:1.0 .
এখন:
repository = myapp
tag = 1.0
আর:
docker build -t myapp:latest .
অথবা production-এ meaningful versioning:
docker build -t myapp:2026.09.08 .
73. Build তারপর inspect
Build:
docker build -t myapp .
Images:
docker images
Run:
docker run myapp
Container:
docker ps
Logs:
docker logs <container>
Shell:
docker exec -it <container> sh
এই basic commandগুলো Dockerfile শেখার সঙ্গে সঙ্গে practice করা জরুরি।
74. Dockerfile debug করার method
Build error হলে প্রথমে দেখো কোন instruction fail করেছে।
উদাহরণ:
Step 4/7 : RUN npm ci
তার মানে dependency installation step-এ problem।
Container start না হলে:
docker logs <container>
দেখো।
Container-এর ভেতর debug:
docker exec -it <container> sh
75. Shell না থাকলে?
Slim/minimal image-এ সবসময় bash নাও থাকতে পারে।
যেমন Alpine image-এ সাধারণত:
sh
ব্যবহার করতে পারো:
docker exec -it container sh
76. ENTRYPOINT-এর একটি গুরুত্বপূর্ণ বিষয়: signal handling
Production container-এ application যেন OS signals ঠিকভাবে receive করে, তার জন্য exec form গুরুত্বপূর্ণ।
ভালো:
ENTRYPOINT ["./server"]
অথবা:
CMD ["node", "server.js"]
Shell wrapper-এর মাধ্যমে unnecessarily:
CMD ./start.sh
ব্যবহার করলে signal behaviour ভিন্ন হতে পারে।
এজন্য process management ও PID 1 behaviour সম্পর্কে পরে শেখা গুরুত্বপূর্ণ।
77. Shell script দিয়ে startup
যদি script প্রয়োজন হয়:
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
entrypoint.sh:
#!/bin/sh
set -e
echo "Starting application..."
exec "$@"
এখানে exec ব্যবহার করলে child process proper PID/signal behaviour পেতে পারে।
78. Dockerfile lint ও checks
Modern Docker build tooling-এ Dockerfile checks পাওয়া যায়।
Dockerfile-এর syntax ও কিছু common issue detect করতে build/checking facilities ব্যবহার করা যায়। Docker-এর reference-এ parser directives এবং check সম্পর্কিত capability-ও documented।
তাই শুধু:
docker build
জানলেই হবে না।
Production-এ:
Build
+
Lint/check
+
Security scan
workflow রাখা ভালো।
79. Base image selection কীভাবে করবে?
প্রথমে প্রশ্ন:
আমার application কী চালাতে চায়?
Python হলে:
FROM python:3.12-slim
Node হলে:
FROM node:22-alpine
Go হলে:
FROM golang:1.26 AS builder
তারপর runtime image আলাদা হতে পারে।
80. "সবচেয়ে ছোট image" খুঁজলেই হবে?
না।
একটি image ছোট হতে পারে, কিন্তু:
Harder debugging
+
Missing libraries
+
Compatibility problems
+
More complexity
হতে পারে।
তাই লক্ষ্য হওয়া উচিত:
Small enough, secure enough, maintainable enough, reproducible enough.
81. Dockerfile-এ package cleanup কেন করা হয়?
Ubuntu/Debian:
RUN apt-get update && \
apt-get install -y --no-install-recommends curl && \
rm -rf /var/lib/apt/lists/*
এখানে package index cleanup করা হচ্ছে যাতে unnecessary package metadata image-এ পড়ে না থাকে।
82. Multiple RUN বনাম single RUN
এটি:
RUN apt-get update
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*
এর চেয়ে এই pattern সাধারণত ভালো:
RUN apt-get update && \
apt-get install -y --no-install-recommends curl && \
rm -rf /var/lib/apt/lists/*
কারণ related package setup একটি coherent build step-এ রাখা হয়।
তবে "সব RUN সবসময় এক লাইনে combine করতে হবে"—এমন কোনো rule নেই।
Readability ও caching-এর balance রাখতে হবে।
83. Dockerfile design করার formula
একটি নতুন application পেলে এই প্রশ্নগুলো করো:
প্রশ্ন ১
Application কোন runtime চায়?
Python?
Node?
Java?
Go?
Rust?
PHP?
প্রশ্ন ২
কোন base image?
official/runtime image
প্রশ্ন ৩
Working directory?
/app
প্রশ্ন ৪
কী dependencies দরকার?
requirements.txt
package.json
pom.xml
go.mod
প্রশ্ন ৫
কীভাবে install হবে?
RUN ...
প্রশ্ন ৬
কোন files copy করতে হবে?
COPY ...
প্রশ্ন ৭
কোন port?
EXPOSE ...
প্রশ্ন ৮
কী command দিয়ে application start হবে?
CMD ...
প্রশ্ন ৯
Production image আরও ছোট করা যায়?
Multi-stage build
প্রশ্ন ১০
Security hardening কী?
USER
.dockerignore
No secrets
Minimal packages
এই ১০টি প্রশ্নের উত্তর দিতে পারলে তুমি বেশিরভাগ application-এর Dockerfile লিখতে পারবে।
84. Beginner Dockerfile Template
সবচেয়ে basic template:
FROM <base-image>
WORKDIR /app
COPY <dependency-files> .
RUN <install-dependencies>
COPY . .
EXPOSE <port>
CMD ["<command>", "<arg>"]
উদাহরণ:
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
85. Production Dockerfile Template
আরও production-oriented structure:
FROM <builder-image> AS builder
WORKDIR /app
COPY dependency-files ./
RUN <install/build>
COPY source .
RUN <build>
FROM <runtime-image>
WORKDIR /app
RUN <create-non-root-user>
COPY --from=builder <artifact> <destination>
USER <non-root-user>
EXPOSE <port>
HEALTHCHECK ...
ENTRYPOINT ["..."]
CMD ["..."]
সব application-এ এই exact template লাগবে না, কিন্তু design pattern হিসেবে অত্যন্ত useful।
86. Common mistakes
Mistake 1 — Dockerfile-এর শেষে extension
Dockerfile.txt
ভুল।
ব্যবহার:
Dockerfile
Mistake 2 — RUN npm start
ভুল:
RUN npm start
সাধারণভাবে দরকার:
CMD ["npm", "start"]
Mistake 3 — Secret COPY করা
COPY . .
এবং .env ignore না করা।
এটি dangerous হতে পারে।
Mistake 4 — ARG দিয়ে secret
--build-arg PASSWORD=...
secret storage হিসেবে ব্যবহার করা উচিত নয়।
Mistake 5 — Dependency cache নষ্ট করা
COPY . .
RUN npm ci
এর বদলে অনেক ক্ষেত্রে:
COPY package*.json ./
RUN npm ci
COPY . .
ভালো।
Mistake 6 — Container root হিসেবে চালানো
সম্ভব হলে non-root user ব্যবহার করো।
Mistake 7 — Production-এ development tools রেখে দেওয়া
Compiler:
gcc
go compiler
Node build tools
debug utilities
এসব final runtime image-এ সবসময় প্রয়োজন নেই।
Multi-stage build দিয়ে আলাদা করা যায়।
Mistake 8 — COPY . . দিয়ে সবকিছু ঢুকিয়ে দেওয়া
.dockerignore ব্যবহার না করলে:
.git
node_modules
.env
logs
build artifacts
অনিচ্ছাকৃতভাবে build context-এ ঢুকতে পারে।
87. একটি real-world workflow
ধরো তোমার Node API:
my-api/
├── src/
├── package.json
├── package-lock.json
├── .env
├── node_modules/
└── Dockerfile
প্রথমে:
Step 1
.dockerignore:
node_modules
.git
.env
npm-debug.log
coverage
dist
Step 2
Dockerfile:
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY src ./src
EXPOSE 3000
CMD ["node", "src/index.js"]
Step 3
Build:
docker build -t my-api .
Step 4
Run:
docker run -p 3000:3000 my-api
Step 5
Test:
curl http://localhost:3000
এই workflow-টাই Dockerfile শেখার জন্য খুব effective।
88. Dockerfile-এর mental model
Dockerfile দেখার সময় এইভাবে চিন্তা করো:
FROM
আমি কোথা থেকে শুরু করছি?
WORKDIR
আমি কোথায় কাজ করছি?
COPY
কী কী দরকার?
RUN
Image build হওয়ার সময় কী করতে হবে?
ENV / ARG
Configuration কোথায়?
EXPOSE
Application কোন port-এ?
USER
কে application চালাবে?
HEALTHCHECK
Application healthy কিনা কীভাবে জানব?
ENTRYPOINT / CMD
Container start হলে কী হবে?
এই mental model তৈরি হয়ে গেলে Dockerfile আর মুখস্থ করতে হবে না।
89. Dockerfile শেখার জন্য ৫টি project
শুধু theory পড়লে Dockerfile পুরোপুরি শেখা যাবে না।
এই sequence-এ project করো।
Project 1 — Python CLI
Python script
↓
Dockerfile
↓
Image
↓
Container
শিখবে:
FROM
WORKDIR
COPY
CMD
Project 2 — Node API
শিখবে:
package.json
npm ci
EXPOSE
ENV
.dockerignore
Project 3 — FastAPI/Flask
শিখবে:
Port
Environment variable
USER
HEALTHCHECK
Project 4 — React/Vite
শিখবে:
Multi-stage build
Node builder
Nginx runtime
Project 5 — Full stack
Frontend
+
Backend
+
Database
এখানে Dockerfile-এর সঙ্গে Docker Compose শেখা শুরু করবে।
90. Dockerfile বনাম Image বনাম Container
এই তিনটি গুলিয়ে ফেলবে না।
Dockerfile
│
│ docker build
↓
Docker Image
│
│ docker run
↓
Container
Dockerfile
Recipe।
Image
Built package/template।
Container
Running instance।
উদাহরণ:
Dockerfile = রান্নার recipe
Image = তৈরি খাবারের package
Container = সেই package থেকে চালু হওয়া instance
91. Dockerfile-এর সবচেয়ে important ১২টি instruction
শুরুতে এইগুলো solid করো:
FROM
WORKDIR
COPY
RUN
ENV
ARG
EXPOSE
USER
CMD
ENTRYPOINT
HEALTHCHECK
এর সঙ্গে:
.dockerignore
অবশ্যই শিখবে।
92. Production-level Dockerfile checklist
Deploy করার আগে নিজের Dockerfile-কে জিজ্ঞাসা করো:
[ ] Base image কি যথাযথ?
[ ] Version কি predictable?
[ ] WORKDIR explicitly set?
[ ] .dockerignore আছে?
[ ] Dependency আগে copy করা হয়েছে?
[ ] Cache ভালোভাবে ব্যবহার হচ্ছে?
[ ] Unnecessary packages বাদ?
[ ] Secrets image-এ ঢুকছে না?
[ ] ARG দিয়ে secret দেওয়া হচ্ছে না?
[ ] Non-root user ব্যবহার করা যায়?
[ ] Multi-stage build দরকার কি?
[ ] Correct EXPOSE?
[ ] Correct CMD/ENTRYPOINT?
[ ] Healthcheck প্রয়োজন?
[ ] Final image unnecessarily বড় কি?
[ ] Dependency lock file ব্যবহার করা হয়েছে?
93. একটি complete example — সবকিছু একসঙ্গে
ধরো Node backend production-এর জন্য:
# syntax=docker/dockerfile:1
FROM node:22-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:22-alpine AS production
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup -S appgroup && \
adduser -S appuser -G appgroup
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
USER appuser
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=5s \
CMD wget --spider -q http://localhost:3000/health || exit 1
CMD ["node", "dist/index.js"]
এখানে আমরা শিখলাম:
syntax directive
↓
multi-stage build
↓
WORKDIR
↓
dependency caching
↓
npm ci
↓
production dependencies
↓
non-root user
↓
EXPOSE
↓
HEALTHCHECK
↓
CMD
এ ধরনের structure production Dockerfile বোঝার জন্য একটি ভালো reference pattern।
94. Dockerfile লেখার golden rules
এগুলো মুখস্থ করার চেয়ে বুঝে রাখো:
Rule 1
Base image carefully choose করো।
FROM python:3.12-slim
Rule 2
WORKDIR explicitly set করো।
WORKDIR /app
Rule 3
Dependency files আগে copy করো।
COPY package*.json ./
RUN npm ci
Rule 4
Source code পরে copy করো।
COPY . .
Rule 5
Build command আর startup command আলাদা করো।
RUN → build time
CMD → runtime
Rule 6
Secret Dockerfile-এ bake কোরো না।
Rule 7
.dockerignore ব্যবহার করো।
Rule 8
Production-এ non-root user বিবেচনা করো।
Rule 9
Compiled/build-heavy applications-এ multi-stage build ব্যবহার করো।
Rule 10
Docker cache কীভাবে কাজ করে তা বুঝে instruction order করো।
Docker-এর current build guidance-ও cache efficiency, multi-stage builds এবং clean runtime images-এর ওপর বিশেষ গুরুত্ব দেয়।
95. শেষ পর্যন্ত Dockerfile কীভাবে নিজে লিখবে?
এখন ধরো তোমাকে একজন বলল:
"আমার একটি Java Spring Boot application আছে। এর Dockerfile লিখে দাও।"
তখন তোমার মাথায় automatically এই প্রশ্নগুলো আসা উচিত:
1. কোন Java version?
2. কোন build system?
Maven না Gradle?
3. Dependency file কোনটি?
4. Build artifact কী?
5. Application কোন port-এ চলে?
6. Runtime-এর জন্য পুরো JDK লাগবে?
7. JRE/runtime image যথেষ্ট?
8. Multi-stage build করা যায়?
9. Non-root user ব্যবহার করা যায়?
10. Health endpoint আছে?
তারপর structure:
Builder stage
↓
Copy dependency descriptors
↓
Download dependencies
↓
Copy source
↓
Build
↓
Runtime stage
↓
Copy artifact
↓
USER
↓
EXPOSE
↓
ENTRYPOINT/CMD
এটাই Dockerfile লেখার আসল skill।
96. সবচেয়ে গুরুত্বপূর্ণ বিষয়
Dockerfile শেখার সময় instruction মুখস্থ করার চেষ্টা কোরো না।
বরং বুঝো:
FROM
↓
Environment কোথা থেকে?
WORKDIR
↓
কোথায় কাজ?
COPY
↓
কী দরকার?
RUN
↓
Build-এর সময় কী করতে হবে?
ENV / ARG
↓
Configuration কী?
USER
↓
কে process চালাবে?
EXPOSE
↓
কোন port?
HEALTHCHECK
↓
Healthy কিনা কীভাবে বুঝব?
ENTRYPOINT / CMD
↓
Container start হলে কী করবে?
এই logic বুঝে গেলে language বদলালেও Dockerfile লিখতে পারবে।
Python:
FROM python:3.12-slim
Node:
FROM node:22-alpine
Java:
FROM eclipse-temurin:21
Go:
FROM golang:1.26 AS builder
Language আলাদা হলেও Dockerfile-এর চিন্তার পদ্ধতি একই থাকে।
97. এক লাইনে পুরো Dockerfile philosophy
শেষে এই pattern-টি মনে রাখো:
Choose base
↓
Set working directory
↓
Copy dependency files
↓
Install dependencies
↓
Copy source code
↓
Build application
↓
Remove unnecessary build/runtime baggage
↓
Create non-root runtime
↓
Expose application port
↓
Define health
↓
Define startup command
আর production application হলে:
Dockerfile
│
↓
Multi-stage build
┌────┴────┐
↓ ↓
Builder Runtime
│ │
Build tools Minimal
Dependencies Dependencies
Source Artifact
│ │
└────┬────┘
↓
Small production
image
এই mental model আয়ত্ত করতে পারলে Dockerfile আর "মুখস্থ করার syntax" থাকবে না—এটি হয়ে যাবে application packaging ও deployment design-এর একটি tool।
Top comments (0)