A Complete Guide to Writing Dockerfiles from Beginner to Production
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 উদাহরণ: EXPO
Comments
No comments yet. Start the discussion.