<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Docker on kenji.blog</title><link>http://kenji.blog/ar/tags/docker/</link><description>Recent content in Docker on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>ar</language><copyright>kenjinote</copyright><lastBuildDate>Sun, 13 Sep 2026 01:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/ar/tags/docker/index.xml" rel="self" type="application/rss+xml"/><item><title>خطوات بناء بيئة تطوير محلية قابلة لإعادة الإنتاج باستخدام Docker</title><link>http://kenji.blog/ar/p/docker-reproducible-local-dev-environment/</link><pubDate>Sun, 13 Sep 2026 01:00:00 +0900</pubDate><guid>http://kenji.blog/ar/p/docker-reproducible-local-dev-environment/</guid><description>&lt;img src="http://kenji.blog/p/docker-reproducible-local-dev-environment/img/eyecatch.jpg" alt="Featured image of post خطوات بناء بيئة تطوير محلية قابلة لإعادة الإنتاج باستخدام Docker" />&lt;h2 id="1-مقدمة-التخلص-من-مشكلة-إنها-تعمل-على-جهازي">1. مقدمة: التخلص من مشكلة &amp;ldquo;إنها تعمل على جهازي&amp;rdquo;
&lt;/h2>&lt;p>في مجال تطوير البرمجيات، لطالما كانت مشكلة &amp;ldquo;إنها تعمل على جهازي (It works on my machine)&amp;rdquo; الناتجة عن اختلاف البيئات بين المطورين سبباً في إهدار الكثير من الوقت في العديد من المشاريع. فالاختلافات في أنظمة التشغيل، وإصدارات اللغات المثبتة، واعتماديات المكتبات، وتعارض الأدوات المثبتة عالمياً، تجعل البيئة المحلية دائماً عرضة لـ &amp;ldquo;عدم يقين الحالة&amp;rdquo;.&lt;/p>
&lt;p>الحل الجذري لهذه التحديات يكمن في تقنية الحاويات مثل &lt;strong>Docker&lt;/strong>، ونموذج &lt;strong>البنية التحتية ككود (IaC)&lt;/strong>. من خلال تحويل بيئة التطوير المحلية إلى حاويات، يمكن تحقيق العزل على مستوى نظام التشغيل، مما يسمح بإدارة إصدارات البيئة نفسها جنباً إلى جنب مع قاعدة الكود.&lt;/p>
&lt;p>في هذا المقال، سنشرح بالتفصيل وبشكل شامل الخطوات اللازمة لبناء &lt;strong>&amp;ldquo;بيئة تطوير محلية قابلة لإعادة الإنتاج بحيث تكون متطابقة تماماً بغض النظر عمن يقوم بتشغيلها، أو متى، أو على أي جهاز&amp;rdquo;&lt;/strong> باستخدام Docker، و Docker Compose، و VSCode DevContainers. كما سنتناول الآليات التقنية العميقة الكامنة وراءها، مع دمج وجهات نظر رياضية.&lt;/p>
&lt;hr>
&lt;h2 id="2-التوافق-بين-البنية-التحتية-ككود-iac-وتقنية-الحاويات">2. التوافق بين البنية التحتية ككود (IaC) وتقنية الحاويات
&lt;/h2>&lt;h3 id="مبادئ-iac-وتطبيقها-على-البيئة-المحلية">مبادئ IaC وتطبيقها على البيئة المحلية
&lt;/h3>&lt;p>البنية التحتية ككود (IaC) هي نهج لإدارة وتجهيز إعدادات البنية التحتية من خلال ملفات تعريف قابلة للقراءة آلياً، بدلاً من العمليات اليدوية. تشمل المبادئ الأساسية لـ IaC العناصر التالية:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>النهج التعريفي (Declarative Approach)&lt;/strong>: تحديد &amp;ldquo;ما يجب أن تكون عليه الحالة النهائية&amp;rdquo; بدلاً من &amp;ldquo;كيفية تغيير الحالة&amp;rdquo;.&lt;/li>
&lt;li>&lt;strong>الاستقواء (Idempotency)&lt;/strong>: ضمان الحصول على نفس النتيجة (الحالة) دائماً بغض النظر عن عدد مرات تشغيل السكربت.&lt;/li>
&lt;li>&lt;strong>التحكم في الإصدارات (Version Control)&lt;/strong>: حفظ حالة البنية التحتية ككود في أنظمة التحكم في الإصدارات (VCS) مثل Git، مما يتيح تتبع سجل التغييرات والمراجعة من قبل النظراء.&lt;/li>
&lt;/ol>
&lt;p>تطبيق IaC في بيئة التطوير المحلية يعني كتابة &amp;ldquo;الحالة المثالية&amp;rdquo; لبيئة التطوير ككود باستخدام ملفات مثل &lt;code>Dockerfile&lt;/code>، و &lt;code>docker-compose.yml&lt;/code>، و &lt;code>devcontainer.json&lt;/code>. وهذا يحقق تجربة تأهيل (Onboarding) سلسة للأعضاء الجدد في الفريق، حيث يمكنهم بدء التطوير فوراً بمجرد استنساخ المستودع وتشغيل أمر واحد.&lt;/p>
&lt;h3 id="ميزات-النواة-kernel-التي-تدعم-تقنية-الحاويات">ميزات النواة (Kernel) التي تدعم تقنية الحاويات
&lt;/h3>&lt;p>تختلف تقنية الحاويات عن المحاكاة الافتراضية القائمة على الهايبرفايزر (مثل الأجهزة الافتراضية VM)، حيث إنها تقنية محاكاة افتراضية خفيفة الوزن تقوم بعزل العمليات (Isolation) مع مشاركة نواة نظام التشغيل المضيف. ولتحقيق ذلك، يتم استخدام الميزات التالية من نواة Linux بشكل أساسي:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>مساحات الأسماء (Namespaces)&lt;/strong>: توفر عرضاً مستقلاً لموارد النظام (مثل PID، والشبكة، ونقاط التركيب (Mount points)، والمستخدمين) لكل عملية.&lt;/li>
&lt;li>&lt;strong>مجموعات التحكم (Cgroups - Control Groups)&lt;/strong>: تقوم بتقييد وتخصيص الموارد المادية (مثل المعالج CPU، والذاكرة، وإدخال/إخراج القرص I/O) التي يمكن للعملية استخدامها.&lt;/li>
&lt;li>&lt;strong>نظام ملفات الاتحاد (UnionFS - Union File System)&lt;/strong>: تقنية تقوم بدمج عدة أشجار أدلة (طبقات) بشكل شفاف لتبدو كنظام ملفات واحد. تعتمد طبقات صور Docker على هذه التقنية.&lt;/li>
&lt;/ul>
&lt;p>دعونا ننظر في النموذج الرياضي لتقييد الموارد. بفرض أن السعة الإجمالية لذاكرة الجهاز المضيف هي $M_{\text{total}}$، وحد الذاكرة لكل حاوية من الحاويات الـ $n$ التي تعمل على المضيف هو $m_i$. فإن الشرط الضروري لعمل النظام باستقرار، مع أخذ الذاكرة الأساسية $M_{\text{os}}$ التي يستهلكها نظام التشغيل المضيف والعمليات الأخرى في الاعتبار، يمكن التعبير عنه بالمتراجحة التالية:&lt;/p>
$$ \sum_{i=1}^{n} m_i \le M_{\text{total}} - M_{\text{os}} $$&lt;p>من خلال الاستخدام الصارم لـ Cgroups لتعريف $m_i$ لكل حاوية، يمكننا منع انهيار الحاويات الأخرى أو النظام المضيف بأكمله بواسطة OOM (Out Of Memory) Killer عندما تتسبب حاوية معينة في تسرب للذاكرة.&lt;/p>
&lt;hr>
&lt;h2 id="3-التصميم-الفعال-لـ-dockerfile-إتقان-البناء-متعدد-الطبقات-multi-stage-build">3. التصميم الفعال لـ Dockerfile: إتقان البناء متعدد الطبقات (Multi-stage Build)
&lt;/h2>&lt;p>الخطوة الأولى نحو بيئة قابلة لإعادة الإنتاج هي تصميم &lt;code>Dockerfile&lt;/code> الذي يحدد بيئة تشغيل التطبيق. هنا، باستخدام Python (FastAPI) كمثال، سنشرح أفضل الممارسات لكتابة Dockerfile آمن وخفيف الوزن بالاستفادة من &lt;strong>البناء متعدد الطبقات (Multi-stage Build)&lt;/strong>.&lt;/p>
&lt;p>البناء متعدد الطبقات هو تقنية تستخدم تعليمات &lt;code>FROM&lt;/code> متعددة داخل &lt;code>Dockerfile&lt;/code> واحد لفصل بيئة البناء (التي تحتوي على بيئة ثقيلة مثل المترجمات وأدوات التطوير) عن بيئة التشغيل (بيئة خفيفة الوزن تحتوي فقط على المخرجات الضرورية).&lt;/p>
&lt;h3 id="مثال-عملي-لـ-dockerfile-لتطبيق-python-fastapi">مثال عملي لـ Dockerfile لتطبيق Python FastAPI
&lt;/h3>&lt;p>الكود أدناه هو مثال متقدم لـ &lt;code>Dockerfile&lt;/code> يجمع بين إدارة الاعتماديات باستخدام Poetry والبناء متعدد الطبقات.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-dockerfile" data-lang="dockerfile">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># ---------------------------------------------------------&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Stage 1: Builder (بيئة البناء)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># ---------------------------------------------------------&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="s"> python:3.11-slim AS builder&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># إعداد متغيرات البيئة الضرورية&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">ENV&lt;/span> &lt;span class="nv">PYTHONUNBUFFERED&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">PYTHONDONTWRITEBYTECODE&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">POETRY_VERSION&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span>.6.1 &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">POETRY_HOME&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/opt/poetry&amp;#34;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">POETRY_VIRTUALENVS_IN_PROJECT&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">true&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">POETRY_NO_INTERACTION&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># تثبيت الحزم المعتمدة&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> apt-get update &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> apt-get install -y --no-install-recommends &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> curl build-essential &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> curl -sSL https://install.python-poetry.org &lt;span class="p">|&lt;/span> python3 - &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> apt-get clean &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> rm -rf /var/lib/apt/lists/*&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">ENV&lt;/span> &lt;span class="nv">PATH&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$POETRY_HOME&lt;/span>&lt;span class="s2">/bin:&lt;/span>&lt;span class="nv">$PATH&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">WORKDIR&lt;/span>&lt;span class="s"> /app&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># نسخ ملفات الاعتماديات وتثبيتها&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> pyproject.toml poetry.lock ./&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> poetry install --no-root --only main&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># ---------------------------------------------------------&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Stage 2: Runtime (بيئة التشغيل)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># ---------------------------------------------------------&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="s"> python:3.11-slim AS runtime&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">ENV&lt;/span> &lt;span class="nv">PYTHONUNBUFFERED&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">PYTHONDONTWRITEBYTECODE&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">PATH&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/app/.venv/bin:&lt;/span>&lt;span class="nv">$PATH&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># إنشاء مستخدم غير متميز بحد أدنى من الصلاحيات&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> groupadd -r appuser &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> useradd -r -g appuser appuser&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">WORKDIR&lt;/span>&lt;span class="s"> /app&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># نسخ البيئة الافتراضية (الاعتماديات) فقط من بيئة البناء&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> --from&lt;span class="o">=&lt;/span>builder --chown&lt;span class="o">=&lt;/span>appuser:appuser /app/.venv /app/.venv&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># نسخ كود التطبيق&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> --chown&lt;span class="o">=&lt;/span>appuser:appuser ./src /app/src&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># التبديل إلى المستخدم غير المتميز&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">USER&lt;/span>&lt;span class="s"> appuser&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># الأمر الافتراضي عند تشغيل الحاوية&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">ENTRYPOINT&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;uvicorn&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;src.main:app&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;--host&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;0.0.0.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;--port&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;8000&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="التقييم-الرياضي-لحجم-الصورة-بسبب-البناء-متعدد-الطبقات">التقييم الرياضي لحجم الصورة بسبب البناء متعدد الطبقات
&lt;/h3>&lt;p>لنفترض أن حجم الصورة عند بنائها في مرحلة واحدة هو $S_{\text{single}}$، وحجم الصورة عند تطبيق البناء متعدد الطبقات هو $S_{\text{multi}}$. يتم حساب معدل تقليل الحجم $R$ على النحو التالي:&lt;/p>
$$ R = \left( 1 - \frac{S_{\text{multi}}}{S_{\text{single}}} \right) \times 100 \ (\%) $$&lt;p>على سبيل المثال، لنفترض أن $S_{\text{single}}$ يحتوي على الصورة الأساسية لنظام التشغيل (حوالي 110 ميجابايت)، وحزم التطوير (مثل gcc حوالي 150 ميجابايت)، وبرنامج Poetry (حوالي 40 ميجابايت)، والمكتبات المعتمدة للمشروع (حوالي 80 ميجابايت)، والكود المصدري (حوالي 5 ميجابايت)، ليصبح المجموع 385 ميجابايت.
في المقابل، في $S_{\text{multi}}$، يتم نسخ المكتبات المعتمدة (80 ميجابايت) والكود المصدري (5 ميجابايت) فقط إلى الصورة الأساسية (110 ميجابايت)، ليصبح المجموع 195 ميجابايت.&lt;/p>
$$ R = \left( 1 - \frac{195}{385} \right) \times 100 \approx 49.35\% $$&lt;p>بهذه الطريقة، من خلال اعتماد البناء متعدد الطبقات، يمكن تقليل حجم الصورة إلى النصف تقريباً. هذا الانخفاض في الحجم يؤدي مباشرة إلى تسريع وقت السحب (Pull) من السجل (Registry)، وتوفير مساحة القرص، وتحسين الأمان من خلال تقليص مساحة الهجوم (Attack Surface).&lt;/p>
&lt;hr>
&lt;h2 id="4-تنسيق-حاويات-متعددة-باستخدام-docker-compose">4. تنسيق حاويات متعددة باستخدام Docker Compose
&lt;/h2>&lt;p>في تطوير تطبيقات الويب الحديثة، من الشائع استخدام بنية الخدمات المصغرة (Microservices Architecture) حيث تتعاون مكونات متعددة مثل خوادم الويب، وقواعد البيانات، وخوادم التخزين المؤقت (Cache). نستخدم &lt;code>docker-compose.yml&lt;/code> لإدارة هذه المكونات بشكل مركزي في البيئة المحلية.&lt;/p>
&lt;p>في هذا المثال، سنقوم ببناء نظام محلي يتكون من 3 طبقات: &amp;ldquo;الويب (FastAPI)&amp;quot;، و &amp;ldquo;قاعدة البيانات (PostgreSQL)&amp;quot;، و &amp;ldquo;التخزين المؤقت (Redis)&amp;rdquo;.&lt;/p>
&lt;h3 id="مخطط-البنية-mermaid">مخطط البنية (Mermaid)
&lt;/h3>&lt;p>يوضح المخطط التالي العلاقة بين الحاويات، والشبكة، ووحدات التخزين (Volumes) على الجهاز المحلي.&lt;/p>
&lt;pre class="mermaid">
graph TD
User[&amp;#34;الجهاز المضيف (المتصفح/curl)&amp;#34;] --&amp;gt;|Localhost:8000| Web[&amp;#34;حاوية FastAPI للويب&amp;#34;]
subgraph &amp;#34;شبكة Docker Bridge (app-network)&amp;#34;
Web --&amp;gt;|Port 5432| DB[&amp;#34;حاوية PostgreSQL&amp;#34;]
Web --&amp;gt;|Port 6379| Redis[&amp;#34;حاوية Redis&amp;#34;]
end
DB --&amp;gt; Volume1[&amp;#34;وحدة تخزين مسماة (postgres_data)&amp;#34;]
Redis --&amp;gt; Volume2[&amp;#34;وحدة تخزين مسماة (redis_data)&amp;#34;]
HostDir[&amp;#34;كود المصدر في المضيف (./src)&amp;#34;] -.-&amp;gt;|Bind Mount| Web
&lt;/pre>
&lt;h3 id="تنفيذ-وشرح-تفصيلي-لـ-docker-composeyml">تنفيذ وشرح تفصيلي لـ docker-compose.yml
&lt;/h3>&lt;p>فيما يلي مثال على &lt;code>docker-compose.yml&lt;/code> متين وقابل للاستخدام في بيئات التطوير العملية.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;3.8&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">services&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">web&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">build&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">context&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">.&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">target&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">runtime&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">container_name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">dev_web&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ports&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;8000:8000&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">./src:/app/src:ro &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># تركيب كود المضيف بصلاحية القراءة فقط (لإعادة التحميل السريع)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">REDIS_URL=redis://redis:6379/0&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">env_file&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">.env&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">depends_on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">db&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">condition&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">service_healthy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">redis&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">condition&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">service_started&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">networks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">app-network&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;uvicorn&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;src.main:app&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;--host&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;0.0.0.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;--port&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;8000&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;--reload&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">db&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">postgres:15-alpine&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">container_name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">dev_db&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ports&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;5432:5432&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">POSTGRES_USER&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">postgres&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">POSTGRES_PASSWORD&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${POSTGRES_PASSWORD}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">POSTGRES_DB&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${POSTGRES_DB}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">postgres_data:/var/lib/postgresql/data&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">networks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">app-network&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">healthcheck&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">test&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;CMD-SHELL&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;pg_isready -U postgres -d ${POSTGRES_DB}&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">interval&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">5s&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">timeout&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">5s&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">retries&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">5&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">redis&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">redis:7-alpine&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">container_name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">dev_redis&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ports&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;6379:6379&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">redis_data:/data&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">networks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">app-network&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;redis-server&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;--appendonly&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;yes&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">postgres_data&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">redis_data&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">networks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">app-network&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">driver&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">bridge&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="وحدات-التخزين-volumes-والاحتفاظ-بالبيانات">وحدات التخزين (Volumes) والاحتفاظ بالبيانات
&lt;/h3>&lt;p>تعتبر الحاويات من حيث المبدأ &amp;ldquo;عديمة الحالة (Stateless)&amp;rdquo; و &amp;ldquo;قصيرة العمر (Ephemeral)&amp;rdquo;. عند تدمير الحاوية، تضيع البيانات الموجودة بداخلها. للحفاظ على بيانات قاعدة البيانات أو التخزين المؤقت، يجب تركيب (Mount) مساحة من نظام ملفات الجهاز المضيف داخل الحاوية.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>تركيب الربط (Bind Mount)&lt;/strong>: يندرج تحت ذلك &lt;code>./src:/app/src:ro&lt;/code> في خدمة &lt;code>web&lt;/code> المذكورة أعلاه. يقوم بتعيين دليل معين على المضيف مباشرة داخل الحاوية. يُستخدم لعكس تعديلات الكود المحلية على الفور في الحاوية (إعادة التحميل السريع). من منظور الأمان، يُعتبر إضافة خيار &lt;code>:ro&lt;/code> (Read-Only) ممارسة مثلى لمنع الحاوية من تعديل كود المصدر الموجود على المضيف.&lt;/li>
&lt;li>&lt;strong>وحدة التخزين المسماة (Named Volume)&lt;/strong>: يندرج تحت ذلك &lt;code>postgres_data&lt;/code> و &lt;code>redis_data&lt;/code>. هي مساحات تديرها Docker داخلياً (مثل &lt;code>/var/lib/docker/volumes/&lt;/code>)، وتتميز بأداء إدخال/إخراج أفضل من تركيب الربط، وتستوعب اختلافات نظام الملفات بين أنظمة التشغيل المختلفة. يجب استخدامها دائماً لحفظ بيانات قواعد البيانات.&lt;/li>
&lt;/ul>
&lt;h3 id="الشبكات-networking-واكتشاف-الخدمات">الشبكات (Networking) واكتشاف الخدمات
&lt;/h3>&lt;p>بشكل افتراضي، يقوم Docker Compose بإنشاء شبكة Bridge خاصة لكل مشروع. هذه هي &lt;code>app-network&lt;/code> المذكورة أعلاه.
يمكن للحاويات التي تنتمي إلى نفس الشبكة تحليل الأسماء (DNS Resolution) لبعضها البعض باستخدام &amp;ldquo;اسم الخدمة (مثل: &lt;code>db&lt;/code>, &lt;code>redis&lt;/code>)&amp;rdquo; كاسم مضيف بدلاً من عنوان IP.
على سبيل المثال، من حاوية الويب، يمكن الوصول إلى قاعدة البيانات باستخدام عنوان URL &lt;code>postgresql://postgres:password@db:5432/mydb&lt;/code>. يتيح ذلك التبديل السلس لوجهة الاتصال بين البيئة المحلية وبيئة الإنتاج باستخدام متغيرات البيئة دون تعديل كود البنية التحتية.&lt;/p>
&lt;h3 id="فحص-الصحة-healthcheck-والتحكم-في-ترتيب-بدء-التشغيل">فحص الصحة (Healthcheck) والتحكم في ترتيب بدء التشغيل
&lt;/h3>&lt;p>يتحكم توجيه &lt;code>depends_on&lt;/code> في ترتيب بدء تشغيل الحاويات، ولكن بمجرد تحديد &lt;code>depends_on&lt;/code> فقط، ستبدأ حاوية الويب بمجرد &amp;ldquo;بدء تشغيل&amp;rdquo; حاوية قاعدة البيانات. في الواقع، قد تستغرق عملية تهيئة قاعدة البيانات (بدء عملية PostgreSQL وتجهيز الجداول) بضع ثوانٍ، مما قد يؤدي إلى حدوث خطأ عند محاولة حاوية الويب الاتصال بها.
لتجنب ذلك، يمكن تعريف &lt;code>healthcheck&lt;/code> واستخدام &lt;code>condition: service_healthy&lt;/code>، مما يسمح بالتأكد من &amp;ldquo;استعداد قاعدة البيانات لاستقبال طلبات الاتصال&amp;rdquo; قبل بدء تشغيل حاوية الويب.&lt;/p>
&lt;hr>
&lt;h2 id="5-إدارة-متغيرات-البيئة-والأمان-env">5. إدارة متغيرات البيئة والأمان (.env)
&lt;/h2>&lt;p>يعتبر تشفير المعلومات الحساسة مثل كلمات مرور قاعدة البيانات ومفاتيح API برمجياً (Hardcoding) داخل &lt;code>docker-compose.yml&lt;/code> ممارسة سيئة يجب تجنبها تماماً. بدلاً من ذلك، نستخدم ملف متغيرات البيئة &lt;code>.env&lt;/code> لحقن هذه القيم.&lt;/p>
&lt;p>قم بإنشاء ملف &lt;code>.env&lt;/code> في جذر المشروع.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-ini" data-lang="ini">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ملف .env (يجب إضافته إلى .gitignore لاستبعاده من إدارة Git)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">POSTGRES_PASSWORD&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">supersecretpassword&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">POSTGRES_DB&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">devdb&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">API_SECRET_KEY&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">dev_secret_key_12345&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>بشكل افتراضي، يقرأ Docker Compose ملف &lt;code>.env&lt;/code> الموجود في دليل التنفيذ، ويستبدل العناصر النائبة بالشكل &lt;code>${VAR_NAME}&lt;/code> في ملف YAML. تتيح هذه الطريقة إدارة إعدادات مختلفة للبيئات المتعددة مثل البيئة المحلية، وبيئة الاختبار (Staging)، وبيئة الإنتاج (Production) بشكل آمن دون تغيير كود البنية التحتية.&lt;/p>
&lt;hr>
&lt;h2 id="6-تجربة-التطوير-القصوى-باستخدام-vscode-devcontainers">6. تجربة التطوير القصوى باستخدام VSCode DevContainers
&lt;/h2>&lt;p>حتى الآن، قمنا ببناء بيئة خلفية (Backend) متينة باستخدام Docker. ولكن يمكننا اتخاذ خطوة أبعد من ذلك. من خلال استخدام ميزة &lt;strong>VSCode DevContainers (Remote - Containers)&lt;/strong>، يصبح من الممكن تشغيل الواجهة الخلفية للمحرر (VSCode) نفسه داخل الحاوية.&lt;/p>
&lt;p>بهذا، لم يعد من الضروري تثبيت Python أو Node.js على الجهاز المحلي، ويمكن تحديد كل شيء بدءاً من أدوات الفحص (Linter مثل flake8/eslint) وأدوات التنسيق (Formatter مثل black/prettier) وصولاً إلى إضافات بيئة التطوير المتكاملة (IDE) داخل قاعدة الكود لمشاركتها مع جميع أعضاء الفريق.&lt;/p>
&lt;h3 id="إعداد-devcontainerjson">إعداد devcontainer.json
&lt;/h3>&lt;p>قم بإنشاء دليل &lt;code>.devcontainer&lt;/code> في جذر المشروع، وضع بداخله ملف التكوين.&lt;/p>
&lt;p>&lt;code>.devcontainer/devcontainer.json&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Python FastAPI Dev Environment&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;dockerComposeFile&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;../docker-compose.yml&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;service&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;web&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;workspaceFolder&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;/app&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;customizations&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;vscode&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;settings&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;python.defaultInterpreterPath&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;/app/.venv/bin/python&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;python.formatting.provider&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;black&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;editor.formatOnSave&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;extensions&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ms-python.python&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ms-python.vscode-pylance&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ms-python.black-formatter&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;tamasfe.even-better-toml&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;forwardPorts&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">8000&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5432&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">6379&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;remoteUser&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;appuser&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;postCreateCommand&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;poetry install&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>بمجرد تضمين هذا الملف في المستودع، عند فتح المشروع في VSCode، ستظهر رسالة &amp;ldquo;Reopen in Container&amp;rdquo;. وبنقرة واحدة، سيتم تشغيل جميع الحاويات اللازمة، وتثبيت الإضافات، لتكون جاهزاً لبدء البرمجة على الفور. إنها تجربة سحرية حقاً.&lt;/p>
&lt;hr>
&lt;h2 id="7-تسلسل-معالجة-الطلبات-ونمذجة-الأداء">7. تسلسل معالجة الطلبات ونمذجة الأداء
&lt;/h2>&lt;p>سنراجع دورة حياة معالجة الطلب لتطبيق الويب في بيئة التطوير المحلية المبنية من خلال مخطط التسلسل (Sequence Diagram)، وسنحلل النموذج الرياضي لأدائها.&lt;/p>
&lt;h3 id="مخطط-التسلسل-تدفق-الطلب">مخطط التسلسل (تدفق الطلب)
&lt;/h3>&lt;pre class="mermaid">
sequenceDiagram
participant Client as &amp;#34;المتصفح / VSCode&amp;#34;
participant Web as &amp;#34;FastAPI (ويب)&amp;#34;
participant Redis as &amp;#34;تخزين Redis المؤقت&amp;#34;
participant DB as &amp;#34;PostgreSQL&amp;#34;
Client-&amp;gt;&amp;gt;Web: &amp;#34;GET /api/users/123&amp;#34;
activate Web
Web-&amp;gt;&amp;gt;Redis: &amp;#34;التحقق من التخزين المؤقت للمستخدم:123&amp;#34;
activate Redis
alt &amp;#34;إصابة التخزين المؤقت Cache Hit (البيانات موجودة)&amp;#34;
Redis--&amp;gt;&amp;gt;Web: &amp;#34;إرجاع بيانات المستخدم المخزنة&amp;#34;
Web--&amp;gt;&amp;gt;Client: &amp;#34;200 OK (استجابة سريعة)&amp;#34;
else &amp;#34;خطأ التخزين المؤقت Cache Miss (البيانات غير موجودة)&amp;#34;
Redis--&amp;gt;&amp;gt;Web: &amp;#34;فارغ Null (غير موجود)&amp;#34;
deactivate Redis
Web-&amp;gt;&amp;gt;DB: &amp;#34;SELECT * FROM users WHERE id = 123&amp;#34;
activate DB
DB--&amp;gt;&amp;gt;Web: &amp;#34;إرجاع صف من قاعدة البيانات&amp;#34;
deactivate DB
Web-&amp;gt;&amp;gt;Redis: &amp;#34;تعيين بيانات user:123 (فترة الصلاحية TTL: 60 ثانية)&amp;#34;
activate Redis
Redis--&amp;gt;&amp;gt;Web: &amp;#34;موافق OK&amp;#34;
deactivate Redis
Web--&amp;gt;&amp;gt;Client: &amp;#34;200 OK (استجابة قياسية)&amp;#34;
end
deactivate Web
&lt;/pre>
&lt;h3 id="النموذج-الرياضي-لتأخير-المعالجة-latency">النموذج الرياضي لتأخير المعالجة (Latency)
&lt;/h3>&lt;p>سنقوم بنمذجة متوسط وقت معالجة الطلب $T_{\text{total}}$ رياضياً في النظام المذكور أعلاه.
نعرّف تأخير (Latency) كل عملية على النحو التالي:&lt;/p>
&lt;ul>
&lt;li>$T_{\text{net}}$: تأخير الشبكة بين العميل وحاوية الويب&lt;/li>
&lt;li>$T_{\text{app}}$: وقت المعالجة الخالص من جانب التطبيق (مثل التسلسل Serialization)&lt;/li>
&lt;li>$T_{\text{cache}}$: الوقت المستغرق في القراءة/الكتابة من وإلى Redis&lt;/li>
&lt;li>$T_{\text{db}}$: الوقت المستغرق لتنفيذ الاستعلام على PostgreSQL&lt;/li>
&lt;li>$p_{\text{miss}}$: معدل فشل التخزين المؤقت (Cache Miss Rate) ($0 \le p_{\text{miss}} \le 1$)&lt;/li>
&lt;/ul>
&lt;p>عندئذٍ، يتم تمثيل متوسط وقت الاستجابة من خلال معادلة القيمة المتوقعة التالية:&lt;/p>
$$ T_{\text{total}} = T_{\text{net}} + T_{\text{app}} + T_{\text{cache}} + p_{\text{miss}} \times (T_{\text{db}} + T_{\text{cache\_write}}) $$&lt;p>في بيئة التطوير المحلية (داخل Docker)، يكون $T_{\text{net}}$ قريباً جداً من 0، ولكن ما يستحق الانتباه هو &lt;strong>أداء الإدخال/الإخراج (I/O) أثناء تركيب الربط (Bind Mount)&lt;/strong>. خاصة عند استخدام Docker Desktop على أنظمة Windows أو macOS، يميل $T_{\text{app}}$ (وقت قراءة الكود وما إلى ذلك) إلى التضخم بسبب العبء الإضافي لمشاركة الملفات بين نظام التشغيل المضيف والجهاز الافتراضي (الحاوية). للتغلب على عنق الزجاجة هذا، يوصى بشدة باستخدام DevContainers المذكورة أعلاه لوضع كود المصدر بالكامل داخل وحدة تخزين مسماة (Named Volume)، أو استخدام بنية يعمل فيها محرك Docker أصلياً على بيئة WSL2 (Windows Subsystem for Linux 2).&lt;/p>
&lt;hr>
&lt;h2 id="8-تحسين-أداء-بناء-docker-استراتيجية-التخزين-المؤقت-للطبقات-layer-cache">8. تحسين أداء بناء Docker: استراتيجية التخزين المؤقت للطبقات (Layer Cache)
&lt;/h2>&lt;p>يتغير وقت البناء بشكل كبير اعتماداً على ما إذا كنت تفهم آلية &amp;ldquo;التخزين المؤقت للطبقات&amp;rdquo; عند كتابة Dockerfile.
تقوم Docker بإنشاء فرق لنظام الملفات (طبقة) لكل تعليمة في Dockerfile (مثل &lt;code>FROM&lt;/code>، و &lt;code>RUN&lt;/code>، و &lt;code>COPY&lt;/code>)، وتحتفظ بها كنسخة مخبأة. عند إعادة البناء، يتم إعادة استخدام النسخ المخبأة للطبقات التي لم تتغير.&lt;/p>
&lt;p>المبدأ الأساسي هو &lt;strong>&amp;ldquo;كتابة التعليمات بالترتيب من الأقل تغييراً إلى الأكثر تغييراً&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;p>دعونا ننمذج تأثير تغيير كود المصدر على وقت البناء. ليكن إجمالي وقت البناء هو $T_{\text{build}}$، ووقت تنفيذ كل خطوة هو $T_{\text{layer}_i}$، ووجود أو عدم وجود إصابة للنسخة المخبأة (Cache Hit) هو قيمة منطقية $c_i \in \{0, 1\}$ (حيث 1 تعني إصابة النسخة المخبأة).&lt;/p>
$$ T_{\text{build}} = T_{\text{init}} + \sum_{i=1}^{n} (1 - c_i) \times T_{\text{layer}_i} $$&lt;p>بمجرد حدوث خطأ في النسخة المخبأة (Cache Miss) ($c_k = 0$) في الطبقة $k$، يتم إبطال التخزين المؤقت ($c_j = 0$) في جميع الطبقات اللاحقة $j > k$.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-dockerfile" data-lang="dockerfile">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># مثال سيء (نسخ كود المصدر أولاً)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> ./src /app/src&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> pyproject.toml poetry.lock ./&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> poetry install&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>في الحالة أعلاه، يؤدي تعديل سطر واحد فقط من الكود إلى فشل النسخة المخبأة لأمر &lt;code>COPY&lt;/code> الأول، مما يتسبب في تنفيذ &lt;code>RUN poetry install&lt;/code> الذي يستغرق وقتاً طويلاً في كل مرة.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-dockerfile" data-lang="dockerfile">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># مثال جيد (حل الاعتماديات أولاً)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> pyproject.toml poetry.lock ./&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> poetry install&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> ./src /app/src&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>بكتابتها بهذه الطريقة، حتى لو قمت بتغيير كود المصدر، يظل التخزين المؤقت لطبقة &lt;code>poetry install&lt;/code> فعالاً ($c_i = 1$)، مما يقلل وقت البناء بشكل كبير من عدة دقائق إلى بضع ثوانٍ.&lt;/p>
&lt;hr>
&lt;h2 id="9-استكشاف-الأخطاء-وإصلاحها-ونصائح-tips">9. استكشاف الأخطاء وإصلاحها ونصائح (Tips)
&lt;/h2>&lt;p>فيما يلي بعض المشاكل الشائعة والحلول عند تشغيل البيئة المحلية.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>خطأ تعارض المنافذ&lt;/strong>
إذا ظهر خطأ مثل &lt;code>Bind for 0.0.0.0:8000 failed: port is already allocated&lt;/code>، فهذا يعني أن عملية أخرى على الجهاز المحلي تستخدم هذا المنفذ. يمكن تجنب ذلك بتغيير رقم المنفذ على الجانب المضيف إلى شيء مثل &lt;code>ports: - &amp;quot;8080:8000&amp;quot;&lt;/code>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>نفاد مساحة القرص&lt;/strong>
مع استخدام Docker لفترات طويلة، تتراكم الصور ووحدات التخزين غير المستخدمة (Dangling Images / Volumes)، مما قد يستهلك عشرات الجيجابايت من مساحة القرص. يُنصح بتنظيف النظام دورياً باستخدام الأمر التالي.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">docker system prune -a --volumes
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>مشكلة صلاحيات الملفات&lt;/strong>
عند استخدام تركيب الربط (Bind Mount) في بيئة Linux، قد يصبح المالك (Owner) للملفات المنشأة داخل الحاوية هو &lt;code>root&lt;/code>، مما يمنع تحريرها من الجانب المضيف. يمكن حل هذه المشكلة عن طريق إنشاء مستخدم غير متميز داخل Dockerfile ومطابقة المعرف الخاص به (UID/GID) (مثل 1000:1000) مع الخاص بنظام التشغيل المضيف.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="10-الخاتمة-كيف-يساهم-التكرار-وقابلية-إعادة-الإنتاج-في-تحسين-سرعة-التطوير">10. الخاتمة: كيف يساهم التكرار وقابلية إعادة الإنتاج في تحسين سرعة التطوير
&lt;/h2>&lt;p>من خلال الجمع بين Docker، و Docker Compose، و VSCode DevContainers، يمكننا تحقيق بيئة تطوير محلية قوية &amp;ldquo;تكون متطابقة تماماً بغض النظر عمن يقوم بإعدادها&amp;rdquo;.&lt;/p>
&lt;p>إن جلب نموذج IaC إلى البيئة المحلية لا يقتصر فقط على تقليل وقت الإعداد الأولي؛ بل يزيل القلق بشأن تغييرات إعدادات البنية التحتية، ويسهل تجربة تقنيات جديدة، ويتيح الانتقال السلس إلى خطوط أنابيب التكامل المستمر والتسليم المستمر (CI/CD)، مما يؤدي إلى تحسين سرعة وجودة دورة التطوير بأكملها بشكل كبير.&lt;/p>
&lt;p>ندعوك لتطبيق أفضل الممارسات التي شرحناها في هذا المقال، مثل تحسين حجم الصورة باستخدام البناء متعدد الطبقات، والتحكم في الاعتماديات من خلال فحوصات الصحة، وكتابة Dockerfile مع مراعاة التخزين المؤقت للطبقات، لتوفير أفضل تجربة تطوير (DX: Developer Experience) في مشاريعك الخاصة.&lt;/p></description></item><item><title>الدليل الشامل لإعداد بيئة التطوير لنظام WSL2 (نظام ويندوز الفرعي لنظام لينكس)</title><link>http://kenji.blog/ar/p/wsl2-ultimate-development-setup-guide/</link><pubDate>Sat, 12 Sep 2026 23:00:00 +0900</pubDate><guid>http://kenji.blog/ar/p/wsl2-ultimate-development-setup-guide/</guid><description>&lt;img src="http://kenji.blog/p/wsl2-ultimate-development-setup-guide/img/eyecatch.jpg" alt="Featured image of post الدليل الشامل لإعداد بيئة التطوير لنظام WSL2 (نظام ويندوز الفرعي لنظام لينكس)" />&lt;p>يوفر &amp;ldquo;WSL2&amp;rdquo; (نظام ويندوز الفرعي لنظام لينكس 2)، والذي يقدم بيئة تطوير أصلية للينكس على ويندوز، أداة لا غنى عنها في تطوير البرمجيات الحديثة. ومع ذلك، هناك فرق شاسع في الأداء وتجربة التطوير بين الاستمرار في استخدامه في حالته الافتراضية، وبين فهم بنيته المعمارية وإجراء الضبط المناسب.&lt;/p>
&lt;p>في هذه المقالة، سنشرح بالتفصيل الشامل (بأكثر من 10,000 حرف) جميع الخطوات اللازمة لبناء &amp;ldquo;بيئة التطوير المطلوبة (المثالية)&amp;rdquo; التي يبحث عنها المهندسون المحترفون. بدءًا من شرح البنية المعمارية التي تشكل أساس WSL2، وصولاً إلى الإعدادات اللازمة لاستخراج أقصى أداء، وبناء بيئة طرفية (Terminal) مريحة، والتكامل السلس مع Docker و VS Code، وإعدادات الشبكة المتقدمة.&lt;/p>
&lt;hr>
&lt;h2 id="1-بنية-wsl2-وتطورها-عن-wsl1">1. بنية WSL2 وتطورها عن WSL1
&lt;/h2>&lt;p>لاستخراج كامل إمكانات WSL2، من المهم أولاً فهم بنيته الداخلية. تختلف المقاربة المستخدمة لتشغيل ثنائيات لينكس على ويندوز بشكل جذري بين الإصدار الأول (WSL1) و WSL2.&lt;/p>
&lt;h3 id="wsl1-طبقة-ترجمة-استدعاءات-النظام-system-calls">WSL1: طبقة ترجمة استدعاءات النظام (System Calls)
&lt;/h3>&lt;p>اعتمد WSL1 على آلية تترجم استدعاءات نظام لينكس إلى واجهة برمجة تطبيقات ويندوز (NT API) في الوقت الفعلي (Real-time). وبما أن هذا لم يستخدم جهازًا افتراضيًا (VM)، كان يتمتع بميزة أن العبء على الموارد كان ضئيلًا جدًا. ومع ذلك، كان من الصعب محاكاة استدعاءات النظام المعقدة بشكل كامل، مثل عمليات الإدخال والإخراج (I/O) لنظام الملفات، مما أدى إلى انخفاض مروع في الأداء، خاصة في العمليات التي تتعامل مع عدد كبير من الملفات الصغيرة، مثل &lt;code>npm install&lt;/code> في Node.js أو عمليات مستودع Git.&lt;/p>
&lt;h3 id="wsl2-جهاز-افتراضي-vm-للمرافق-خفيف-الوزن-ونواة-لينكس-كاملة">WSL2: جهاز افتراضي (VM) للمرافق خفيف الوزن ونواة لينكس كاملة
&lt;/h3>&lt;p>في WSL2، تم تجديد البنية المعمارية، وأصبحت نواة لينكس حقيقية، تم بناؤها بواسطة Microsoft، تعمل مباشرة على &amp;ldquo;جهاز افتراضي للمرافق خفيف الوزن&amp;rdquo; يستخدم مجموعة فرعية من بنية Hyper-V. هذا يضمن توافقًا بنسبة 100% مع استدعاءات النظام، ومن خلال استخدام قرص افتراضي (VHDX) يستخدم نظام ملفات ext4 الأصلي للينكس، تم تحسين أداء إدخال/إخراج الملفات بشكل كبير مقارنة بـ WSL1.&lt;/p>
&lt;p>يوضح مخطط Mermaid التالي الاختلافات الهيكلية بين WSL1 و WSL2.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
subgraph &amp;#34;بيئة نظام تشغيل ويندوز&amp;#34;
A[&amp;#34;نواة Windows NT&amp;#34;]
A --&amp;gt; F[&amp;#34;نظام ملفات NTFS (محرك C:)&amp;#34;]
end
subgraph &amp;#34;بنية WSL2&amp;#34;
B[&amp;#34;مراقب الأجهزة الافتراضية Hyper-V&amp;#34;]
B --&amp;gt; C[&amp;#34;جهاز افتراضي (VM) للمرافق خفيف الوزن&amp;#34;]
C --&amp;gt; D[&amp;#34;نواة لينكس (Microsoft)&amp;#34;]
D --&amp;gt; E[&amp;#34;مساحة مستخدم Ubuntu (glibc, bash, إلخ)&amp;#34;]
D --&amp;gt; G[&amp;#34;قرص افتراضي ext4 (.vhdx)&amp;#34;]
end
A -.-&amp;gt;|&amp;#34;مشاركة ملفات شبكة بروتوكول Plan 9 (9P)&amp;#34;| D
style B fill:#f9f,stroke:#333,stroke-width:2px
style D fill:#bbf,stroke:#333,stroke-width:2px
&lt;/pre>
&lt;p>الدرس المهم المستفاد من هذا الهيكل هو أن &lt;strong>&amp;ldquo;الوصول إلى الملفات الموجودة على جانب لينكس (داخل VHDX) سريع للغاية، ولكن الوصول إلى الملفات الموجودة على جانب ويندوز (&lt;code>/mnt/c/&lt;/code>) بطيء جدًا لأنه يمر عبر بروتوكول 9P&amp;rdquo;&lt;/strong>. يجب وضع الشيفرة المصدرية (Source code) للمشروع دائمًا ضمن الدليل الرئيسي (&lt;code>~&lt;/code>) على جانب WSL.&lt;/p>
&lt;hr>
&lt;h2 id="2-التحليل-الرياضي-للأداء-لماذا-يعتبر-wsl2-سريعا">2. التحليل الرياضي للأداء: لماذا يعتبر WSL2 سريعًا؟
&lt;/h2>&lt;p>دعونا نقيم تحسين أداء WSL2 بشكل كمي باستخدام نموذج رياضي. في تطوير البرمجيات، واحدة من أكثر العمليات استهلاكًا للوقت هي تلك التي تتضمن عمليات إدخال/إخراج (I/O) لعدد كبير من الملفات (مثل: تثبيت المكتبات أو البناء).&lt;/p>
&lt;p>يتم التعبير عن وقت التنفيذ الإجمالي للعملية $T_{total}$ بمجموع وقت الحوسبة بواسطة وحدة المعالجة المركزية $T_{compute}$ ووقت إدخال/إخراج القرص $T_{io}$.&lt;/p>
$$ T_{total} = T_{compute} + T_{io} $$&lt;p>في حالة WSL1، يتم تكبد عبء لتحويل عمليات جانب لينكس إلى عمليات NTFS، لذلك يتم نمذجة وقت الإدخال/الإخراج على النحو التالي. هنا، $n$ هو عدد عمليات الملفات، و $t_{ntfs\_syscall}$ هو وقت تنفيذ استدعاء النظام على جانب ويندوز، و $t_{trans}$ هو عبء طبقة الترجمة.&lt;/p>
$$ T_{wsl1\_io} = \sum_{i=1}^{n} (t_{ntfs\_syscall_i} + t_{trans_i}) $$&lt;p>من ناحية أخرى، في حالة WSL2، تُصدر النواة (Kernel) عمليات الإدخال/الإخراج مباشرة إلى نظام ملفات ext4، لذلك يكون العبء عبارة عن تأخير طفيف جداً بسبب المحاكاة الافتراضية $t_{virt}$ فقط.&lt;/p>
$$ T_{wsl2\_io} = \sum_{i=1}^{n} (t_{ext4_i} + t_{virt_i}) $$&lt;p>في أنظمة الملفات العامة، بما أن $t_{ext4} \ll t_{ntfs\_syscall} + t_{trans}$، فإنه عندما يكون $n$ كبيرًا جدًا (إجراء عشرات الآلاف إلى مئات الآلاف من عمليات الملفات)، يتسع الفارق في وقت الإدخال/الإخراج بين WSL1 و WSL2 بشكل أُسّي.&lt;/p>
&lt;p>بالإضافة إلى ذلك، إذا كانت نسبة عبء حساب وحدة المعالجة المركزية (CPU) في البيئة الافتراضية هي $\rho$، فإن المحاكاة الافتراضية الحديثة المدعومة بالأجهزة (Intel VT-x / AMD-V) ستبقيها عند حوالي $\rho \approx 0.01 \sim 0.03$ (1 إلى 3٪). وبالتالي، حتى في مهام الحساب البحتة، يتم تحقيق أداء بنسبة $97\% \sim 99\%$، وهو ما يمكن مقارنته ببيئة لينكس الأصلية (Native).&lt;/p>
&lt;hr>
&lt;h2 id="3-التثبيت-وبناء-الأساس">3. التثبيت وبناء الأساس
&lt;/h2>&lt;p>على أنظمة التشغيل Windows 10/11، أصبح تثبيت WSL2 بسيطًا للغاية. افتح PowerShell بصلاحيات المسؤول وقم بتنفيذ الأمر التالي.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># سيتم تثبيت WSL2 و Ubuntu بشكل افتراضي&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">wsl&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-install&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># لتحديد توزيعة معينة&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># يمكن التحقق منها باستخدام wsl --list --online&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">wsl&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-install&lt;/span> &lt;span class="n">-d&lt;/span> &lt;span class="n">Ubuntu&lt;/span>&lt;span class="p">-&lt;/span>&lt;span class="mf">24.04&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>بعد التثبيت وإعادة التشغيل، سيُطلب منك إعداد اسم مستخدم UNIX وكلمة مرور عند بدء التشغيل لأول مرة. هذا المستخدم مستقل عن مستخدم ويندوز ويكون صالحًا فقط داخل WSL.&lt;/p>
&lt;p>إذا كنت تستخدم WSL1 بالفعل، فقم بالتحويل إلى WSL2 باستخدام الأوامر التالية.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># تحويل توزيعة موجودة إلى WSL2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">wsl&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-set-version&lt;/span> &lt;span class="n">Ubuntu&lt;/span> &lt;span class="mf">2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># تعيين WSL2 كإصدار افتراضي للتوزيعات التي ستضاف مستقبلاً&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">wsl&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-set-default-version&lt;/span> &lt;span class="mf">2&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="4-أسرار-التحكم-في-الموارد-wslconfig-و-wslconf">4. أسرار التحكم في الموارد: .wslconfig و wsl.conf
&lt;/h2>&lt;p>أحد أكبر فخاخ WSL2 هو &amp;ldquo;الاستهلاك غير المحدود للذاكرة (تضخم عملية Vmmem)&amp;rdquo;. نظرًا لأن WSL2 يستخدم ذاكرة التخزين المؤقت للصفحات (Page cache) الخاصة بنواة لينكس، فإنه سيستهلك ذاكرة المضيف (ويندوز) بلا حدود في كل مرة يتم فيها إجراء إدخال/إخراج (I/O). لمنع ذلك، من الضروري تقييد الموارد باستخدام ملفات الإعدادات.&lt;/p>
&lt;p>تنقسم ملفات إعدادات WSL2 إلى قسمين: &lt;strong>&lt;code>.wslconfig&lt;/code> الذي يؤثر على نظام ويندوز بأكمله&lt;/strong>، و &lt;strong>&lt;code>wsl.conf&lt;/code> الذي يؤثر على التوزيعة الفردية من الداخل&lt;/strong>.&lt;/p>
&lt;h3 id="41-wslconfig-جانب-ويندوز">4.1. .wslconfig (جانب ويندوز)
&lt;/h3>&lt;p>قم بإنشاء ملف في مجلد ملف تعريف مستخدم ويندوز الخاص بك (&lt;code>C:\Users\&amp;lt;اسم المستخدم&amp;gt;\.wslconfig&lt;/code>) للتحكم في تخصيص الموارد للجهاز الافتراضي (VM).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-ini" data-lang="ini">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># C:\Users\&amp;lt;اسم المستخدم&amp;gt;\.wslconfig&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">[wsl2]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># أقصى قدر من الذاكرة المخصصة للجهاز الافتراضي. يوصى بنسبة 50% إلى 75% من إجمالي ذاكرة المضيف&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">memory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">16GB&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># عدد نوى وحدة المعالجة المركزية (CPU) المراد استخدامها (إذا تم حذفها، يتم استخدام جميع النوى)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">processors&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">8&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># حجم ملف التبادل (Swap file)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">swap&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">8GB&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># وجهة حفظ ملف التبادل (إذا كنت ترغب في توفير مساحة على محرك الأقراص C)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># swapfile=D:\\wsl\\swap.vhdx&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># تمكين إعادة توجيه localhost (للوصول إلى WSL من جانب ويندوز باستخدام localhost)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">localhostForwarding&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># تحرير الذاكرة تلقائيًا (نظام التشغيل Windows 11 فقط)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># يحرر ذاكرة التخزين المؤقت للصفحات ديناميكيًا ويمنع تضخم Vmmem&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">autoMemoryReclaim&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">dropcache&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">[experimental]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ميزات الشبكات المتقدمة المتاحة في Windows 11 إصدار 22H2 وما بعده&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># يتيح هذا دعم IPv6 ومشاركة نفس عنوان IP بين WSL وويندوز&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">networkingMode&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">mirrored&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">dnsTunneling&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">firewall&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">autoProxy&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">true&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="42-wslconf-جانب-لينكس">4.2. wsl.conf (جانب لينكس)
&lt;/h3>&lt;p>قم بتحرير &lt;code>/etc/wsl.conf&lt;/code> داخل WSL للتحكم في السلوك الخاص بالتوزيعة.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-ini" data-lang="ini">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># /etc/wsl.conf (تم التحرير داخل WSL)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">[network]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># تعطيل إنشاء ملف /etc/resolv.conf التلقائي عند بدء تشغيل WSL&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># مفيد عندما تريد إعداد DNS خاص بك (مثال: 8.8.8.8)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">generateResolvConf&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># تعيين اسم مضيف (hostname) مخصص&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">hostname&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">WSL-DevNode&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">[automount]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># الإعدادات عند تركيب محركات أقراص ويندوز (Mounting)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">enabled&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">options&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;metadata,uid=1000,gid=1000,umask=022&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># تغيير نقطة تركيب محرك الأقراص C من /mnt/c إلى /c (لتقصير المسار)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">root&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">/&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">[boot]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># تمكين systemd (في WSL إصدار 0.67.6 وما بعده)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># يتيح هذا لـ snap والبرامج الخفية (daemons) المتنوعة (مثل Docker) العمل محليًا&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">systemd&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">[user]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># المستخدم الذي سيتم تسجيل الدخول به افتراضيًا&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">default&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">kenji&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>لتطبيق هذه الإعدادات، تحتاج إلى تشغيل &lt;code>wsl --shutdown&lt;/code> في PowerShell لإيقاف تشغيل جهاز WSL الافتراضي بالكامل قبل إعادة تشغيله.&lt;/p>
&lt;hr>
&lt;h2 id="5-بيئة-الطرفية-المطلوبة-zsh--powerlevel10k">5. بيئة الطرفية المطلوبة: Zsh + Powerlevel10k
&lt;/h2>&lt;p>لن تتحسن إنتاجيتك مع بقاء bash الافتراضي. سنقوم ببناء أقوى موجه أوامر (Prompt) من خلال الجمع بين Zsh، الذي يتميز بوظائف إكمال قوية وإمكانيات رؤية واضحة، مع السمة (Theme) فائقة السرعة &amp;ldquo;Powerlevel10k&amp;rdquo;.&lt;/p>
&lt;h3 id="51-تثبيت-وإعداد-windows-terminal">5.1. تثبيت وإعداد Windows Terminal
&lt;/h3>&lt;p>قم بتثبيت &amp;ldquo;Windows Terminal&amp;rdquo; من متجر Microsoft. افتح إعدادات JSON (&lt;code>settings.json&lt;/code>)، واضبط ملف التعريف (Profile) الافتراضي على WSL (Ubuntu)، وقم بتغيير الخط إلى خط Nerd مخصص للتطوير (مثال: &lt;code>HackGen Console NF&lt;/code> أو &lt;code>MesloLGS NF&lt;/code>).&lt;/p>
&lt;h3 id="52-تثبيت-zsh-و-oh-my-zsh">5.2. تثبيت Zsh و Oh My Zsh
&lt;/h3>&lt;p>قم بتنفيذ الأوامر التالية في محطة طرفية لـ WSL.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># تحديث الحزم وتثبيت Zsh&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo apt update &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> sudo apt upgrade -y
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo apt install -y zsh git curl
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># تنفيذ برنامج نصي (Script) لتثبيت Oh My Zsh&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sh -c &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="k">$(&lt;/span>curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh&lt;span class="k">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="53-تقديم-powerlevel10k-والإضافات-plugins">5.3. تقديم Powerlevel10k والإضافات (Plugins)
&lt;/h3>&lt;p>قم بتثبيت الإضافات لتعزيز Zsh (تسليط الضوء على بناء الجملة والإكمال التلقائي للإدخال) وسمة Powerlevel10k.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Powerlevel10k&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git clone --depth&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span> https://github.com/romkatv/powerlevel10k.git &lt;span class="si">${&lt;/span>&lt;span class="nv">ZSH_CUSTOM&lt;/span>&lt;span class="k">:-&lt;/span>&lt;span class="nv">$HOME&lt;/span>&lt;span class="p">/.oh-my-zsh/custom&lt;/span>&lt;span class="si">}&lt;/span>/themes/powerlevel10k
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># zsh-autosuggestions&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git clone https://github.com/zsh-users/zsh-autosuggestions &lt;span class="si">${&lt;/span>&lt;span class="nv">ZSH_CUSTOM&lt;/span>&lt;span class="k">:-&lt;/span>&lt;span class="p">~/.oh-my-zsh/custom&lt;/span>&lt;span class="si">}&lt;/span>/plugins/zsh-autosuggestions
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># zsh-syntax-highlighting&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git clone https://github.com/zsh-users/zsh-syntax-highlighting.git &lt;span class="si">${&lt;/span>&lt;span class="nv">ZSH_CUSTOM&lt;/span>&lt;span class="k">:-&lt;/span>&lt;span class="p">~/.oh-my-zsh/custom&lt;/span>&lt;span class="si">}&lt;/span>/plugins/zsh-syntax-highlighting
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>قم بتحرير &lt;code>~/.zshrc&lt;/code> وتمكين السمة والإضافات.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># التغييرات في ~/.zshrc&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">ZSH_THEME&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;powerlevel10k/powerlevel10k&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># أضفه إلى مصفوفة الإضافات (plugins)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">plugins&lt;/span>&lt;span class="o">=(&lt;/span>git zsh-autosuggestions zsh-syntax-highlighting&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>عندما تقوم بالحفظ وتشغيل &lt;code>source ~/.zshrc&lt;/code>، سيبدأ معالج إعداد Powerlevel10k (&lt;code>p10k configure&lt;/code>). اتبع التعليمات التي تظهر على الشاشة لتخصيص موجه الأوامر (Prompt) حسب رغبتك (نمط الموجه، وجود الرموز من عدمها، المعلومات التي سيتم عرضها، إلخ). سيتم عرض أسماء فروع Git وحالتها، وإصدار Node.js، ووقت تنفيذ الأوامر، وما إلى ذلك في الوقت الفعلي، مما يؤدي إلى زيادة كفاءة التطوير بشكل كبير.&lt;/p>
&lt;hr>
&lt;h2 id="6-vs-code-remote---تكامل-سلس-مع-wsl">6. VS Code Remote - تكامل سلس مع WSL
&lt;/h2>&lt;p>عند التطوير في WSL2، توفر إضافة &amp;ldquo;Remote - WSL&amp;rdquo; آلية للوصول السلس إلى الملفات داخل WSL من بيئة التطوير المتكاملة (Visual Studio Code) المثبتة على جانب ويندوز.&lt;/p>
&lt;h3 id="شرح-البنية-المعمارية">شرح البنية المعمارية
&lt;/h3>&lt;p>يوضح مخطط التسلسل (Sequence diagram) التالي كيف يتصل VS Code مع WSL2.&lt;/p>
&lt;pre class="mermaid">
sequenceDiagram
autonumber
participant U as &amp;#34;المطور&amp;#34;
participant V as &amp;#34;واجهة مستخدم VS Code (ويندوز)&amp;#34;
participant S as &amp;#34;خادم VS Code (WSL2)&amp;#34;
participant F as &amp;#34;نظام ملفات ext4 (WSL2)&amp;#34;
U-&amp;gt;&amp;gt;V: &amp;#34;كتابة `code .` في محطة WSL&amp;#34;
V-&amp;gt;&amp;gt;S: &amp;#34;إنشاء اتصال RPC عبر Vsock&amp;#34;
Note over V,S: الاتصال باستخدام مآخذ Hyper-V بدلاً من TCP/IP
S-&amp;gt;&amp;gt;F: &amp;#34;قراءة الملفات المصدرية / تشغيل أداة التحقق (Linter)&amp;#34;
F--&amp;gt;&amp;gt;S: &amp;#34;إرجاع البيانات والتحليل&amp;#34;
S--&amp;gt;&amp;gt;V: &amp;#34;بث نتائج خادم اللغة (Language Server) إلى واجهة المستخدم&amp;#34;
V--&amp;gt;&amp;gt;U: &amp;#34;عرض تمييز بناء الجملة (syntax highlighting) والأخطاء&amp;#34;
&lt;/pre>
&lt;p>يعمل VS Code على جانب ويندوز كمجرد &amp;ldquo;عميل خفيف (واجهة مستخدم)&amp;quot;، وتتم معالجة جميع المهام الثقيلة مثل خادم اللغة (Language Server)، والمصحح (Debugger)، وتنفيذ المحطة الطرفية بواسطة &amp;ldquo;خادم VS Code&amp;rdquo; على جانب WSL. يتيح لك ذلك الحفاظ على نظافة البيئة الخاصة بك من خلال استخدام جانب WSL فقط، دون تثبيت Node.js أو Python على جانب ويندوز.&lt;/p>
&lt;h3 id="إعدادات-vs-code-الأساسية">إعدادات VS Code الأساسية
&lt;/h3>&lt;p>من &amp;ldquo;الإضافات&amp;rdquo; (Extensions) في VS Code، قم بتثبيت &lt;strong>&amp;ldquo;WSL&amp;rdquo; (ms-vscode-remote.remote-wsl)&lt;/strong>. بعد ذلك، ببساطة انتقل إلى دليل المشروع في محطة WSL وقم بتنفيذ &lt;code>code .&lt;/code>، وسيتم تشغيل VS Code على جانب ويندوز مع فتح ذلك الدليل.&lt;/p>
&lt;p>&lt;strong>ملاحظة هامة (مشكلة رمز نهاية السطر (Line Ending)):&lt;/strong>
رموز نهاية السطر تختلف بين ويندوز ولينكس (ويندوز يستخدم &lt;code>CRLF&lt;/code>، ولينكس يستخدم &lt;code>LF&lt;/code>). عند التطوير على WSL، تأكد من توحيد إعداد &lt;code>core.autocrlf&lt;/code> في Git وإعداد الملف الافتراضي في VS Code إلى &lt;code>LF&lt;/code>. سيؤدي الفشل في القيام بذلك إلى التسبب في أخطاء غامضة عند تشغيل نصوص الصدفة (Shell scripts) أو حاويات Docker.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># إعداد رمز نهاية السطر (Line Ending) لـ Git في WSL&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global core.autocrlf input
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>أضف الإعدادات التالية إلى &lt;code>settings.json&lt;/code> الخاص بـ VS Code (الإعدادات عن بُعد).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;files.eol&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;\n&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;terminal.integrated.defaultProfile.linux&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;zsh&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="7-تحسين-docker-desktop-وتكامله-مع-wsl2">7. تحسين Docker Desktop وتكامله مع WSL2
&lt;/h2>&lt;p>هناك طريقتان رئيسيتان لاستخدام Docker في بيئة WSL2.&lt;/p>
&lt;ol>
&lt;li>تثبيت &lt;strong>Docker Desktop لنظام ويندوز&lt;/strong> وتمكين ميزة تكامل WSL2.&lt;/li>
&lt;li>تثبيت &lt;strong>محرك Docker الأصلي (Docker Engine)&lt;/strong> مباشرة داخل WSL2 (مثل Ubuntu).&lt;/li>
&lt;/ol>
&lt;h3 id="النهج-1-docker-desktop-موصى-به">النهج 1: Docker Desktop (موصى به)
&lt;/h3>&lt;p>يُوصى بهذا النهج غالبًا لأنه يسهل الإدارة عبر واجهة المستخدم الرسومية (GUI) والوصول الشفاف إلى الحاويات (Containers) بين ويندوز و WSL. تحقق من التالي في إعدادات Docker Desktop (Settings).&lt;/p>
&lt;ul>
&lt;li>في &lt;code>General&lt;/code> -&amp;gt; ضع علامة اختيار على &lt;code>Use the WSL 2 based engine&lt;/code>.&lt;/li>
&lt;li>في &lt;code>Resources&lt;/code> -&amp;gt; &lt;code>WSL Integration&lt;/code> -&amp;gt; ضع علامة اختيار على &lt;code>Enable integration with my default WSL distro&lt;/code>، وقم بتشغيل مفتاح التبديل للتوزيعة التي تستخدمها (Ubuntu).&lt;/li>
&lt;/ul>
&lt;p>يسمح لك ذلك بتنفيذ أوامر &lt;code>docker&lt;/code> مباشرة من محطة WSL2، ويتم الاتصال ببرنامج Docker الخفي (Daemon) من خلال أجهزة افتراضية خفيفة الوزن مخصصة يديرها Docker Desktop (&lt;code>docker-desktop&lt;/code> و &lt;code>docker-desktop-data&lt;/code>).&lt;/p>
&lt;h3 id="النهج-2-التثبيت-المباشر-لمحرك-docker-الأصلي-native-docker-engine">النهج 2: التثبيت المباشر لمحرك Docker الأصلي (Native Docker Engine)
&lt;/h3>&lt;p>إذا كان هناك قيود على شبكة الشركة (مثل تجنب الإصدار المدفوع من Docker Desktop) أو كنت ترغب في تقليل عبء الأداء إلى أدنى حد ممكن، فقم بتمكين &lt;code>systemd&lt;/code> في &lt;code>/etc/wsl.conf&lt;/code> وقم بتثبيت Docker كخادم Ubuntu نقي.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># مقتطف من خطوات التثبيت الرسمية لـ Docker في WSL2 Ubuntu مع تفعيل systemd&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo apt-get update
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo apt-get install ca-certificates curl gnupg
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo install -m &lt;span class="m">0755&lt;/span> -d /etc/apt/keyrings
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">curl -fsSL https://download.docker.com/linux/ubuntu/gpg &lt;span class="p">|&lt;/span> sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo chmod a+r /etc/apt/keyrings/docker.gpg
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># إضافة المستودع (Repository)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="s2">&amp;#34;deb [arch=&amp;#34;&lt;/span>&lt;span class="k">$(&lt;/span>dpkg --print-architecture&lt;span class="k">)&lt;/span>&lt;span class="s2">&amp;#34; signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&lt;/span>&lt;span class="k">$(&lt;/span>. /etc/os-release &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$VERSION_CODENAME&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="k">)&lt;/span>&lt;span class="s2">&amp;#34; stable&amp;#34;&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> sudo tee /etc/apt/sources.list.d/docker.list &amp;gt; /dev/null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo apt-get update
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># إضافة المستخدم الحالي إلى مجموعة docker (للتشغيل بدون sudo)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo usermod -aG docker &lt;span class="nv">$USER&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>بعد إعادة التشغيل، سيعمل &lt;code>systemctl start docker&lt;/code> تمامًا كما هو الحال في بيئة لينكس الأصلية، مما يوفر أداءً عاليًا.&lt;/p>
&lt;hr>
&lt;h2 id="8-تكامل-مفاتيح-ssh-المصادقة-السلسة-بين-ويندوز-و-wsl">8. تكامل مفاتيح SSH: المصادقة السلسة بين ويندوز و WSL
&lt;/h2>&lt;p>تعد إدارة مفاتيح SSH المنفصلة على ويندوز و WSL لاستنساخ Git (Git clone) عبر SSH أو الاتصال بخوادم عن بُعد عبر SSH مهمة شاقة جدًا. لتحقيق التوازن بين الأمان والراحة، سنقوم بإعداد جسر (Bridge) لوكيل SSH (SSH Agent) الذي يعمل على جانب ويندوز (أو مدير كلمات مرور مثل 1Password) إلى جانب WSL.&lt;/p>
&lt;p>هنا، سنشرح الطريقة الأكثر أمانًا وحداثة باستخدام &lt;strong>ميزة وكيل SSH في 1Password&lt;/strong> أو &lt;strong>وكيل مصادقة OpenSSH في ويندوز (OpenSSH Authentication Agent)&lt;/strong>، وإعادة توجيهها إلى مقبس نطاق UNIX (UNIX domain socket) الخاص بـ WSL2 باستخدام &lt;code>npiperelay&lt;/code> أو &lt;code>socat&lt;/code>.&lt;/p>
&lt;h3 id="إعادة-توجيه-المقبس-socket-forwarding-لوكيل-ssh-agent">إعادة توجيه المقبس (Socket Forwarding) لوكيل ssh-agent
&lt;/h3>&lt;p>عادة، يجب تحويل وكيل SSH المقدم كأنبوب مسمى (Named Pipe) في ويندوز إلى ملف مقبس (Socket file) على جانب WSL. من السهل استخدام &lt;code>wsl-ssh-agent&lt;/code> أو الميزات المقدمة من 1Password.&lt;/p>
&lt;p>من شاشة إعدادات 1Password، قم بتمكين &amp;ldquo;Developer&amp;rdquo; (المطور) -&amp;gt; &amp;ldquo;Use SSH agent&amp;rdquo; (استخدام وكيل SSH).
بعد ذلك، أضف الإعدادات التالية إلى &lt;code>~/.zshrc&lt;/code> أو &lt;code>~/.bashrc&lt;/code> على جانب WSL لربط المقبس (Socket bind) تلقائيًا عند تسجيل الدخول.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># إضافة إلى ~/.zshrc (مثال عند استخدام وكيل SSH الخاص بـ 1Password)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">SSH_AUTH_SOCK&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nv">$HOME&lt;/span>/.ssh/agent.sock
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># إذا لم يكن المقبس موجودًا عند بدء تشغيل WSL، أو إذا لم تكن العملية مرتبطة (bind)، فاستخدم socat و npiperelay لإعادة التوجيه (forward)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">ALREADY_RUNNING&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="k">$(&lt;/span>ps -aux &lt;span class="p">|&lt;/span> grep &lt;span class="s2">&amp;#34;[n]piperelay.exe -ei -s //./pipe/openssh-ssh-agent&amp;#34;&lt;/span> &lt;span class="p">|&lt;/span> wc -l&lt;span class="k">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="o">[&lt;/span> &lt;span class="nv">$ALREADY_RUNNING&lt;/span> -eq &lt;span class="m">0&lt;/span> &lt;span class="o">]&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="k">then&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="o">[&lt;/span> -S &lt;span class="nv">$SSH_AUTH_SOCK&lt;/span> &lt;span class="o">]&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="k">then&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> rm &lt;span class="nv">$SSH_AUTH_SOCK&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fi&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># تشغيل socat في الخلفية وتوصيل الأنبوب المسمى (Named Pipe) لجانب ويندوز بمقبس UNIX لجانب WSL&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">(&lt;/span>setsid socat UNIX-LISTEN:&lt;span class="nv">$SSH_AUTH_SOCK&lt;/span>,fork EXEC:&lt;span class="s2">&amp;#34;npiperelay.exe -ei -s //./pipe/openssh-ssh-agent&amp;#34;&lt;/span>,nofork &lt;span class="p">&amp;amp;&lt;/span>&lt;span class="o">)&lt;/span> &amp;gt;/dev/null 2&amp;gt;&lt;span class="p">&amp;amp;&lt;/span>&lt;span class="m">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">fi&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>※يتطلب هذا تثبيت &lt;code>npiperelay.exe&lt;/code> وإضافته إلى المسار (Path) على جانب ويندوز مسبقًا.&lt;/p>
&lt;p>بمجرد اكتمال هذا الإعداد، عند تشغيل &lt;code>ssh-add -l&lt;/code> من محطة WSL، سيتم عرض قائمة بالمفاتيح العامة (Public keys) المسجلة في 1Password أو على جانب ويندوز. يتيح لك هذا اجتياز المصادقة بأمان دون الحاجة إلى نسخ ملفات المفاتيح الخاصة (Private keys) إلى WSL.&lt;/p>
&lt;hr>
&lt;h2 id="9-الصيانة-تحسين-ضغط-ملفات-vhdx-المتضخمة">9. الصيانة: تحسين (ضغط) ملفات VHDX المتضخمة
&lt;/h2>&lt;p>أحد أكبر عيوب WSL2 هو أن &amp;ldquo;حجم ملف القرص الافتراضي على جانب ويندوز (.vhdx) لا يتقلص تلقائيًا حتى لو قمت بحذف صور Docker أو الملفات&amp;rdquo;. إذا واصلت التطوير لفترة طويلة، سيتضخم ملف ext4.vhdx إلى عشرات أو مئات الجيجابايت.&lt;/p>
&lt;p>لتحرير مساحة على القرص، يجب عليك تحسين (Compact) ملف VHDX من جانب ويندوز بانتظام.&lt;/p>
&lt;ol>
&lt;li>أولاً، قم بإيقاف تشغيل WSL بالكامل.
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">wsl&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-shutdown&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;li>افتح PowerShell بصلاحيات المسؤول، وقم بتنفيذ أمر &lt;code>diskpart&lt;/code> أدناه، أو أمر &lt;code>Optimize-VHD&lt;/code> من وحدة Hyper-V (يمكن استخدام الأخير فقط إذا تم تمكين Hyper-V).&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># إذا كانت وحدة Hyper-V متاحة&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Optimize-VHD&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$env:LOCALAPPDATA&lt;/span>&lt;span class="s2">\Packages\CanonicalGroupLimited.Ubuntu_79rhkp1fndgsc\LocalState\ext4.vhdx&amp;#34;&lt;/span> &lt;span class="n">-Mode&lt;/span> &lt;span class="n">Full&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># في حالة استخدام diskpart&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">diskpart&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># أدخل بشكل تفاعلي داخل الموجه التالي&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">DISKPART&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="nb">select &lt;/span>&lt;span class="n">vdisk&lt;/span> &lt;span class="n">file&lt;/span>&lt;span class="p">=&lt;/span>&lt;span class="s2">&amp;#34;C:\Users\&amp;lt;اسم المستخدم&amp;gt;\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu_79rhkp1fndgsc\LocalState\ext4.vhdx&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">DISKPART&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="n">attach&lt;/span> &lt;span class="n">vdisk&lt;/span> &lt;span class="n">readonly&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">DISKPART&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="n">compact&lt;/span> &lt;span class="n">vdisk&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">DISKPART&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="n">detach&lt;/span> &lt;span class="n">vdisk&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">DISKPART&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="n">exit&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>من خلال إجراء هذه العملية بانتظام، يمكنك استعادة المساحة المستهلكة بلا داعٍ على محرك الأقراص C.&lt;/p>
&lt;hr>
&lt;h2 id="10-خاتمة">10. خاتمة
&lt;/h2>&lt;p>لقد تجاوز WSL2 تمامًا إطار كونه مجرد &amp;ldquo;لينكس إضافي يعمل على ويندوز&amp;rdquo;، وتطور ليصبح منصة تطوير قوية لا تقل أهمية عن نظام MacOS أو أجهزة لينكس الأصلية (Native)، بل وربما تتفوق عليها.&lt;/p>
&lt;p>من خلال تطبيق جميع الإعدادات الموضحة في هذا الدليل (تحسين الموارد باستخدام &lt;code>.wslconfig&lt;/code>، وتحسين المحطة الطرفية (Terminal) باستخدام Zsh + Powerlevel10k، والوصول الشفاف باستخدام VS Code Remote، بالإضافة إلى دمج SSH وصيانة VHDX)، ستحصل على &amp;ldquo;بيئة تطوير مطلوبة&amp;rdquo; خالية من التوتر، سريعة، وآمنة.&lt;/p>
&lt;p>على الرغم من أن إعداد البيئة يتطلب بعض الجهد، بمجرد الانتهاء من ضبط الإعدادات، ليس هناك شك في أن إنتاجيتك الهندسية ستتحسن بشكل كبير في المستقبل. لا تتردد في استكشاف المزيد من التخصيصات بناءً على هذا الدليل لتناسب مشاريعك وتفضيلاتك الخاصة.&lt;/p></description></item></channel></rss>