কীভাবে ডকার ইমেজের সাইজ ৯৯% পর্যন্ত কমানো যায়?

আমরা যারা বিগিনার, তারা অনেক সময় না বুঝেই bloated image ব্যবহার করি। Bloated image-এ অপ্রয়োজনীয় build tools এবং dependencies থাকে। Bloated image ব্যবহার করলে:

১. ডেভেলপমেন্টের সময় বেশি সময় লাগে।
২. অনেক বেশি স্পেস প্রয়োজন হয়।
৩. এটি লাইভ করলে, সিকিউরিটি ইস্যু থাকে, কারণ অনেক ট্যুল ইনস্টল করা থাকে।

সিঙ্গেল-স্টেজ Dockerfile

চলুন আমরা একটি Python-এর bloated image-এর উদাহরণ দেখি:

FROM python:3.12
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python3", "main.py"]

এটি যদি আমরা রান করি, তাহলে প্রায় ১ জিবি স্পেস নিবে। এখন আমরা এটি অপ্টিমাইজ করার চেষ্টা করবো।

মিনিমাল বেইজ ইমেজ ব্যবহার করা

আমরা সব সময় মিনিমাল বেস (slim, alpine) ইমেজ ব্যবহার করবো। মোটামুটি সব ধরনের অ্যাপ্লিকেশনের জন্য slim ইমেজ উপযুক্ত। একদম সিম্পল অ্যাপের জন্য alpine ইমেজ সঠিক হবে। তবে যদি দেখেন alpine ইমেজে অনেক অতিরিক্ত প্যাকেজ ইনস্টল করতে হচ্ছে, তাহলে slim ইমেজ ব্যবহার করবেন।

মাল্টি-স্টেজ Dockerfile

এটিই হচ্ছে গেম চেঞ্জার। এটি মূলত বিল্ড টাইমের জন্য প্রয়োজনীয় ডিপেন্ডেন্সি এবং রানটাইমের জন্য প্রয়োজনীয় ডিপেন্ডেন্সি আলাদা করার সুবিধা দেয়।

সহজ ভাষায় বলা যায়, আপনি প্রথমে ডকার ইমেজে কোড কম্পাইল বা বিল্ড করবেন (যেখানে বড় টুলস বা লাইব্রেরি দরকার), এরপর সেই বিল্ড থেকে শুধু প্রয়োজনীয় ফাইলগুলো নিয়ে আরেকটি ইমেজ তৈরি করবেন যা রানটাইমে দরকার। ফলে, ফাইনাল ইমেজে শুধু দরকারি ফাইল থাকবে, অপ্রয়োজনীয় বড় টুলস বা লাইব্রেরি থাকবে না।

চলুন আমরা সিঙ্গেল-স্টেজ Dockerfile-কে ২টি স্টেজে ভাগ করি।

# Stage 1: Build Stage
FROM python:3.12-slim AS build
WORKDIR /app

RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    gcc \
    patchelf \
    && rm -rf /var/lib/apt/lists/*

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .

RUN pip install pyinstaller staticx
RUN pyinstaller --onefile main.py
RUN staticx /app/dist/main /app/main.static

# Stage 2: Runtime Stage
FROM scratch

# Create tmp directory
WORKDIR /tmp
WORKDIR /app

# Copy the static binary
COPY --from=build /app/main.static /app/main

# Set the entry point to the executable
ENTRYPOINT ["/app/main"]

এখানে বিল্ড স্টেজে বড় ডিপেন্ডেন্সিগুলো ব্যবহার করা হচ্ছে, যেমন: Python 3.12-slim, gcc, এবং অন্যান্য কম্পাইলার টুলস। তারপর কোড কপি করে PyInstaller এবং StaticX ব্যবহার করেছি, যা আমাদের Python স্ক্রিপ্টকে একটি স্ট্যাটিক এক্সিকিউটেবল ফাইল তৈরি করতে সাহায্য করছে।

আমরা বিল্ড স্টেজে slim ইমেজ ইউজ করেছি। আমরা bloated ইমেজও ব্যবাহার করতে পারি। এটি আসলে আপনার অ্যাপ্লিকেশন অনুযায়ী সিদ্ধান্ত নিতে হবে।

রানটাইম স্টেজে আমরা একটি একেবারে ছোট, ফাঁকা বেস ইমেজ scratch ব্যবহার করছি, যেখানে কোনো অতিরিক্ত প্যাকেজ নেই। আমরা শুধু বিল্ড স্টেজ থেকে তৈরি হওয়া স্ট্যাটিক এক্সিকিউটেবল ফাইলটিকে কপি করে ব্যবহার করছি।

  • এখানে scratch ইমেজ ব্যবহার করার ফলে ইমেজের সাইজ একেবারে কমে গেছে, কারণ রানটাইমে আমাদের শুধুমাত্র অ্যাপ্লিকেশনটি চালানোর জন্য দরকারি ফাইলগুলোই ব্যবহার করা হচ্ছে।

  • স্ট্যাটিক বাইনারি main ফাইলটি কপি করা হয়েছে এবং ENTRYPOINT এ সেট করা হয়েছে, যার মাধ্যমে কন্টেইনারটি চালু হবে।

এখন যদি এই Dockerfile রান করি, তাহলে এটি মাত্র 8 MB এর মতো স্পেস নিবে।

এভাবে Multi-Stage Build ব্যবহার করে আপনি একটি ছোট, কমপ্যাক্ট এবং সিকিউর ডকার ইমেজ তৈরি করতে পারেন।

আমি আরো কিছু বিষয় শেয়ার করতেছি।

ল্যায়ার অপটিমাইজেশন

Dockerfile এ যখন আপনি কোনো RUN, COPY, বা ADD কমান্ড ব্যবহার করেন, তখন প্রতিটি কমান্ড একটি নতুন লেয়ার তৈরি করে। প্রতিটি লেয়ার ইমেজের সাইজ এবং বিল্ড টাইম বাড়ায়। যেমন:

  • RUN: যেকোনো কমান্ড রান করানোর জন্য ব্যবহার করা হয়, যেমন apt install বা npm install, এগুলো নতুন লেয়ার তৈরি করে।
  • COPY: ফাইল বা ডিরেক্টরি কপি করতে ব্যবহার করা হয়, এবং প্রতিটি কপি অপারেশন নতুন লেয়ার অ্যাড করে।
  • ADD: এটা COPY এর মতোই কাজ করে, তবে কিছু অতিরিক্ত ফিচার নিয়ে আসে, যেমন রিমোট ইউআরএল থেকে ফাইল ডাউনলোড করা বা ফাইলকে আনজিপ করা।

প্রতিটি লেয়ার ইমেজের সাইজ বাড়ায়, কারণ লেয়ারগুলো একটার ওপর আরেকটা তৈরি হয়, এবং প্রতিটি লেয়ার ডকার ইমেজে সেভ থাকে। এছাড়াও, প্রতিটি লেয়ার নতুনভাবে তৈরি হলে বিল্ড টাইমও কিছুটা বেড়ে যায়।

ডকার ইমেজকে ছোট রাখার জন্য একাধিক RUN কমান্ডকে একত্রিত করা বেটার। যেমন:

# from
RUN apt-get update
RUN apt-get install -y --no-install-recommends \
    build-essential \
    gcc
RUN rm -rf /var/lib/apt/lists/*

# to
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    gcc \
    patchelf \
    && rm -rf /var/lib/apt/lists/*

আমরা কখন “bloated” ইমেজ ব্যবহার করব?

এটি মুলত builder ইমেজ হিসেবে মাল্টি-স্টেজ বিল্ডে ইউজ করবো।

Distroless ইমেজ

এটি slim থেকে ৩০% বা তারও বেশি হালকা সাইজের ইমেজ। এই ইমেজগুলিতে সাধারণত কোন প্যাকেজ ম্যানেজার বা শেল থাকে না, ফলে হ্যাকাদের আক্রমণের সুযোগ কম থাকে। Distroless ইমেজগুলিতে শুধু অ্যাপ্লিকেশন এবং অ্যাপ্লিকেশন চালানোর জন্য প্রয়োজনীয় dependency গুলো থাকে।

Scratch ইমেজ

এটি একেবারে খালি, সবচেয়ে ছোট এবং হালকা ইমেজ। কোন ধরনের অপারেটিং সিস্টেম বা utility tools থাকে না।

যেহেতু এখানে কিছুই নেই, আপনাকে নিজেই সব কিছু কনফিগার করতে হবে। আপনার অ্যাপ্লিকেশন চালানোর জন্য প্রয়োজনীয় সব কিছু ম্যানুয়ালি যোগ করতে হয়।

আপনার যদি অত্যন্ত lightweight container প্রয়োজন হয়, যেখানে security বা speed একটি বড় concern, সেখানে আপনি scratch ইমেজ ইউজ করতে পারেন।

3 Likes

চেস্টা করে দেখবো। সময় থাকলে একটা ভিডিও বানাইয়েন

1 Like