التطبيق · فصل ٥

Dockerfile لتطبيق حقيقي — Node و React

COPY · WORKDIR · layer cache · .dockerignore · multi-stage build
🎯 الهدف: تكتب Dockerfile لـ API بـ Node وواحد لـ React app، وتفهم الـ layer cache والـ multi-stage عشان الـ image تبقى صغيرة وسريعة.

الـ instructions الأساسية

الـ instructionبيعمل إيه
FROMالـ base image
WORKDIRفولدر الشغل جوه الـ image (ويتعمل لو مش موجود)
COPYينسخ ملفات من الـ build context للـ image
RUNأمر وقت البناء، بيعمل طبقة
ENVمتغيّر بيئة ثابت في الـ image
EXPOSEتوثيق للبورت اللي التطبيق بيسمع عليه (مش بيفتحه)
USERيشغّل اللي بعده بمستخدم معين بدل root
CMDالأمر الافتراضي لما الـ container يقوم

سر السرعة: الـ layer cache

كل instruction بتعمل طبقة، و Docker بيعمل cache لكل طبقة. لو الطبقة وكل اللي قبلها متغيّروش، بيستخدم الكاش. أول ما طبقة تتغيّر، كل اللي بعدها يتبني من جديد.

عشان كده الترتيب مهم: الحاجات اللي بتتغير قليل (الـ dependencies) فوق، والحاجات اللي بتتغير كتير (الكود) تحت.

🧪 Lab: API بـ Node

Dockerfile
FROM node:22-alpineWORKDIR /app# انسخ ملفات الـ dependencies الأول بس → الكاش يفضل شغال لما الكود يتغيرCOPY package.json package-lock.json ./RUN npm ci --omit=dev# بعدين الكودCOPY . .ENV NODE_ENV=productionEXPOSE 3000USER nodeCMD ["node", "src/index.js"]

ولو بتستخدم pnpm، فعّله بـ corepack enable جوه الـ image وانسخ pnpm-lock.yaml بدل package-lock.json (راجع الـ docs لأمر التسطيب المناسب).

.dockerignore

زي .gitignore بس للـ build context. من غيره، COPY . . هينسخ node_modules بتاعتك (وممكن تكون لنظام تشغيل تاني!) و .env بأسرارك.

.dockerignore
node_modulesdist.git.env*.logDockerfiledocker-compose.yml

🧪 Lab: React app بـ multi-stage

React بعد الـ build مجرد ملفات static. مش محتاج Node في الـ production خالص، محتاج web server زي nginx. هنا ييجي الـ multi-stage build: stage يبني، و stage تاني ياخد الناتج بس.

Dockerfile
# Stage 1: البناءFROM node:22-alpine AS buildWORKDIR /appCOPY package.json package-lock.json ./RUN npm ciCOPY . .RUN npm run build# Stage 2: التشغيل — nginx بس + ملفات الـ buildFROM nginx:alpineCOPY --from=build /app/dist /usr/share/nginx/htmlEXPOSE 80

ابني وشغّل

terminal
docker build -t my-api ./apidocker run -d --name api -p 3000:3000 my-apidocker build -t my-web ./webdocker run -d --name web -p 8080:80 my-web

خلّصت الفصل لما

🧠 اختبر نفسك
١) غيّرت سطر في src/index.js. أنهي طبقات هتتبني تاني؟
من COPY . . وانت نازل. طبقة npm ci هتيجي من الكاش.
٢) ليه final image بتاعة React مفيهاش node_modules؟
عشان الـ multi-stage: آخر stage بياخد dist بس من الـ build stage.
٣) عملت docker run -e VITE_API_URL=... والـ React لسه بيكلم الـ URL القديم. ليه؟
متغيّرات Vite بتتحط وقت الـ build، مش وقت التشغيل.