نظرة عامة

يحدد Dockerfile كيفية بناء Docker صورة. تغطي هذه الورقة المرجعية جميع 17 تعليمة أساسية، أنماط متقدمة مثل البناء متعدد المراحل وتثبيتات ذاكرة التخزين المؤقت، أفضل الممارسات الأمنية والأداء، وتقنيات التحسين. جميع الصيغ حالية لـ Docker 27.

التعليمات الأساسية

FROM

التعليمة الغرض مثال
FROM <image>:<tag> تعيين الصورة الأساسية (يجب أن تكون السطر الأول، باستثناء التعليقات/ARG) FROM ubuntu:24.04
FROM <image>:<tag> AS <stage> تعيين مرحلة مسماة في بناء متعدد المراحل FROM golang:1.22 AS builder
FROM scratch البدء من أساس فارغ (للملفات الثنائية الثابتة فقط) FROM scratch

ملاحظات:
– يمكنك استخدام عدة بيانات FROM لإنشاء عدة مراحل بناء.
– تعيد كل FROM تعيين نظام الملفات؛ يتم تجاهل الطبقات السابقة ما لم يتم نسخها صراحةً.
– scratch يحتوي فقط على ما تضيفه صراحةً؛ أصغر صورة ممكنة.

RUN

التعليمة الغرض مثال
RUN <command> تشغيل أمر أثناء البناء (نموذج shell) RUN apt-get update && apt-get install -y curl
RUN ["executable", "param1", "param2"] تشغيل أمر بنموذج exec (بدون shell) RUN ["python3", "-m", "pip", "install", "django"]

أفضل الممارسات:
– استخدم نموذج exec عندما يكون ممكناً لتجنب مشاكل تفسير shell.
– اربط الأوامر بـ && للحفاظ على الطبقات صغيرة: RUN apt-get update && apt-get install && apt-get clean
– نظّف ذاكرة مدير الحزم المؤقتة: rm -rf /var/lib/apt/lists/* (apt)، apk del .build-deps (apk)
– استخدم أعلام --no-cache في مديري الحزم لتقليل حجم الطبقة.

COPY

التعليمة الغرض مثال
COPY <source> <dest> نسخ الملفات/المجلدات من سياق البناء إلى الصورة COPY app.py /app/app.py
COPY --chown=<user>:<group> <source> <dest> النسخ وتعيين الملكية COPY --chown=appuser:appuser . /app/
COPY --chmod=<mode> <source> <dest> النسخ وتعيين أذونات الملف COPY --chmod=755 script.sh /app/script.sh

أفضل الممارسات:
– يُفضل COPY على ADD للنسخ البسيطة للملفات.
– استخدم .dockerignore لاستثناء القطع الأثرية وملفات الاختبار و .git.
– انسخ فقط ما تحتاجه؛ اقسم إلى عدة أسطر COPY لكفاءة ذاكرة التخزين المؤقت.

ADD

التعليمة الغرض مثال
ADD <source> <dest> نسخ الملفات/المجلدات مع ميزات إضافية (استخراج tar وجلب URL) ADD archive.tar.gz /app/
ADD --chown=<user>:<group> <source> <dest> الإضافة مع الملكية ADD --chown=appuser:appuser file.txt /app/
ADD --chmod=<mode> <source> <dest> الإضافة مع أذونات الملف ADD --chmod=644 config.txt /etc/config.txt

ملاحظات:
– إذا كان المصدر أرشيف tar/zip/gzip، يتم استخراجه تلقائياً.
– إذا كان المصدر عنوان URL، يتم تحميله (بدون استخراج).
– عادةً ما يكون COPY أوضح؛ استخدم ADD فقط لاستخراج tar أو جلب URL.

WORKDIR

التعليمة الغرض مثال
WORKDIR <path> تعيين دليل العمل لجميع الأوامر اللاحقة (RUN و CMD و ENTRYPOINT و COPY و ADD) WORKDIR /app

ملاحظات:
– إذا لم يكن المجلد موجوداً، يتم إنشاؤه.
– استخدم المسارات المطلقة لتجنب الالتباس.
– عدة تعليمات WORKDIR تراكمية: WORKDIR /app ثم WORKDIR src تؤدي إلى /app/src.

ENV

التعليمة الغرض مثال
ENV <key>=<value> تعيين متغير بيئي (متاح في الحاوية قيد التشغيل) ENV NODE_ENV=production
ENV <key> <value> صيغة بديلة (عفا عليها الزمن، تجنب) ENV DEBUG true

ملاحظات:
– ينقل إلى الحاويات؛ عيّن مرة واحدة أثناء البناء، متاح في وقت التشغيل.
– استخدم لإعدادات مستوى التطبيق (عناوين URL لقاعدة البيانات وكلمات مرور API للاختبار).
– لا تستخدم ENV للأسرار؛ استخدم أسرار Docker أو مرر في وقت التشغيل.

ARG

التعليمة الغرض مثال
ARG <name>=<default> تحديد متغير وقت البناء (غير متاح في الحاوية قيد التشغيل) ARG PYTHON_VERSION=3.12
ARG <name> تحديد متغير بدون افتراضي (يجب توفيره مع --build-arg) ARG BUILD_NUMBER

الاستخدام في البناء:

docker build --build-arg PYTHON_VERSION=3.11 -t myapp:1.0 .

ملاحظات:
– متغيرات ARG تُستخدم فقط أثناء البناء؛ لا تظهر في الصورة النهائية.
– لتمرير قيمة ARG إلى الحاوية قيد التشغيل، أعد تعيينها باستخدام ENV: ENV PYTHON_VERSION=$PYTHON_VERSION

EXPOSE

التعليمة الغرض مثال
EXPOSE <port> توثيق أن حاوية تستمع على منفذ (لا تنشره) EXPOSE 8080
EXPOSE <port>/udp توثيق منفذ UDP EXPOSE 53/udp
EXPOSE <port1> <port2> توثيق منافذ متعددة EXPOSE 8080 8443

ملاحظات:
– EXPOSE هي بيانات وصفية فقط؛ لا تنشر المنفذ فعلياً.
– للنشر، استخدم docker run -p <host>:<container> أو Docker Compose ports:.
– مفيد للتوثيق ولـ docker run -P (منافذ عالية الرقم عشوائية).

USER

التعليمة الغرض مثال
USER <user> تعيين المستخدم (أو UID) للأوامر اللاحقة (RUN و CMD و ENTRYPOINT و COPY و ADD) USER appuser
USER <uid>:<gid> استخدم UID و GID مباشرة USER 1000:1000

أفضل ممارسة أمنية:

RUN groupadd -r appgroup && useradd -r -g appgroup appuser
USER appuser

ملاحظات:
– التشغيل كـ root في حاوية مخاطرة أمنية.
– استخدم مستخدماً مخصصاً بدون جذر لتحديد دائرة الانفجار عند الهروب من الحاوية.
– يجب إنشاؤها قبل تعليمة USER (استخدم RUN).

HEALTHCHECK

التعليمة الغرض مثال
HEALTHCHECK --interval=<seconds> --timeout=<seconds> --start-period=<seconds> --retries=<count> CMD <command> تحديد أمر فحص صحي HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 CMD curl -f http://localhost:8000/health \|\| exit 1
HEALTHCHECK NONE تعطيل فحص صحي موروث من الصورة الأساسية HEALTHCHECK NONE

الخيارات:
– --interval: عدد مرات تشغيل الفحص (الافتراضي: 30 ثانية)
– --timeout: كم من الوقت ننتظر الفحص (الافتراضي: 30 ثانية)
– --start-period: فترة رحمة قبل الفحص الأول (الافتراضي: 0 ثانية)
– --retries: الأخطاء المتتالية قبل وضع العلامة كغير صحي (الافتراضي: 3)

ملاحظات:
– رمز الخروج 0 = صحي، 1 = غير صحي، 2 = محجوز.
– يستخدم Docker Compose وموجهات الحاويات حالة الصحة لإعادة التشغيل/الاستبدال.

ENTRYPOINT

التعليمة الغرض مثال
ENTRYPOINT ["executable", "param1"] تحديد العملية الرئيسية للحاوية (نموذج exec، مفضل) ENTRYPOINT ["python3", "-u", "app.py"]
ENTRYPOINT command param1 تحديد العملية الرئيسية (نموذج shell، تجنب) ENTRYPOINT python3 -u app.py

نموذج Exec مقابل نموذج Shell:
– نموذج Exec: يشغل التنفيذي مباشرة؛ يتم تسليم الإشارات (SIGTERM) بشكل صحيح؛ بدون تفسير shell.
– نموذج Shell: يلف الأمر في /bin/sh -c؛ معالجات shell الإشارات وليس تطبيقك؛ يمكن أن يسبب عمليات zombie.

مع CMD:

ENTRYPOINT ["python3"]
CMD ["app.py"]
# docker run image arg → python3 app.py arg

ملاحظات:
– يحدد ENTRYPOINT ما لا يمكن تجاوزه بسهولة.
– استخدم دائماً نموذج exec لـ ENTRYPOINT.

CMD

التعليمة الغرض مثال
CMD ["executable", "param1", "param2"] توفير حجج أو أمر افتراضي (نموذج exec، مفضل) CMD ["python3", "app.py"]
CMD command param1 توفير حجج افتراضية (نموذج shell، تجنب) CMD python3 app.py
CMD ["param1", "param2"] توفير حجج افتراضية إلى ENTRYPOINT CMD ["production"]

ملاحظات:
– إذا لم يتم تعيين ENTRYPOINT، فإن CMD هو الأمر.
– إذا تم تعيين ENTRYPOINT، فإن CMD يوفر حجج له.
– استخدم دائماً نموذج exec لـ CMD.

VOLUME

التعليمة الغرض مثال
VOLUME <path> وضع علامة على مجلد كنقطة تثبيت حجم VOLUME /data
VOLUME ["<path1>", "<path2>"] وضع علامة على نقاط تثبيت متعددة VOLUME ["/var/log", "/data"]

ملاحظات:
– VOLUME إعلانية؛ توثق أن مجلداً يجب أن يبقى أو يتم تثبيته.
– لا ينشئ حجماً فعلياً؛ يتم إنشاء الحجم في وقت التشغيل.
– في وقت التشغيل: docker run -v myvolume:/data image أو docker run -v /host/path:/data image

LABEL

التعليمة الغرض مثال
LABEL <key>=<value> إضافة بيانات وصفية إلى صورة LABEL maintainer="team@example.com"
LABEL <key1>=<value1> <key2>=<value2> إضافة عدة تسميات LABEL version="1.0" description="My app"

ملاحظات:
– التسميات قابلة للبحث: docker images --filter "label=version=1.0"
– التسميات الشائعة: maintainer، version، description، org.opencontainers.image.*

STOPSIGNAL

التعليمة الغرض مثال
STOPSIGNAL SIGTERM الإشارة المراد إرسالها عند إيقاف الحاوية (الافتراضي: SIGTERM) STOPSIGNAL SIGTERM
STOPSIGNAL SIGKILL إشارة قتل القوة (نادراً ما تكون مطلوبة) STOPSIGNAL SIGKILL

ملاحظات:
– معظم التطبيقات تتعامل مع SIGTERM (15) للإيقاف الرشيق.
– استخدم SIGKILL (9) فقط إذا لم يتعامل تطبيقك مع SIGTERM.

SHELL

التعليمة الغرض مثال
SHELL ["<executable>", "<param>"] تجاوز shell الافتراضي (الافتراضي: ["/bin/sh", "-c"] على Linux) SHELL ["/bin/bash", "-c"]

حالة الاستخدام:

FROM mcr.microsoft.com/windows/servercore:ltsc2022
SHELL ["powershell", "-Command", "-ErrorActionPreference", "Stop"]
RUN Get-ChildItem

ONBUILD

التعليمة الغرض مثال
ONBUILD <instruction> تشغيل تعليمة في الصور الفرعية (نادراً ما تُستخدم) ONBUILD RUN npm install

ملاحظات:
– عندما تستخدم صورة فرعية FROM <parent>، يتم تنفيذ تعليمات ONBUILD من الأصل.
– مفيدة لصور الأساس التي تنظم عمليات البناء؛ تجنب في Dockerfiles التطبيق.

البناء متعدد المراحل

يقلل البناء متعدد المراحل حجم الصورة النهائية بواسطة استخدام المراحل الوسيطة للبناء ومرحلة نهائية بها فقط تبعيات التشغيل.

النمط: Builder + Runtime

# المرحلة 1: البناء
FROM golang:1.22 AS builder
WORKDIR /src
COPY . .
RUN go build -o app .

# المرحلة 2: التشغيل (الحد الأدنى)
FROM alpine:3.20
COPY --from=builder /src/app /app
ENTRYPOINT ["/app"]

الفوائد الرئيسية:
– تبعيات البناء (المترجمات وأدوات التطوير) ليست في الصورة النهائية.
– الصورة النهائية تحتوي فقط على الملف الثنائي المترجم.
– يمكن تقليل حجم الصورة من 500 ميجابايت إلى 10 ميجابايت أو أقل.

متقدم: المراحل المسماة والبناء الشروطي

FROM golang:1.22 AS builder
ARG BUILD_TARGET=linux
WORKDIR /src
COPY . .
RUN GOOS=linux GOARCH=amd64 go build -o app .

FROM alpine:3.20 AS runtime
COPY --from=builder /src/app /app
USER nobody
ENTRYPOINT ["/app"]

# الاستخدام: docker build --target runtime -t myapp:latest .

تثبيتات ذاكرة التخزين المؤقت (Docker 19.03+)

تحافظ تثبيتات ذاكرة التخزين المؤقت على الملفات بين عمليات البناء، مما يتيح التثبيت الأسرع للحزم وتخزين التبعيات المؤقت.

FROM python:3.12-alpine
WORKDIR /app

# تثبيت ذاكرة مؤقتة لحزم pip
RUN --mount=type=cache,target=/root/.cache/pip \
    pip install -r requirements.txt

# الاستخدام: docker build --build-context . -t myapp:1.0 .

حالات الاستخدام:
– ذاكرة مدير الحزم المؤقتة (pip، npm، cargo، إلخ)
– ذاكرة التخزين المؤقت للقطع الأثرية البناء (Go cache، Rust target، Maven .m2)

أمر البناء:

docker build -t myapp:1.0 --build-context .

.dockerignore

استخدم .dockerignore لاستثناء الملفات من سياق البناء، مما يقلل حجم الطبقة ووقت البناء.

# .dockerignore
.git
.gitignore
.env
.env.local
*.pyc
__pycache__
.pytest_cache
node_modules
dist
build
*.log
README.md
.vscode
.idea
.DS_Store

ملاحظات:
– الأنماط تعمل مثل .gitignore.
– يقلل حجم السياق المرسل إلى Docker daemon.
– يمكن أن يسرع عمليات البناء بشكل كبير على المشاريع الكبيرة.

أفضل الممارسات الأمنية

التشغيل بدون جذر

FROM alpine:3.20
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
COPY --chown=appuser:appgroup . /app
USER appuser
ENTRYPOINT ["./app"]

إسقاط القدرات غير الضرورية

RUN setcap -r /bin/app  # إزالة جميع القدرات من التنفيذي
# أو في وقت التشغيل: docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE image

استخدام نظام ملفات للقراءة فقط

# في وقت التشغيل: docker run --read-only --tmpfs /tmp image

صور أساسية بالحد الأدنى

  • alpine:3.20 (~7 MB) — يُنصح به لمعظم الحالات
  • distroless/python3-nonroot (~50 MB) — محسّن مسبقاً وبدون مدير حزم
  • scratch (~0 MB) — للملفات الثنائية الثابتة فقط

أفضل الممارسات للحجم

تنظيف ذاكرة مدير الحزم المؤقتة

# Alpine
RUN apk add --no-cache python3 py3-pip

# Debian/Ubuntu
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*

# pip
RUN pip install --no-cache-dir django

دمج أوامر RUN

# سيء (3 طبقات)
RUN apt-get update
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*

# جيد (1 طبقة)
RUN apt-get update && \
    apt-get install -y curl && \
    rm -rf /var/lib/apt/lists/*

استخدم COPY بشكل استراتيجي

# انسخ فقط ما تحتاجه بترتيب تغيير التكرار
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY src ./src
# تغيير src لا يلغي طبقة pip

الأنماط التي ستعاد استخدامها

# صورة أساسية مع ARG لالإصدار
FROM python:${PYTHON_VERSION:-3.12}-alpine AS base

# متعدد المراحل مع حجج البناء
FROM node:20-alpine AS builder
ARG NODE_ENV=production
RUN npm ci --only=production

# فحص صحي مع curl
HEALTHCHECK --interval=30s --timeout=5s \
  CMD curl -f http://localhost:3000/health || exit 1

# مستخدم بدون جذر برقم معرّف ثابت للقابلية للتكرار
RUN adduser -D -u 1000 appuser

# نسخ مع الملكية للمستخدم بدون جذر
COPY --chown=appuser:appuser . /app

# استخدم ذاكرة البناء المؤقتة لمديري الحزم
RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt

# نموذج Exec ENTRYPOINT + CMD
ENTRYPOINT ["python3", "-u"]
CMD ["app.py"]

الأسئلة الشائعة

ما الفرق بين COPY و ADD؟

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

هل يجب أن أستخدم ENV أم ARG؟

ARG لمتغيرات وقت البناء (متاح فقط أثناء البناء وليس في الحاوية قيد التشغيل). ENV لمتغيرات التشغيل (متاح في الحاوية قيد التشغيل). استخدم ARG لإعدادات البناء و ENV لإعدادات التطبيق.

ما الفرق بين ENTRYPOINT و CMD؟

يحدد ENTRYPOINT العملية الرئيسية للحاوية ولا يمكن عادةً تجاوزها. يوفر CMD حجج افتراضية إلى ENTRYPOINT، أو هو الأمر إذا لم يتم تعيين ENTRYPOINT. استخدم نموذج exec لكليهما.

كيف أكتب Dockerfile ينتج صورة صغيرة؟

استخدم صورة أساسية مثل alpine:latest أو scratch. استخدم البناء متعدد المراحل لنسخ القطع الأثرية المترجمة فقط. أزل تبعيات البناء. نظّف ذاكرة مدير الحزم المؤقتة (rm -rf /var/lib/apt/lists/*). تجنب تضمين الملفات غير الضرورية (استخدم .dockerignore).

لماذا يجب أن أشغل كمستخدم بدون جذر؟

التشغيل كـ root في حاوية يعني أن الخرق أو الهروب يمكن أن يعطي مهاجماً وصول جذر إلى المضيف. أنشئ مستخدماً مخصصاً واسقط القدرات لتقليل المخاطر. أضف USER <uid> قبل الأمر النهائي.

كيف تم التحقق من هذا الدليل

كُتب يدويًا من الوثائق الرسمية، وأُعيد فحص كل أمر، ثم رُوجع مرة ثانية قبل النشر. آخر مراجعة في .

المصادر الرسمية التي قُرئت لهذا المقال

شاركها.

التعليقات مغلقة.