التثبيت
محرك يعمل، والأوامر التي تهمّ فعلًا.
التثبيت والخطوات الأولى
يستغرق تثبيت Docker خمس دقائق إذا اتبعتَ الإجراء الصحيح، وأمسية كاملة إذا اتبعتَ الإجراء الخاطئ. والفخ الأكثر شيوعًا هو الحزمة docker.io أو docker التي يقترحها مدير الحزم في توزيعتك. فهي موجودة، وتُثبَّت، وتعمل إلى حدٍّ ما، لكنها كثيرًا ما تتأخر عدة إصدارات رئيسية، وقد تفتقر إلى إضافة Compose، فتقضي عشرين دقيقة تبحث عن سبب «عدم وجود» أمر وارد في التوثيق الرسمي لديك.
أما الفخ الثاني فمصدره مكان آخر، ويصيب الجميع تقريبًا مرة واحدة: بعد تثبيت ناجح تمامًا، يأتي ردّ أول أمر بالرسالة permission denied while trying to connect to the Docker daemon socket. هذا ليس فشلًا في التثبيت، بل نتيجة مباشرة للبنية المعمارية التي رأيناها في الدرس السابق: العميل يتحدث إلى daemon ذي صلاحيات مرتفعة عبر socket. ويُحَل ذلك بسطر واحد، بشرط أن تفهم أيَّ سطر هو ولماذا.
يساعدك هذا الدرس على تجاوز هذين العائقين بحسب نظامك، ثم يركّز على ما يهمّ فعلًا: نحو عشرة أوامر تغطي 90% من العمل اليومي. لا قائمة شاملة بالخيارات، فالتوثيق موجود لذلك، بل المجموعة الصغيرة التي ستكتبها كل يوم، مع ما يحدث خلف كل أمر.
في النهاية ستعرف كيف تشغّل حاوية، وتدخل إليها، وتقرأ سجلاتها، وتفهم سبب توقفها، وتسترجع عشرات الغيغابايتات التي راكمها Docker بصمت على قرصك.
تثبيت Docker Engine على Linux
على Linux يعمل Docker بشكل أصلي: بلا آلة افتراضية وسيطة ولا طبقة ترجمة. إنها البيئة الأبسط والأكثر أداءً. والطريقة الموصى بها تمرّ عبر المستودع الرسمي لـ Docker، مما يضمن التحديثات ووجود الإضافات الحديثة.
على Debian وUbuntu:
# 1. Retirer les paquets anciens ou concurrents, s'ils sont presents
for p in docker.io docker-doc docker-compose podman-docker containerd runc; do
sudo apt-get remove -y "$p"
done
# 2. Ajouter la cle GPG officielle de Docker
sudo apt-get update
sudo apt-get install -y ca-certificates curl
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
# 3. Declarer le depot (le nom de code de la distribution est detecte)
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 4. Installer le moteur ET les plugins (buildx, compose)
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
الحزمتان الأخيرتان هما اللتان يُنسى تثبيتهما كثيرًا، وهما اللتان توفّران docker buildx وdocker compose. وبالنسبة إلى Debian، استبدل ubuntu بـ debian في الموضعين داخل عناوين URL. أما على Fedora أو RHEL فيستخدم الإجراء المكافئ dnf والمستودع docker-ce.repo، وهو مشروح في docs.docker.com/engine/install.
يبقى التأكد من أن daemon يبدأ الآن وعند كل إعادة تشغيل للجهاز:
# --now demarre le service, enable l'active au demarrage
sudo systemctl enable --now docker
# Verifier son etat
systemctl status docker --no-pager
توجد بديل لجهاز مؤقت أو آلة اختبار: سكربت التثبيت الرسمي.
curl -fsSL https://get.docker.com -o get-docker.sh
# Toujours lire un script avant de l'executer en root
less get-docker.sh
sudo sh get-docker.sh
هذا السكربت عملي، لكن Docker نفسها تنصح صراحةً بعدم استخدامه في الإنتاج: فهو يخمّن توزيعتك ويتخذ قرارات نيابةً عنك، وهذا ما لا نريده على خادم يجب أن نتمكن من إعادة بنائه بالمواصفات نفسها.
«permission denied»: مجموعة docker
هذا هو الخطأ الذي ينتظر الجميع عند تنفيذ أول أمر:
permission denied while trying to connect to the Docker daemon socket
at unix:///var/run/docker.sock
يستمع daemon على socket من نوع UNIX هو /var/run/docker.sock، مالكه root ومجموعته docker. ولا ينتمي مستخدمك إلى هذه المجموعة إلا إذا أضفتَه إليها.
# Le groupe existe deja apres l'installation ; la commande est idempotente
sudo groupadd -f docker
# Ajouter votre utilisateur (-a = append, indispensable :
# sans lui, usermod REMPLACE la liste des groupes)
sudo usermod -aG docker "$USER"
# L'appartenance a un groupe est lue a l'ouverture de session.
# Ouvrez une nouvelle session, ou forcez-la pour le shell courant :
newgrp docker
# Verifier
id -nG | tr ' ' '\n' | grep docker
docker run --rm hello-world
نسيان -a في usermod -aG خطأ مكلف: فهو يزيل المستخدم من جميع مجموعاته الأخرى، بما فيها sudo.
ينبغي أن تعرف ما يتيحه هذا الإجراء فعليًا. يعمل daemon بصلاحيات root، وتتيح الواجهة البرمجية التي يعرضها، من بين ما تتيحه، ربط أي مجلد من المضيف داخل حاوية. لذلك فإن الانتماء إلى مجموعة docker يعادل عمليًا امتلاك وصول المستخدم الأعلى (superuser) إلى الجهاز. وهذا مقبول على جهاز عملك؛ أما على خادم مشترك فيستحق قرارًا واعيًا. وللحالات التي لا يكون فيها هذا الارتقاء مقبولًا، يوفّر Docker وضع rootless الذي يشغّل daemon تحت حسابك الخاص.
macOS وWindows: المرور عبر آلة افتراضية
تذكير من الدرس الأول: تتطلب صورة Linux نواة Linux، ولا يوفّرها macOS ولا Windows. على هذين النظامين يثبّت Docker Desktop آلة افتراضية صغيرة تعمل بنظام Linux ويديرها نيابةً عنك؛ ويتحدث عميل docker في طرفيتك إلى daemon الذي يعمل داخلها. يعمل كل شيء بشفافية، لكن هناك نتيجتين ستذكّرانك بنفسيهما باستمرار: عمليات الإدخال والإخراج على الملفات المشتركة مع المضيف أبطأ، والذاكرة المخصصة للآلة الافتراضية سقف شامل.
على macOS يتم التثبيت عبر حزمة .dmg من docs.docker.com/desktop/install/mac-install، أو عبر Homebrew:
brew install --cask docker
# Puis lancer l'application Docker une premiere fois : c'est elle
# qui installe le daemon et demarre la VM.
docker version
انتبه إلى المعمارية: على أجهزة Mac ذات Apple Silicon (M1 وما بعده) يكون المعالج arm64. أما الصورة المنشورة لـ amd64 فقط فستُحاكى ببطء، أو سترفض الإقلاع. ويمكن فرض المعمارية عند الحاجة:
# Voir l'architecture du daemon
docker info --format '{{.Architecture}}'
# Forcer une plateforme, au prix de l'emulation
docker run --rm --platform linux/amd64 alpine:3.20 uname -m
على Windows، الإعداد الصحيح هو WSL2 (Windows Subsystem for Linux الإصدار 2) الذي يوفّر نواة Linux حقيقية. أما وضع «Hyper-V» القديم في Docker Desktop فيُفضّل تجنبه، ووضع «حاويات Windows» يلبّي حاجة مختلفة (صور Windows Server).
# Dans PowerShell en administrateur : installe WSL2 et une Ubuntu par defaut
wsl --install
# S'assurer que la version 2 est celle utilisee par defaut
wsl --set-default-version 2
# Verifier : la colonne VERSION doit afficher 2
wsl -l -v
ثبّت بعد ذلك Docker Desktop، ثم فعّل التوزيعة التي تستخدمها من إعداداته في Settings > Resources > WSL Integration. عندها ستتمكن من كتابة أوامر docker مباشرة من صدفة Ubuntu.
نصيحة أداء تغيّر كل شيء على Windows: اعمل داخل نظام ملفات Linux، أي تحت /home/vous/projets، وليس تحت /mnt/c/Users/.... فالملفات المركّبة من قرص Windows تمرّ عبر طبقة ترجمة، وقد يكون npm install هناك أبطأ بعشر مرات.
التحقق من سلامة التثبيت
تكفي ثلاثة أوامر، ويجيب كل منها عن سؤال مختلف.
# 1. Le client et le daemon se parlent-ils, et en quelle version ?
# Si la section "Server" manque, le daemon est injoignable.
docker version
# 2. Etat detaille : pilote de stockage, nombre de conteneurs, memoire
docker info
# 3. Le chemin complet fonctionne-t-il : pull depuis un registre + execution
docker run --rm hello-world
الأمر الثالث هو الاختبار الحقيقي من البداية إلى النهاية: فهو يتحقق من حل DNS، والوصول إلى registry، والكتابة في الذاكرة المخبئية المحلية، وإنشاء حاوية. ويحذف الخيار --rm الحاوية بمجرد خروجها، وهو منعكس ينبغي اكتسابه مع كل حاوية مؤقتة، وإلا تراكمت.
تشريح docker run
docker run هو الأمر الأكثر استخدامًا والأكثر كثافة. وهو في الواقع يجمع ثلاث عمليات: تنزيل الصورة إن لم تكن موجودة، وإنشاء حاوية، وتشغيلها.
docker run [OPTIONS] IMAGE [COMMANDE] [ARGUMENTS...]
الترتيب غير قابل للتفاوض: ما يسبق اسم الصورة يضبط Docker، وما يليه يُمرَّر إلى العملية داخل الحاوية. ووضع -p 8080:80 بعد اسم الصورة لا يسبب خطأ في الصياغة، بل يمرّر -p 8080:80 وسيطًا إلى البرنامج المشغَّل، فيستغرب منه.
الخيارات المهمة وما تفعله حقًا:
docker run \
-d \ # detache : rend le terminal, le conteneur tourne en fond
--name api \ # nom stable, sinon Docker en invente un aleatoire
-p 8080:80 \ # publie le port : 8080 sur l'hote -> 80 dans le conteneur
-e LOG_LEVEL=debug \ # variable d'environnement
-v mes-donnees:/data \ # volume nomme monte sur /data
-w /app \ # repertoire de travail initial
--restart unless-stopped \ # relance apres un crash ou un reboot de l'hote
--memory 512m \ # plafond memoire (cgroups)
nginx:1.27-alpine
يتقابل وضعان ويخدم كلٌّ منهما حاجة مختلفة. الخيار -d يفصل الحاوية عن الطرفية: وهو وضع الخدمات. أما -it فيجمع -i (إبقاء الدخل القياسي مفتوحًا) و-t (تخصيص طرفية وهمية): وهو وضع الجلسات التفاعلية.
# Une session shell jetable dans une Alpine, supprimee a la sortie
docker run --rm -it alpine:3.20 sh
# Un shell Python temporaire, sans installer Python sur l'hote
docker run --rm -it python:3.12-slim python
# Remplacer la commande par defaut de l'image
docker run --rm nginx:1.27-alpine nginx -v
يوضح هذا السطر الأخير فكرة يجب تذكّرها: الأمر المعلن في الصورة ليس سوى قيمة افتراضية، يمكن استبدالها عند التشغيل.
دورة حياة الحاوية
تمرّ الحاوية بعدة حالات، وينشأ كثير من الالتباس من قراءة سريعة جدًا لمخرجات docker ps.
docker create
(image) ─────────────────────> created
│ docker start
v
docker stop / le processus finit
exited <─────────────────────── running <──> paused
│ │ (pause/unpause)
│ docker start │ docker restart
│ v
└──> docker rm ──> (محذوف) running
# Ne montre QUE les conteneurs en cours d'execution
docker ps
# -a montre aussi les conteneurs arretes. C'est la commande a reflexe
# quand "mon conteneur a disparu" : il est la, en statut Exited.
docker ps -a
# Format personnalise, bien plus lisible que la sortie par defaut
docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
النقطة غير البديهية: تعيش الحاوية ما دامت عمليتها الرئيسية (PID 1) حية. فهي لا «تحتوي» آلة مشتعلة في وضع الانتظار. وإذا أنهت عمليتها عملها، انتقلت الحاوية فورًا إلى الحالة Exited.
# Ce conteneur s'arrete instantanement : echo finit son travail.
docker run --name test-court alpine:3.20 echo "bonjour"
docker ps -a --filter name=test-court # Exited (0)
# Celui-la tourne 30 secondes puis sort.
docker run -d --name test-sleep alpine:3.20 sleep 30
وهذا هو تفسير سوء الفهم الكلاسيكي «حاويتي تتوقف من تلقاء نفسها»: فإما أن الصورة لا تشغّل أي خدمة دائمة، أو أن الخدمة تنتقل إلى الخلفية وتعيد التحكم، وهذا ما لا ينبغي فعله أبدًا داخل حاوية.
أوامر التحكم:
docker stop api # SIGTERM, puis SIGKILL apres 10 s de grace
docker stop -t 30 api # allonger le delai de grace a 30 s
docker kill api # SIGKILL immediat, aucune chance de finir proprement
docker start api # redemarre un conteneur existant (etat disque conserve)
docker restart api
docker rm api # supprime le conteneur arrete, et sa couche d'ecriture
docker rm -f api # arrete et supprime d'un coup
الفرق بين stop وkill ليس شكليًا. فـ stop يرسل SIGTERM ويمنح التطبيق وقتًا لإغلاق اتصالاته وتفريغ مخازنه المؤقتة؛ أما kill فيقطع فورًا، مع خطر إتلاف البيانات التي تُكتب حاليًا. ويجب على التطبيق المعبأ في حاوية بشكل صحيح أن يعترض SIGTERM.
الدخول إلى حاوية ومراقبتها
عندما لا تستجيب خدمة، يكون الحدس الأول أن ننظر إلى الداخل. ثلاث أدوات، بهذا الترتيب.
أولًا السجلات، لأنها تكفي في معظم الأحيان. يلتقط Docker الخرج القياسي وخرج الأخطاء للعملية الرئيسية.
docker logs api # tout depuis le demarrage
docker logs -f api # suivre en direct (comme tail -f)
docker logs --tail 50 api # les 50 dernieres lignes
docker logs --since 10m api # les 10 dernieres minutes
docker logs --timestamps api # avec horodatage
نتيجة جوهرية: يجب أن يكتب التطبيق المعبأ في حاوية سجلاته على الخرج القياسي، لا في ملف داخلي. وإلا كان docker logs فارغًا وماتت سجلاته مع الحاوية.
ثم فتح صدفة داخل حاوية قيد التشغيل:
# bash quand l'image en dispose (Debian, Ubuntu)
docker exec -it api bash
# sh sur les images Alpine et les images minimales : bash n'y est pas
docker exec -it api sh
# Executer une commande unique sans session interactive
docker exec api ls -la /etc/nginx
docker exec api env
انتبه جيدًا إلى الفرق: docker exec يضيف عملية داخل حاوية تعمل بالفعل، بينما ينشئ docker run حاوية جديدة. وكل ما تعدّله أثناء هذه الجلسة يعيش في طبقة الكتابة الخاصة بالحاوية: وسيضيع عند حذفها. هذا الوضع للتشخيص، لا للإعداد الدائم أبدًا.
وأخيرًا، الفحص والقياسات:
# Toute la configuration du conteneur, en JSON
docker inspect api
# Cibler une valeur precise avec un modele Go
docker inspect --format '{{.State.Status}}' api
docker inspect --format '{{.State.ExitCode}}' api
docker inspect --format '{{range $p, $c := .NetworkSettings.Ports}}{{$p}} {{end}}' api
# Consommation en direct (CPU, memoire, reseau, E/S)
docker stats
# Processus tournant dans le conteneur
docker top api
# Fichiers modifies par rapport a l'image (A ajoute, C change, D supprime)
docker diff api
# Copier un fichier dans les deux sens
docker cp api:/etc/nginx/nginx.conf ./nginx.conf
docker cp ./nginx.conf api:/etc/nginx/nginx.conf
يستحق رمز الخروج الانتباه: فالرمز 137 يعني في الغالب أن العملية تلقّت إشارة SIGKILL (128 + 9)، وغالبًا لأنها تجاوزت حد الذاكرة المسموح به فقتلتها النواة. إنها معلومة لن تمنحكم إياها أي رسالة خطأ صادرة عن التطبيق.
التنظيف: Docker يملأ القرص بصمت
كل صورة يتم تنزيلها، وكل حاوية متوقفة، وكل طبقة وسيطة من طبقات البناء تبقى على القرص. وعلى جهاز تطوير نشط، قد يصل ذلك سريعًا إلى عشرات الجيجابايتات.
# Le bilan : ce que Docker occupe, et ce qui est recuperable
docker system df
# Detail par objet
docker system df -v
يتم التنظيف بدرجات متزايدة من الحدّة.
# 1. Les conteneurs arretes
docker container prune
# 2. Les images sans nom (les "dangling", <none>), produites par les rebuilds
docker image prune
# 3. Les volumes qu'aucun conteneur n'utilise
# ATTENTION : ce sont vos donnees. Verifiez avant.
docker volume ls
docker volume prune
# 4. Le cache de build, souvent le plus gros poste
docker builder prune
# 5. Tout d'un coup, images non utilisees comprises
docker system prune -a
الأمر docker system prune -a أمر ينبغي معرفته واستخدامه بحذر: فهو يحذف جميع الصور التي لا تستخدمها أي حاوية، بما فيها تلك التي ستعيدون تنزيلها غدًا. أما من دون -a، فيقتصر على الكائنات اليتيمة فعلًا.
وفيما يلي بعض التعليمات المتسلسلة العملية، وينبغي فهمها قبل نسخها:
# Arreter tous les conteneurs en cours (-q ne renvoie que les identifiants)
docker stop $(docker ps -q)
# Supprimer tous les conteneurs, y compris ceux qui tournent
docker rm -f $(docker ps -aq)
# Supprimer les images d'un depot donne
docker images --filter reference='mon-app' -q | xargs -r docker rmi
ملاحظة بخصوص macOS وWindows: فالمساحة التي تشغلها الآلة الافتراضية الخاصة بـ Docker Desktop لا تعود دائمًا إلى النظام المضيف بعد تنفيذ prune. إذ يبقى ملف قرص الآلة الافتراضية بحجمه الأقصى. ويوفّر Docker Desktop إجراءً لاستعادة المساحة في إعداداته.
الخلاصة
- على Linux، ثبّتوا Docker من المستودع الرسمي لـ Docker، وليس من حزمة التوزيعة أبدًا، ولا تنسوا
docker-buildx-pluginوdocker-compose-plugin: ففي غيابهما لا يوجد الأمرdocker compose. - يُعالَج الخطأ
permission deniedعلى/var/run/docker.sockبالأمرsudo usermod -aG docker $USERمتبوعًا ببدء جلسة جديدة. وتذكّروا أن ذلك يعادل منح صلاحية root على الجهاز. - على macOS وWindows، يعتمد Docker على آلة افتراضية تعمل بنظام Linux. وعلى Windows، استخدموا WSL2 وضعوا مشاريعكم في نظام ملفات Linux وليس تحت
/mnt/c، وإلا واجهتم بطئًا كبيرًا. - تعيش الحاوية بقدر ما تعيش العملية ذات المعرّف PID 1 تمامًا. وعبارة «تتوقف من تلقاء نفسها» تعني في الغالب أن هذه العملية قد أنهت تنفيذها. يعرض
docker ps -aالحاويات المتوقفة، بينما لا يعرضهاdocker ps. - يمكن تلخيص الاستخدام اليومي في ثمانية أوامر:
runوps -aوlogs -fوexec -itوstopوrmوinspectوsystem df. وعوّدوا أنفسكم على استخدام--rmمع كل حاوية مؤقتة. - راقبوا
docker system dfبانتظام: فالصور والأقراص (volumes) وذاكرات البناء المؤقتة تملأ القرص من دون سابق إنذار.
نصيحة: شغّلوا
docker run --rm -it alpine:3.20 shواستكشفوا بحرية. فالحاوية المؤقتة هي أأمن بيئة للتجريب: اكتبواexitولن يبقى منها أي أثر.
التعليقات
التعليقات مدعومة عبر GitHub Discussions
سجّل الدخول باستخدام GitHub للمشاركة في النقاش