قبل ساعتين
مقدمة
«يعمل على جهازي» جملة يعرفها كل مبرمج. Docker يحزم التطبيق مع بيئته (نظام التشغيل الأساسي، والمكتبات، والإعدادات) في صورة واحدة تعمل بالطريقة نفسها على أي جهاز. هذا الدرس يغطي الأساسيات مع ممارسات أمان من البداية.
أهداف التعلم
- التمييز بين الصورة والحاوية والطبقات.
- كتابة Dockerfile بمراحل متعددة ومستخدم غير جذري.
- تمرير الإعدادات والأسرار دون وضعها في الصورة.
- تشغيل خدمات متعددة بـ Docker Compose.
1. المفاهيم
- الصورة (Image): قالب للقراءة فقط مكون من طبقات.
- الحاوية (Container): نسخة تعمل من الصورة، معزولة عن العمليات الأخرى.
- الطبقات: كل تعليمة في Dockerfile تنشئ طبقة؛ ويعيد Docker استخدام الطبقات غير المتغيرة فيسرّع البناء.
2. Dockerfile لتطبيق Node.js
# مرحلة البناء
FROM node:22-slim AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build && npm prune --omit=dev
# مرحلة التشغيل: أصغر وبلا أدوات البناء
FROM node:22-slim
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
COPY package.json ./
USER node
EXPOSE 3000
CMD ["node", "dist/server.js"]
- نسخ
package.jsonقبل الكود يجعل طبقةnpm ciتُعاد استخدامها ما دامت التبعيات لم تتغير. - المراحل المتعددة تُبقي المترجمات وملفات المصدر خارج الصورة النهائية.
USER nodeيشغل التطبيق بمستخدم غير جذري، فثغرة في التطبيق لا تعطي صلاحيات root داخل الحاوية.
وأضف ملف .dockerignore:
node_modules
.git
.env
*.log
حتى لا تُنسخ الأسرار أو الملفات الضخمة إلى الصورة.
3. البناء والتشغيل
docker build -t arabcode-api:1.0 .
docker run --rm -p 3000:3000 --env-file .env.local arabcode-api:1.0
--rmيحذف الحاوية عند توقفها.- الأسرار تُمرر وقت التشغيل (متغيرات بيئة أو أسرار المنصة)، لا في
ENVداخل Dockerfile ولا في الصورة؛ فالصورة قد تُرفع إلى سجل يراه غيرك، وطبقاتها قابلة للفحص.
4. Docker Compose: التطبيق مع قاعدة البيانات
services:
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
api:
build: .
ports:
- "127.0.0.1:3000:3000"
environment:
DATABASE_URL: postgres://postgres:${DB_PASSWORD}@db:5432/postgres
depends_on:
db:
condition: service_healthy
volumes:
pgdata:
docker compose up -d --build
docker compose logs -f api
- الحجم (Volume)
pgdataيحفظ بيانات القاعدة عند حذف الحاوية. 127.0.0.1:3000:3000ينشر المنفذ على الجهاز المحلي فقط، لا على كل واجهات الشبكة.- القاعدة لا تحتاج منفذاً منشوراً أصلاً؛ التطبيق يصلها عبر الشبكة الداخلية باسم
db.
تمرين عملي
- اكتب Dockerfile لتطبيق صغير (Node أو Python) بمرحلتين ومستخدم غير جذري.
- قارن حجم الصورة بمرحلة واحدة ومرحلتين:
docker images. - شغّل التطبيق مع PostgreSQL عبر Compose، ثم احذف الحاويات (
docker compose down) وأعد تشغيلها وتأكد أن البيانات باقية. - افحص الصورة بحثاً عن ثغرات معروفة:
docker scout cves arabcode-api:1.0أو أداة Trivy.
أخطاء شائعة
- وضع كلمات المرور في Dockerfile أو نسخ ملف
.envإلى الصورة. - التشغيل بصلاحيات root داخل الحاوية.
- نشر منفذ قاعدة البيانات على
0.0.0.0في خادم عام. - استخدام الوسم
latestفي الإنتاج؛ ثبّت إصداراً محدداً. - تخزين بيانات مهمة داخل الحاوية دون حجم دائم.
الخلاصة
الصورة تحزم البيئة، والحاوية تشغلها معزولة. ابنِ بمراحل متعددة، شغّل بمستخدم غير جذري، مرر الأسرار وقت التشغيل، واحفظ البيانات في أحجام دائمة.
مصادر مقترحة
- توثيق Docker: «Dockerfile best practices».
- توثيق Docker Compose.
- OWASP: «Docker Security Cheat Sheet».