کوچک کردن ایمیج داکر Node.js از ۱.۲GB به ۷۸MB
خلاصهٔ کاملتر
نقطه شروع یه Dockerfile معمولیه که خیلی از تیمها ازش استفاده میکنن — کار میکنه، ولی به شدت اسرافکاره. با ایمیج node:22 که مبتنی بر دبیانه و یه toolchain کامل داره که اصلاً در زمان اجرا لازم نیست، سایز نهایی ۱.۲۱ گیگابایت میشه؛ در حالی که خود اپ فقط ۴ مگابایت JavaScript کامپایلشده تولید میکنه.
گام اول: تغییر ایمیج پایه — جایگزینی node:22 با node:22-slim سایز رو به ۴۱۲ مگابایت میرسونه. نسخه Alpine هم ۱۷۸ مگابایته ولی از musl libc به جای glibc استفاده میکنه که ممکنه با ماژولهای native مثل bcrypt یا sharp مشکل ایجاد کنه؛ پس پیشفرض slim منطقیتره.
گام دوم: فایل .dockerignore — دستور COPY . . بدون این فایل، node_modules، .git، فایلهای .env محلی و پوشههای IDE رو هم داخل ایمیج میبره. با یه .dockerignore مناسب، سایز به ۳۸۸ مگابایت میرسه و مهمتر از اون، فایلهای حساس دیگه توی رجیستری عمومی پنهان نمیمونن.
گام سوم: Multi-stage build — این بزرگترین پیشرفته. ایده اینه که TypeScript، ابزارهای تست و صدها وابستگی dev رو فقط برای build نیاز داری، نه برای اجرا. پس در یه stage کامپایل میکنی و npm prune --omit=dev رو اجرا میکنی، بعد فقط خروجی نهایی رو به یه ایمیج تمیز کپی میکنی. سایز از ۳۸۸ به ۱۹۸ مگابایت میرسه.
# ---- builder ----
FROM node:22-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
RUN npm prune --omit=dev
# ---- runtime ----
FROM node:22-slim
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./package.json
EXPOSE 3000
CMD ["node", "dist/index.js"]گام چهارم: ترتیب لایهها برای کش بهتر — اگر COPY . . رو قبل از npm ci بذاری، با هر تغییر کوچیک در کد، کل نصب وابستگیها دوباره اجرا میشه. با کپی کردن package*.json قبل از بقیه فایلها، زمان rebuild از ۹۴ ثانیه به ۱۸ ثانیه رسید — فقط با یه تغییر ترتیب.
گام پنجم: Alpine برای runtime — میشه builder رو روی slim نگه داشت ولی runtime رو به node:22-alpine تغییر داد. JavaScript کامپایلشده به سیستمعامل وابسته نیست و سایز به ۹۶ مگابایت میرسه.
گام ششم: ایمیج distroless گوگل — ایمیجهای distroless فقط runtime نود و گواهینامههای TLS دارن؛ هیچ shell، package manager یا ابزار اضافهای ندارن. این هم سطح حمله رو کاهش میده هم سایز رو به ۷۸ مگابایت میرسونه. یه نکته: چون shell وجود نداره، باید از exec form برای CMD استفاده کنی و فقط اسم فایل رو بدی چون entrypoint خودش nodeه.
FROM gcr.io/distroless/nodejs22-debian12
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./package.json
EXPOSE 3000
CMD ["dist/index.js"]نکات کلیدی:
- تغییر از node:22 به node:22-slim به تنهایی ۶۷٪ حجم رو کم میکنه
- .dockerignore از لیک شدن فایلهای .env و اطلاعات حساس به رجیستری جلوگیری میکنه
- Multi-stage build بزرگترین کاهش حجم رو داره: dev dependencies رو کاملاً کنار میذاره
- ترتیب درست لایهها (کپی package.json قبل از کد) rebuild رو ۵ برابر سریعتر میکنه
- ایمیج distroless امنیت رو هم بالا میبره: صدها CVE روی node:22 در مقابل چند تا روی distroless
- ابزارهایی مثل docker-slim یا pkg معمولاً ارزش پیچیدگیشون رو ندارن




