Docker: أوامر Dockerfile المتقدمة

آخر تحديث: 2026-08-26

Dockerfiles على مستوى الإنتاج يجب ألا تعمل فقط، بل يجب أن تكون آمنة وقابلة للتكوين والمراقبة — كل ذلك يتحقق من خلال التعليمات المتقدمة.

1. ما ستتعلمه



2. قصة عن تدقيق أمني

(1) نقطة الألم: تشغيل الحاويات كـ root ثغرة عالية المخاطر

يشير تقرير التدقيق الأمني لتشارلي إلى أن "الحاويات التي تعمل كـ root" هي ثغرة عالية المخاطر. إذا تمكن مهاجم من الوصول إلى حاوية من خلال ثغرة تطبيق، فسيحصل على صلاحيات root ويمكنه تعديل ملفات النظام وتركيب أدلة المضيف. درجة التدقيق 45 نقطة فقط.

(2) حلول تأمين Dockerfiles

أضافت أليس سطرًا USER appuser إلى Dockerfile، مما رفع درجة الأمان من 45 إلى 85.

DOCKERFILE
# تعزيز الأمان: التشغيل كمستخدم غير root
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .

# إنشاء والتبديل إلى مستخدم غير root
RUN useradd -m appuser
USER appuser

CMD ["python", "app.py"]

(3) الفائدة: مضاعفة درجة الأمان

أضفت سطرين فقط (RUN useradd + USER)، وارتفعت درجة الأمان من 45 إلى 85، واجتازت التدقيق.



3. COPY مقابل ADD

(1) مقارنة الميزات

الميزة COPY ADD
نسخ الملفات المحلية إلى الصورة
تنزيل ملف من URL
استخراج تلقائي لـ tar/gzip/bzip2/xz
بناء متعدد المراحل --from

(2) مبادئ الاختيار

📌 نقطة أساسية: أفضل ممارسة هي استخدام COPY فقط. سلوك الاستخراج التلقائي وتنزيل URL لـ ADD غير متوقع وعرضة للأخطاء. عند الحاجة إلى الاستخراج، استخدم صراحةً أمر RUN tar لمزيد من الشفافية والتحكم.

▶ مثال: اختلافات السلوك بين COPY و ADD (الصعوبة: ⭐⭐)

DOCKERFILE
# COPY: ينسخ ملف tar كما هو ببساطة
COPY archive.tar.gz /tmp/
# النتيجة: /tmp/archive.tar.gz (لا يزال مضغوطًا)

# ADD: يستخرج ملف tar تلقائيًا
ADD archive.tar.gz /tmp/
# النتيجة: /tmp/archive/ (المحتويات المستخرجة)

▶ مثال: بناء متعدد المراحل مع COPY --from (الصعوبة: ⭐⭐⭐)

DOCKERFILE
# متعدد المراحل: نسخ الناتج من مرحلة builder
FROM golang:1.22 AS builder
WORKDIR /src
COPY . .
RUN go build -o server

FROM alpine:3.19
COPY --from=builder /src/server /usr/local/bin/server
CMD ["server"]


  1. ARG و ENV

(1) مقارنة نطاق التطبيق

البُعد ARG ENV
المراحل المتاحة وقت البناء (docker build) وقت التشغيل (docker run)
الاستمرارية لا يُكتب في بيانات الصورة الوصفية يُكتب في بيانات الصورة الوصفية
قابل للتجاوز --build-arg docker run -e
CMD/ENTRYPOINT متاح
الأمان غير مكشوف وقت التشغيل مكشوف وقت التشغيل (مرئي عبر docker inspect)
100%
graph TB
    BUILD["وقت البناء"] -->|ARG| LAYER["طبقة الصورة"]
    RUN["وقت التشغيل"] -->|ENV| CONTAINER["بيئة الحاوية"]
    BUILD -->|ENV يستمر| CONTAINER

▶ مثال: ARG بناء رقم الإصدار (الصعوبة: ⭐⭐)

DOCKERFILE
# استخدام ARG لمتغيرات وقت البناء
ARG PYTHON_VERSION=3.12
FROM python:${PYTHON_VERSION}-slim

ARG APP_VERSION=1.0
LABEL version="${APP_VERSION}"

WORKDIR /app
COPY . .
CMD ["python", "app.py"]
BASH
# بناء مع إصدار Python مخصص
docker build --build-arg PYTHON_VERSION=3.11 -t myapp:3.11 .

# بناء مع إصدار تطبيق مخصص
docker build --build-arg APP_VERSION=2.0 -t myapp:v2.0 .

▶ مثال: ENV إعداد متغير البيئة (الصعوبة: ⭐⭐)

DOCKERFILE
# ENV: متاح وقت التشغيل
FROM python:3.12-slim

ENV APP_PORT=5000 \
    APP_HOST=0.0.0.0 \
    LOG_LEVEL=info

WORKDIR /app
COPY . .
CMD ["python", "app.py"]
BASH
# تجاوز ENV وقت التشغيل
docker run -d -e APP_PORT=8080 -e LOG_LEVEL=debug myapp:1.0
⚠️ ملاحظة: لا تخزن معلومات حساسة (كلمات مرور/مفاتيح) في متغيرات ENV، لأنها ستُكتب في بيانات الصورة الوصفية ويمكن لأي شخص رؤيتها بـ docker inspect. احقن المعلومات الحساسة وقت التشغيل باستخدام docker run -e، أو استخدم Docker Secrets.



4. WORKDIR دليل العمل

▶ مثال: WORKDIR—تعيين دليل العمل (الصعوبة: ⭐)

DOCKERFILE
# WORKDIR يعين دليل العمل للتعليمات اللاحقة
FROM python:3.12-slim

# كل WORKDIR ينشئ الدليل إذا لم يكن موجودًا
WORKDIR /app
COPY . .

# WORKDIR يمكن أن يكون نسبيًا (نسبة إلى WORKDIR السابق)
WORKDIR src
RUN pwd  # المخرجات: /app/src
القاعدة الوصف
استخدام مسارات مطلقة WORKDIR /app بدلاً من WORKDIR app
إنشاء تلقائي إنشاء تلقائي إذا لم يكن الدليل موجودًا
يؤثر على RUN/CMD/ENTRYPOINT/COPY الأوامر اللاحقة تنفذ بناءً على WORKDIR
لا تستخدم RUN cd RUN cd /app && ... صالح فقط لـ RUN الحالي؛ WORKDIR يبقى ساري المفعول


5. مبادئ الأمان للمستخدمين غير root

(1) مخاطر تشغيل الحاويات كـ root

المخاطرة الوصف
تصعيد الصلاحيات ثغرة الحاوية + صلاحيات root = يحصل المهاجم على صلاحيات root على المضيف
تعديل الملفات أي ملف داخل الحاوية (بما في ذلك ملفات النظام) يمكن تعديله
مخاطر التركيب عند تركيب دليل مضيف، يمكن للحاوية root تعديل ملفات المضيف
CIS Benchmark "الحاويات تعمل كمستخدم غير root" متطلب إلزامي في خط أساس أمان CIS Docker

▶ مثال: التشغيل كمستخدم USER غير root (الصعوبة: ⭐⭐)

DOCKERFILE
# أفضل ممارسة: إنشاء مستخدم مخصص والتبديل إليه
FROM python:3.12-slim

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

# إنشاء مستخدم غير root بـ UID/GID محدد
RUN groupadd -r appgroup && \
    useradd -r -g appgroup -u 1000 -m appuser

# ضمان أن مستخدم التطبيق يملك ملفات التطبيق
RUN chown -R appuser:appgroup /app

# التبديل إلى مستخدم غير root
USER appuser

CMD ["python", "app.py"]
🔒 الأمان: جميع الأوامر (RUN/CMD/ENTRYPOINT) بعد USER appuser تنفذ كمستخدم appuser. حتى لو حصل مهاجم على وصول إلى الحاوية، فلن يكون لديه صلاحيات root.



6. EXPOSE إعلان المنفذ

▶ مثال: EXPOSE إعلان المنفذ (الصعوبة: ⭐)

DOCKERFILE
# EXPOSE يوثق المنافذ التي تستمع عليها الحاوية
FROM python:3.12-slim
WORKDIR /app
COPY . .
EXPOSE 5000
CMD ["python", "app.py"]
⚠️ ملاحظة: EXPOSE هو إعلان توثيقي؛ لا يكشف المنفذ فعليًا. تعيين منفذ الحاوية لا يزال يتطلب docker run -p 5000:5000. الغرض من EXPOSE هو: ① التوثيق؛ ② docker run -P يختار تلقائيًا المنافذ المعلنة بـ EXPOSE عند إجراء تعيين عشوائي.



7. HEALTHCHECK فحص الصحة

يسمح HEALTHCHECK لـ Docker بالتحقق تلقائيًا مما إذا كانت التطبيقات داخل الحاويات سليمة وإعادة تشغيلها تلقائيًا إذا لم تكن كذلك.

(1) صيغة فحص الصحة

DOCKERFILE
HEALTHCHECK [OPTIONS] CMD command
الخيار الافتراضي الوصف
--interval 30s فترة الفحص
--timeout 30s المهلة
--start-period 0s فترة سماح بدء تشغيل الحاوية
--retries 3 وضع علامة "unhealthy" بعد X فشل متتالي

▶ مثال: HEALTHCHECK فحص curl (الصعوبة: ⭐⭐)

DOCKERFILE
# فحص الصحة باستخدام curl
FROM python:3.12-slim

WORKDIR /app
COPY . .
RUN apt-get update && \
    apt-get install -y --no-install-recommends curl && \
    rm -rf /var/lib/apt/lists/*

EXPOSE 5000

HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD curl -f http://localhost:5000/health || exit 1

CMD ["python", "app.py"]
BASH
# التحقق من حالة الصحة
docker inspect myapp --format='{{.State.Health.Status}}'
💻 المخرجات:

TEXT 📖 للعرض فقط
healthy

(1) وصف حالة الصحة

الحالة المعنى سلوك Docker
starting خلال فترة السماح (start-period) لا تُحتسب
healthy اجتاز الفحص يعمل بشكل طبيعي
unhealthy فشل في المحاولات المتتالية يشغل تنبيهًا؛ يمكن إعادة التشغيل تلقائيًا عند الدمج مع سياسة إعادة التشغيل


8. LABEL بيانات وصفية

▶ مثال: إضافة بيانات وصفية إلى LABEL (الصعوبة: ⭐)

DOCKERFILE
# LABEL يضيف بيانات وصفية إلى الصورة
LABEL maintainer="alice@example.com"
LABEL version="1.0"
LABEL description="Flask web application for production"
LABEL org.opencontainers.image.source="https://github.com/example/app"


9. مثال كامل: كتابة Dockerfile آمن لتطبيق Spring Boot

DOCKERFILE
# ============================================
# Dockerfile على مستوى الإنتاج لـ Spring Boot
# الميزات: مستخدم غير root، HEALTHCHECK، ARG، LABEL
# ============================================

# معامل بناء لاسم ملف JAR
ARG JAR_FILE=app.jar

# المرحلة 1: بناء (متعدد المراحل مستقبلاً، هنا مجرد نسخ)
FROM eclipse-temurin:21-jre-alpine

# بيانات وصفية
LABEL maintainer="dev-team@example.com"
LABEL version="2.0"

# إنشاء مستخدم غير root
RUN addgroup -S appgroup && \
    adduser -S appuser -G appgroup

# تعيين دليل العمل
WORKDIR /app

# نسخ ملف JAR (استخدام ARG للمرونة)
COPY target/${JAR_FILE} app.jar

# ضمان أن مستخدم التطبيق يملك الملفات
RUN chown -R appuser:appgroup /app

# التبديل إلى مستخدم غير root
USER appuser

# كشف منفذ التطبيق
EXPOSE 8080

# فحص الصحة
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
  CMD wget -qO- http://localhost:8080/actuator/health || exit 1

# تشغيل التطبيق
ENTRYPOINT ["java", "-jar", "app.jar"]
CMD ["--server.port=8080"]
BASH
# بناء مع اسم JAR مخصص
docker build --build-arg JAR_FILE=myapp-2.0.jar -t spring-app:2.0 .

# تشغيل مع تجاوز البيئة
docker run -d -p 8080:8080 --name spring spring-app:2.0

# التحقق من حالة الصحة
docker inspect spring --format='User: {{.Config.User}}, Health: {{.State.Health.Status}}'
💻 المخرجات:

TEXT 📖 للعرض فقط
User: appuser, Health: healthy

❓ أسئلة شائعة

س هل يمكن لـ ADD استخراج أرشيفات tar تلقائيًا؟
ج نعم، لكن هذه "ميزة فخ" — إذا كنت تريد فقط نسخ ملف tar (بدون استخراجه)، فسيقوم ADD باستخراجه بشكل غير متوقع. أفضل ممارسة: استخدم COPY حصريًا، واستخدم صراحةً RUN tar -xzf file.tar.gz عندما تحتاج إلى الاستخراج، لضمان سلوك شفاف وقابل للتحكم.
س ما الفرق بين ARG و ENV؟
ج ARG متاح فقط أثناء عملية البناء ولا يُكتب في الصورة؛ ENV يُكتب في الصورة ويكون مرئيًا أيضًا وقت التشغيل. قاعدة بسيطة: استخدم ENV لأي شيء يحتاج أن يكون متاحًا وقت التشغيل (مثل إعدادات المنفذ)، واستخدم ARG لأي شيء يُستخدم فقط أثناء البناء (مثل أرقام الإصدارات أو روابط التنزيل). استخدم -e وقت التشغيل لتخزين كلمات المرور، وليس ENV.
س كيف يجب أن أعد HEALTHCHECK لتجنب الإيجابيات الكاذبة؟
ج ثلاث نقاط رئيسية: ① عيّن --start-period للسماح بوقت كافٍ لبدء التطبيق (30 ثانية على الأقل لتطبيقات Java)؛ ② تحقق من نقطة نهاية الصحة الفعلية للتطبيق (مثل /health)؛ لا تتحقق فقط من أن المنفذ يمكن الوصول إليه؛ ③ تأكد من أن --timeout لا يتجاوز نصف --interval لتجنب تراكم الفحوصات.
س لماذا لا ينبغي تشغيل الحاويات كـ root؟
ج عندما تعمل الحاوية كـ root، فإن المهاجم الذي يحصل على وصول إلى الحاوية من خلال ثغرة تطبيق سيحصل على صلاحيات root. بالدمج مع ثغرة kernel، يمكن أن يؤدي ذلك إلى الهروب إلى المضيف. التشغيل كمستخدم غير root يقلل بشكل كبير من سطح الهجوم — يسرد CIS Docker Benchmark "التشغيل كمستخدم غير root" كمتطلب إلزامي.
س هل EXPOSE يكشف المنافذ فعليًا؟
ج لا. EXPOSE هو مجرد إعلان توثيقي يخبر المستخدمين بالمنافذ التي تنوي الحاوية استخدامها. التعيين الفعلي يتطلب docker run -p أو -P. -P (بأحرف كبيرة) يعين تلقائيًا المنافذ المعلنة بـ EXPOSE إلى منافذ عشوائية على المضيف.
س كيف يمكنني التحقق من أن الحاوية تعمل كمستخدم غير root؟
ج docker exec <حاوية> whoami يجب أن يعيد اسم مستخدم غير root. أو استخدم docker inspect <حاوية> --format='{{.Config.User}}' لعرض المستخدم المكون.

📖 ملخص


📝 تمارين

  1. تمرين أساسي (الصعوبة: ⭐): أضف مستخدمًا غير root إلى Dockerfile في الدرس 7. بعد بناء الصورة، استخدم docker exec للتحقق من أن whoami لا يعيد "root".
  2. تمرين متقدم (الصعوبة: ⭐⭐): أضف تعليمة HEALTHCHECK واستخدم curl للتحقق من نقطة نهاية الصحة للتطبيق. بعد بناء التطبيق وتشغيله، استخدم docker inspect لعرض Health.Status.
  3. تحدٍ (الصعوبة: ⭐⭐⭐): اكتب Dockerfile كاملاً على مستوى الإنتاج لتطبيق Flask من الدرس 7، متضمنًا: ARG رقم الإصدار + إعداد ENV + مستخدم غير root + HEALTHCHECK + LABEL. ثم استخدم docker scout quickview أو trivy image لفحص الصورة بحثًا عن ثغرات أمنية.
Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%