لنفرض أن لديك سيرفراً جديداً وتريد أن تشغل عليه عدة تطبيقات، فسوف تجد أن أحدها يحتاج إصداراً معيناً من PHP وآخر يحتاج قاعدة بيانات Database بإصدار مختلف، وتثبيتها كلها بالطريقة التقليدية على نفس السيرفر Server يعني تعارضات بين المكتبات وتحديثات تخشى من تنفيذها. وهنا يأتي دور Docker الذي تعمل عليه معظم التطبيقات التي تستضيفها بنفسك، حيث يعمل كل تطبيق داخل Container مستقل يحمل معه كل ما يحتاجه، فلا يتعارض مع غيره على السيرفر نفسه، ويصبح تثبيته وتحديثه والتراجع عنه أمراً سهلاً.
ولأن كل ما سوف تضيفه لاحقاً سيعمل فوق Docker، فأي خطأ في تثبيته سوف يتكرر مع كل خدمة Service جديدة تضيفها، وأشهر هذه الأخطاء قرص Disk يمتلئ بالسجلات Logs بعد أسابيع من التشغيل، أو منفذ إداري Admin Port يبقى مفتوحاً للإنترنت دون أن تنتبه له، لذلك من المهم أن يكون التثبيت صحيحاً من البداية حتى لا تكتشف المشكلة بعد أن يصبح السيرفر مليئاً بالخدمات.
وسوف نناقش في هذا المقال ما يلي:
- الفرق بين Docker Engine وDocker Desktop، ولماذا لا نثبت حزمة
docker.ioمن Ubuntu أو سكربت get.docker.com على سيرفر الإنتاج. - تثبيت Docker Engine من المستودع الرسمي لـ Docker Official Repository خطوة بخطوة.
- ثلاثة أمور يغفلها كثيرون بعد التثبيت: تشغيل الأوامر دون
sudoمع فهم ما يعنيه ذلك أمنياً، وتدوير السجلات Log Rotation حتى لا يمتلئ القرص، وطريقة تعامل Docker مع جدار الحماية Firewallufw. - التحقق من التثبيت، والنسخ الاحتياطي، والتحديث، وأشهر المشكلات وحلولها.
وإذا أردت بعد ذلك إدارة ال Containers من المتصفح عبر واجهة ويب Web UI، فراجع دليل تثبيت Portainer بعد أن تنتهي من هذا الدليل.
Docker Engine أم Docker Desktop؟
Docker Engine هو المحرك نفسه، أي خدمة تعمل في الخلفية على السيرفر وتتعامل معها من سطر الأوامر Command Line، وهذا كل ما تحتاجه على أي سيرفر.
أما Docker Desktop فهو تطبيق بواجهة رسومية GUI لأجهزة المطورين على Windows وmacOS وLinux، حيث يشغل Docker Engine داخل جهاز افتراضي VM صغير ويضيف فوقه أدوات تساعد في التطوير، ولكنه ليس مصمماً للسيرفرات، وبالإضافة إلى ذلك فهو يحتاج إلى اشتراك مدفوع Subscription في الجهات الحكومية، وفي الشركات التي يبلغ عدد موظفيها 250 أو أكثر أو إيراداتها السنوية 10 ملايين دولار أو أكثر. لذلك سوف نثبت هنا Docker Engine وحده.
لماذا لا نثبت حزمة docker.io من Ubuntu؟
وقد يتساءل البعض: لماذا كل هذه الخطوات، وحزمة docker.io موجودة أصلاً في مستودعات Ubuntu وتثبيتها يحتاج أمراً واحداً؟ والإجابة أن هذه الحزمة يجهزها فريق Ubuntu وتتبع جدوله في التحديث، أما المستودع الرسمي لـ Docker فيعطيك أحدث إصدار مستقر Stable Release، ومعه الإضافتان Plugins docker compose وbuildx، وتصلك تحديثاته الأمنية Security Updates عبر apt مع باقي النظام، وبالتالي فأنت تعمل على نفس الإصدار الذي يشرحه التوثيق الرسمي وتصلك إصلاحاته مباشرة.
وماذا عن سكربت get.docker.com؟
الحل السريع الثاني هو السكربت السريع Convenience Script الذي توفره Docker، حيث يثبت كل شيء بأمرين: curl -fsSL https://get.docker.com -o get-docker.sh ثم sudo sh get-docker.sh، والنتيجة قريبة من الطريقة اليدوية لأنه يضيف المستودع نفسه ويثبت الحزم نفسها. ولكن Docker نفسها لا تنصح به على سيرفرات الإنتاج Production، والسبب أنه:
- يشغل سكربتاً من الإنترنت بصلاحيات root، فلا تعرف ما ينفذه إلا إذا قرأته قبل تشغيله.
- يثبت أحدث إصدار افتراضياً مع حزم إضافية دون أن يسألك، ولا يتيح لك تخصيص معظم إعدادات التثبيت.
- غير مصمم لتحديث تثبيت موجود، وقد يسبب تشغيله مرة ثانية مشكلات.
لذلك فالسكربت مناسب لسيرفر تجارب Test Server تريد تجهيزه بسرعة، أما السيرفر الذي سوف تشغل عليه خدماتك فاتبع فيه الخطوات التالية، وهي تقريباً نفس الأوامر التي ينفذها السكربت، ولكنك ترى كل خطوة وتتحكم فيها، ثم تحدث Docker لاحقاً عبر apt مع باقي النظام.
ما تحتاجه قبل أن تبدأ Requirements
- سيرفر يعمل بنظام Ubuntu Server 24.04 LTS بمعمارية Architecture
amd64أوarm64، وإذا لم تختر سيرفرك بعد فابدأ بدليل كيف تختار خادماً افتراضياً VPS، ثم تأمين خادم VPS من أول دخول. - مستخدم عادي Non-root User يملك صلاحية
sudo، وتدخل به عبر SSH بمفتاح SSH Key وليس بكلمة مرور. - Docker نفسه خفيف، فخطط الموارد Resources بحسب التطبيقات التي سوف تشغلها، وكبداية معقولة: 2 GB من الذاكرة RAM و20 GB من القرص.
- اتصال بالإنترنت يصل إلى
download.docker.com.
إزالة الحزم المتعارضة Conflicting Packages
إذا كانت حزمة docker.io أو docker-buildx أو podman-docker مثبتة من مستودعات Ubuntu، فسوف تتعارض مع حزم Docker الرسمية، لذلك نبدأ بإزالتها. والأمر التالي يزيل ما هو مثبت منها ويتجاهل الباقي، ولاحظ أنه لا يمس ال Containers وال Images المحفوظة في /var/lib/docker:
for pkg in docker.io docker-doc docker-compose docker-compose-v2 docker-buildx podman-docker containerd runc; do sudo apt-get remove -y $pkg; doneإضافة مستودع Docker الرسمي
الطريقة القديمة كانت تضيف مفتاح التوقيع Signing Key بالأمر apt-key add، والمشكلة فيها أنها تجعل المفتاح موثوقاً لكل المستودعات وليس لمستودع Docker وحده، ولهذا ألغتها إصدارات Ubuntu الحديثة. أما الطريقة الحالية فتحفظ المفتاح في /etc/apt/keyrings وتربطه بمستودع Docker وحده عبر Signed-By. ابدأ بتحديث فهرس الحزم Package Index وتثبيت الأدوات اللازمة:
sudo apt update
sudo apt install -y ca-certificates curlبعد ذلك نزل مفتاح Docker واجعله قابلاً للقراءة من قبل apt:
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.ascالآن سوف نضيف المستودع بصيغة deb822 الحديثة كما يلي:
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOFفي الإعداد أعلاه لاحظ التالي:
- سطر Suites يقرأ اسم الإصدار تلقائياً، وهو
nobleفي Ubuntu 24.04، فلا تحتاج لكتابته بنفسك. - سطر Architectures يقرأ معمارية السيرفر تلقائياً، سواءً كانت
amd64أوarm64. - سطر
Signed-Byهو الذي يربط المفتاح بهذا المستودع وحده.
حدث الفهرس، ثم تأكد من أن الحزمة سوف تأتي من مستودع Docker:
sudo apt update
apt-cache policy docker-ce | head -n 5والمخرج سوف يكون كما يلي، مع العلم أن رقم الإصدار يتغير بمرور الوقت:
docker-ce:
Installed: (none)
Candidate: 5:29.8.2-1~ubuntu.24.04~noble
Version table:
5:29.8.2-1~ubuntu.24.04~noble 500تثبيت Docker Engine وإضافة Compose
سوف نثبت خمس حزم معاً: المحرك Engine، وأداة سطر الأوامر CLI، وcontainerd، وbuildx لبناء ال Images، وإضافة Compose التي توفر الأمر docker compose، ولاحظ أنه بمسافة وليس بشرطة كما في الإصدار القديم.
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginوإذا احتجت إلى إصدار محدد، كأن يطابق سيرفراً آخر لديك، فاعرض الإصدارات المتاحة ثم ثبت أحدها باسمه الكامل:
apt list --all-versions docker-ce
VERSION_STRING=5:29.8.2-1~ubuntu.24.04~noble
sudo apt install -y docker-ce=$VERSION_STRING docker-ce-cli=$VERSION_STRING containerd.io docker-buildx-plugin docker-compose-pluginالخدمة تبدأ تلقائياً بعد التثبيت على Ubuntu، ولكن تأكد من أنها مفعلة عند الإقلاع Boot وأنها تعمل فعلاً:
sudo systemctl enable --now docker containerd
sudo systemctl status docker --no-pagerثم اختبر المحرك وتحقق من أرقام الإصدارات:
sudo docker run --rm hello-world
docker --version
docker compose versionوالمخرج سوف يكون كما يلي:
Hello from Docker!
This message shows that your installation appears to be working correctly.
...
Docker version 29.8.1, build 4a63305
Docker Compose version v5.6.0تشغيل docker دون sudo
كتابة sudo قبل كل أمر تصبح مرهقة بسرعة، خصوصاً عندما تنساها للمرة العاشرة في نفس اليوم وتعيد كتابة الأمر من جديد. ولتشغيل الأوامر بمستخدمك مباشرة أضفه إلى مجموعة Group docker، ثم اخرج من جلسة SSH وادخل من جديد (أو نفذ newgrp docker) حتى تسري العضوية Membership:
sudo usermod -aG docker $USER
newgrp docker
docker info --format '{{.ServerVersion}} {{.Driver}}'docker إلا لمن تمنحه sudo، والسبب أنها تعادل صلاحية root على السيرفر، حيث يستطيع من يملكها تشغيل Container يركب Mount نظام الملفات Filesystem بأكمله. وتذكر أن نفس الأمر ينطبق على أي Container تتيح له الوصول إلى /var/run/docker.sock، ومنها Portainer.docker.إعدادات المحرك Daemon Configuration: تدوير السجلات وlive-restore
يحفظ Docker سجلات ال Containers افتراضياً بصيغة json-file دون أي حد للحجم، وبالتالي قد يملأ Container كثير الرسائل القرص خلال أسابيع، والحل أن تستخدم مشغل السجلات Logging Driver local الذي يضغط السجلات ويدورها تلقائياً. وسوف نضيف معه خيار live-restore الذي يبقي ال Containers عاملة عندما تعيد تشغيل Restart Docker نفسه، أثناء تحديثه مثلاً.
sudo tee /etc/docker/daemon.json <<'EOF'
{
"log-driver": "local",
"log-opts": {
"max-size": "20m",
"max-file": "5"
},
"live-restore": true
}
EOFفي الإعداد أعلاه لاحظ التالي:
- السطر
"log-driver": "local"يستبدلjson-fileبمشغل السجلاتlocal. - القيمتان max-size وmax-file تعنيان أن سجل كل Container يدور على 5 ملفات حجم كل منها 20 MB، فلا يتجاوز مجموعها 100 MB مهما طال التشغيل.
- السطر الأخير يفعل
live-restore.
تحقق من صحة الملف قبل إعادة التشغيل، والسبب أن خطأ واحداً في صياغة Syntax ملف JSON يكفي لمنع الخدمة من العمل:
sudo dockerd --validate --config-file /etc/docker/daemon.json
sudo systemctl restart dockerتذكر: الإعداد الجديد يسري فقط على ال Containers التي تنشئها بعده، أما الموجودة فأعد إنشاءها Recreate بالأمر docker compose up -d --force-recreate.
انتبه: Docker يتجاوز جدار الحماية ufw
ports: "8080:8080" يضيف Docker قواعد iptables خاصة به تسبق قواعد ufw، وبالتالي يصبح المنفذ مفتوحاً للإنترنت حتى لو لم تسمح به في ufw. أما المنافذ الإدارية فانشرها على 127.0.0.1 أو على عنوان في شبكة خاصة Private Network أو VPN، مثل "127.0.0.1:8080:8080"، ويمكنك كذلك أن تجعل ال Reverse Proxy يصل إلى ال Container عبر شبكة Docker دون نشر أي منفذ.كيف تتأكد أن التثبيت نجح؟ Verification
- الخدمة مفعلة وتعمل: الأمر
systemctl is-active dockerيعيد القيمةactive، والأمرsystemctl is-enabled dockerيعيد القيمةenabled. - المستودع صحيح: الأمر
apt-cache policy docker-ceيشير إلىdownload.docker.com. - Compose متاح بالصيغة الجديدة: الأمر
docker compose versionيعيد الإصدار v5.6.0 أو أحدث. - إعداد السجلات مطبق: الأمر
docker info --format '{{.LoggingDriver}}'يعيد القيمةlocal. - المحرك يشغل ال Containers فعلاً:
docker run --rm hello-worldوعند تشغيل الأمر سوف تجد رسالة تبدأ بعبارة Hello from Docker!، ثم يحذف Docker ال Container تلقائياً.
النسخ الاحتياطي Backup والاستعادة Restore
Docker نفسه لا يحمل بيانات مهمة سوى إعداداته، أما بياناتك الفعلية فهي في ال Volumes الخاصة بكل تطبيق، ولكل تطبيق طريقة نسخ يشرحها دليله. وعلى مستوى Docker احفظ ما يلي:
/etc/docker/daemon.json(إعدادات المحرك).- ملفات Compose ومجلدات
/opt/<app>لكل خدمة، والأفضل أن تحفظها في Git.
ولنسخ Volume دون الاعتماد على Image التطبيق شغل Container مؤقتاً يضغط محتواه في ملف، وإذا كان التطبيق يكتب فيه باستمرار كقواعد البيانات فأوقفه أولاً:
docker run --rm -v app_data:/data:ro -v "$PWD":/backup alpine:3.24 \
tar czf /backup/app_data-$(date +%F).tar.gz -C /data .ثم انقل النسخة إلى خارج السيرفر، والسبب أن النسخة المحفوظة على نفس القرص لن تنفعك إذا تعطل القرص نفسه.
التحديث Upgrade إلى إصدار أحدث
يتحدث Docker مع باقي النظام عبر apt، وإذا تغير الإصدار الرئيسي Major Version فاقرأ ملاحظات الإصدار Release Notes أولاً، ثم نفذ:
sudo apt update
apt list --upgradable 2>/dev/null | grep -E 'docker|containerd'
sudo apt install --only-upgrade docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginومع live-restore تبقى ال Containers عاملة أثناء التحديث التصحيحي Patch Release، مثل الانتقال من 29.8.1 إلى 29.8.2، أما عند الانتقال إلى إصدار أحدث من ذلك فإن توثيق live-restore لا يضمن بقاءها، لذلك خطط لتوقف قصير. ولاحظ أن unattended-upgrades لا يحدث حزم Docker في إعداده الافتراضي، والسبب أنه يقتصر على مستودعات Ubuntu، فإذا كان السيرفر يحدث نفسه تلقائياً عبر unattended-upgrades بعد أن أضفت إليه مستودع Docker، وأردت أن تختار أنت موعد تحديث Docker، فجمد حزمه Hold ثم حررها في فترة الصيانة Maintenance Window التي تحددها:
sudo apt-mark hold docker-ce docker-ce-cli containerd.io
sudo apt-mark unhold docker-ce docker-ce-cli containerd.ioمشكلات شائعة وحلولها Troubleshooting
permission denied while trying to connect to the Docker daemon socket
هذا الخطأ يعني أن مستخدمك ليس عضواً في مجموعة docker، أو أنك لم تبدأ جلسة جديدة بعد إضافته، لذلك نفذ groups للتأكد، ثم اخرج وادخل من جديد.
Conflicting values set for option Signed-By
سوف ترى هذا الخطأ عندما يبقى تعريف قديم للمستودع من طريقة تثبيت سابقة (مثل /etc/apt/sources.list.d/docker.list)، والحل أن تحذف التعريف القديم وتبقي docker.sources وحده، ثم تنفذ sudo apt update.
لماذا لا تبدأ الخدمة بعد تعديل daemon.json؟
السبب في الغالب خطأ في صياغة JSON، حيث يحدد الأمر sudo dockerd --validate --config-file /etc/docker/daemon.json موضع الخطأ، ويعرض journalctl -u docker -n 50 سبب الفشل.
امتلاء القرص بمرور الوقت
اعرف حجم ما يستهلكه Docker بالأمر docker system df، ثم احذف ال Images غير المستخدمة بالأمر docker image prune -a بعد أن تتأكد أنك لا تحتاجها. ولكن لا تشغل docker system prune --volumes على سيرفر إنتاجي Production Server دون مراجعة، والسبب أنه يحذف كل Volume غير مرتبط بـ Container قائم، وقد يكون فيه بيانات تحتاجها.
الخلاصة
وصلنا لنهاية الموضوع، وأهم ما فيه:
- ثبت Docker Engine على السيرفر وليس Docker Desktop، ومن المستودع الرسمي وليس من حزمة
docker.ioأو السكربت السريع، حتى ترى كل خطوة وتصلك التحديثات عبرapt. - العضوية في مجموعة
dockerتعادل صلاحية root، فلا تمنحها إلا لمن تمنحهsudo. - فعل مشغل السجلات
localوlive-restoreمن اليوم الأول، حتى لا يمتلئ القرص بالسجلات. - Docker يتجاوز
ufwعند نشر المنافذ، فانشر المنافذ الإدارية على127.0.0.1فقط. - بياناتك في ال Volumes وليست في Docker نفسه، فانسخها وانقل النسخة إلى خارج السيرفر.
سجل التحديثات (Changelog)
- سبتمبر 2026: كتابة الدليل واختباره على Docker Engine 29.8.1 وDocker Compose v5.5.1 على Ubuntu 24.04.
- أكتوبر 2026: مراجعة الدليل وتحديثه إلى Docker Engine 29.8.2، وهو إصدار يصلح ثغرات أمنية، وإلى Docker Compose v5.6.0. وأضفنا حزمة
docker-buildxإلى قائمة الحزم المتعارضة كما في التوثيق الرسمي، ووضحنا حدودlive-restoreعند التحديث.