Podman أم Docker على VPS: ما الفرق فعلياً؟
يعمل Podman بلا daemon وبلا root افتراضياً. تعرّف إلى أثر ذلك على Compose وQuadlet والمنافذ وملكية وحدات التخزين في خادم VPS المستأجر.
ما الذي يختلف فعلياً بين Podman وDocker
يشغّل Podman وDocker صور OCI (open container initiative) نفسها على VPS، لذلك لا يتعلق الاختيار بالبرامج التي يمكنك تشغيلها. يكمن الاختلاف في نموذج العمليات. يشغّل Docker عفريتاً بصلاحيات root يملك كل حاوية، بينما الأمر docker عبارة عن عميل صغير يطلب من ذلك العفريت تنفيذ العمل. لا يستخدم Podman عفريتاً؛ إذ يشغّل podman run الحاوية كعملية فرعية للعملية التي استدعته، باستخدام حساب المستخدم غير المميّز الخاص بك.
تنتج جميع الفروق الأخرى عن هذه الحقيقة. تصبح مهمة التشغيل التلقائي من اختصاص systemd بدلاً من العفريت. تنتقل ملكية وحدات التخزين عبر مساحة أسماء للمستخدم، لذلك لا يكون المالك الذي تراه باستخدام ls -l على المضيف هو المالك الذي تراه الحاوية. ترفض المنافذ الأقل من 1024 الارتباط إلى أن تغيّر إعداداً في النواة. وتستمر واجهة docker لسطر الأوامر (command line interface) في العمل عبر غلاف التفافي، إلى أن يحاول شيء ما الوصول إلى Docker socket.
لا توجد خدمة daemon: ما الذي يعمل فعلياً عند بدء حاوية
على مضيف Docker، يعرض pstree -a العملية dockerd بصفتها root، ويعرض containerd بجانبها، وعملية containerd-shim-runc-v2 واحدة لكل حاوية قيد التشغيل. يكون تطبيقك تابعاً لهذه العملية الوسيطة، وتكون العملية الوسيطة تابعة لـPID 1. لا يربط أي شيء الحاوية بالصدفة التي بدأت تشغيلها. إذا أوقفت daemon، تفقد مستوى التحكم في كل حاوية على المضيف، ومع تعطيل الإعداد الافتراضي live-restore، يعيد systemctl restart docker تشغيل حاوياتك أيضاً.
لا يملك Podman عملية مكافئة. عند بدء حاوية، تحصل على عملية conmon واحدة، وهي عملية مراقبة الحاوية التي تحتفظ بالعملية الرئيسية للحاوية، ويملكها المستخدم الذي نفّذ الأمر.
podman run -d --name web -p 8080:80 docker.io/library/caddy:2
ps -o user,pid,ppid,args -C conmon
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080ينبغي أن يعرض ps العملية conmon قيد التشغيل باسم مستخدم تسجيل الدخول لديك وليس باسم root، وينبغي أن يطبع curl القيمة 200. وبما أنه لا توجد خدمة مركزية تملك الحاوية، فإن sudo apt upgrade podman لا يوقف أي شيء قيد التشغيل، كما أن تعطل عملية مراقبة حاوية واحدة لا يؤدي إلى تعطل الحاويات الأخرى.
لكن غياب daemon يحمّلك تكلفة أيضاً. لا يبدأ أي شيء حاوياتك بعد إعادة التشغيل. يُعد --restart=always وعداً يحتفظ به daemon عند الإقلاع، بينما يستبدله Podman بـsystemd، وهذا هو الغرض من قسم quadlet أدناه.
المقبس هو النصف الآخر من القصة. يمثل /var/run/docker.sock نقطة نهاية لواجهة برمجة تطبيقات مملوكة لـroot، ويمكن لأي عملية لديها صلاحية الكتابة إليها بدء حاوية ذات امتيازات تثبّت نظام ملفات المضيف. تؤدي إضافة مستخدم إلى مجموعة docker إلى منح ذلك المستخدم صلاحيات root بطريقة غير مباشرة، ومن المفيد قراءة ذلك إلى جانب منح كل حساب خدمة الصلاحيات التي يحتاج إليها فقط. لا يعرض Podman أي مقبس ما لم تطلب ذلك، والمقبس الذي تحصل عليه يخص مستخدماً واحداً عند /run/user/<uid>/podman/podman.sock.
تثبيت Podman على Ubuntu 24.04 والتأكد من أن التشغيل دون root فعلي
sudo apt update
sudo apt install -y podman uidmap
podman --version
podman info | grep -i rootlessتوفر حزمة uidmap كلاً من newuidmap وnewgidmap. وهما أداتا setuid تتيحان للمستخدم العادي حجز نطاق من المعرّفات التابعة. ومن دونهما لا تبدأ الحاويات التي تعمل دون root. يجب أن يعرض podman info القيمة rootless: true.
تأتي Ubuntu 24.04 مع Podman 4.9، وتأتي Debian 13 مع Podman 5.x، وفقاً للتحقق الذي أُجري في August 2026. هذا الفرق مهم، لأن ملفات quadlet تحتاج إلى الإصدار 4.4 أو أحدث، بينما تحتاج ملفات quadlet من .pod إلى الإصدار 5.0. شغّل podman --version قبل نسخ مثال من وثائق المشروع الأصلية.
يحتاج كل مستخدم يعمل دون root إلى نطاق من المعرّفات التابعة:
grep "$USER" /etc/subuid /etc/subgidيحصل المستخدم الذي ينشئه adduser في Ubuntu على نطاق تلقائياً. أما المستخدم الذي ينشئه useradd -M أو تنشئه أداة إعداد، فلا يحصل عليه غالباً، ويظهر الفشل كما يلي:
Error: cannot find UID/GID for user deploy: no subuid ranges found for user "deploy" in /etc/subuid - check rootless mode in man pages.عيّن نطاقاً، ثم أعد ضبط مساحة تخزين ذلك المستخدم لكي يُستخدم الربط الجديد:
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 deploy
podman system migrateهناك مفاجأة أخرى عند التشغيل الأول: لا يفترض Podman استخدام Docker Hub. يُحل اسم الصورة المختصر بالرجوع إلى unqualified-search-registries في /etc/containers/registries.conf، وفي script لا يرتبط به terminal يفشل السحب مع short-name resolution enforced but cannot prompt without a TTY. اكتب الاسم الكامل في كل مرة. استخدم docker.io/library/nginx:1.27 بدلاً من nginx.
ما الذي توفره الحاويات دون root فعلياً على خادم مستأجر
تعمل الحاوية دون root داخل مساحة أسماء للمستخدمين، وهي ميزة في النواة تمنح العملية خريطة خاصة بها لمعرّفات المستخدمين. داخل هذه المساحة، يكون المستخدم المميّز في الحاوية هو UID (معرّف المستخدم) 0. أما خارجها، على VPS الخاص بك، فتكون العملية نفسها تابعة لمستخدم تسجيل الدخول العادي لديك. لا يكون root داخل الحاوية هو root على المضيف.
هذا هو الحجم الحقيقي للفائدة. إذا أصرّت image على التشغيل بصلاحيات root، أو احتوى تطبيق ويب على ثغرة تنفيذ تعليمات برمجية عن بُعد، أو اعتمد escape على كون العملية UID 0 خارج الحاوية، فستنتهي هذه الحالات كلها بصلاحيات المستخدم غير المميّز لديك بدلاً من صلاحيات الجهاز. لكن التشغيل دون root لا يحميك من أخطاء النواة، ولا يحمي ملفاتك أنت، لأن العملية التي خرجت من الحاوية تعمل باسمك ويمكنها قراءة كل ما يمكنك قراءته.
يمكن لـDocker أن يعمل دون root أيضاً. dockerd-rootless-setuptool.sh install ينشئ daemon خاصاً بكل مستخدم، ويعمل ذلك جيداً. يكمن الفرق في الاتجاه الافتراضي. مع Podman تحصل على التشغيل دون root تلقائياً، لذلك يكون أول فشل لديك حاوية لا تستطيع ربط المنفذ 80، بدلاً من خدمة ظلت تعمل بصلاحيات root بهدوء لمدة عامين.
لماذا تكون ملفات وحدات التخزين مملوكة للمعرّف UID 100999؟
بسبب مساحة أسماء المستخدمين نفسها. يُطابق UID 0 داخل الحاوية معرّف المستخدم على المضيف. ويُطابق UID 1 داخل الحاوية أول معرّف في نطاق subuid الخاص بك، ثم تزداد المعرّفات بالتتابع. عند بدء النطاق من 100000، يظهر UID 1000 داخل الحاوية على المضيف بالمعرّف 100999.
mkdir -p "$PWD/data"
podman run --rm --user 1000 -v "$PWD/data:/data" docker.io/library/alpine:3 sh -c 'id -u; touch /data/f'
ls -ln "$PWD/data"تعرض الحاوية 1000. وتعرض قائمة الملفات على المضيف المالك 100999، لأن 100000 زائد 1000 ناقص 1 يساوي 100999. لا يوجد عطل هنا، ولن يعالج الأمر chown ذلك، لأن المستخدم غير ذي الصلاحيات لا يستطيع تغيير ملكية الملفات خارج مساحة الأسماء على الإطلاق.
هناك أربع طرق لمعالجة ذلك:
- ينفّذ
podman unshare chown 1000:1000 "$PWD/data"الأمرchownداخل مساحة أسماء المستخدمين نفسها، حيث تحمل الأرقام المعنى المستخدم داخل الحاوية. - يطلب
-v "$PWD/data:/data:U"من Podman تصحيح ملكية الدليل المصدر نيابةً عنك. استخدمه مع دليل جديد، وليس مع بيانات تهمك. - يطابق
--userns=keep-idمعرّف المستخدم UID على المضيف مع المعرّف نفسه داخل الحاوية، لذلك تكون ملكية الملفات الجديدة لك. - تتجنب وحدة تخزين مسماة مثل
-v appdata:/dataهذه المشكلة، لأن Podman ينشئها داخل مساحة التخزين الخاصة بك مع ضبط الملكية بشكل صحيح مسبقاً.
إذا واجهت هذه المشكلة في Docker، فهي المشكلة نفسها ولكن على طبقة إضافية. تضبط متغيرات PUID وPGID التي تتيحها صور كثيرة معرّف المستخدم UID الذي تستخدمه العملية داخل الحاوية، وتتم مطابقة هذا المعرّف مرة ثانية في Podman الذي يعمل دون root. حتى PUID=1000 داخل حاوية تعمل دون root يكتب ملفات على المضيف بملكية 100999. اختر الأرقام مع مراعاة عملية المطابقة الثانية، أو انقل البيانات إلى وحدة تخزين مسماة وتجنب التعامل مع هذه التفاصيل.
هناك ملاحظتان إضافيتان حول عمليات التركيب. الخياران :z و:Z اللذان تراهما في أمثلة Fedora وRHEL هما خيارا إعادة تسمية وفق SELinux، بينما تستخدم Ubuntu نظام AppArmor، لذلك لا يفعلان شيئاً هناك. كما لا يستطيع Podman الذي يعمل دون root تركيب دليل على المضيف لا يستطيع المستخدم قراءته. وهذا سلوك مقصود، وليس عطلاً.
لماذا يرفض Podman بدون root نشر المنفذ 80؟
لأن ربط منفذ أقل من 1024 يحتاج إلى امتياز لا يملكه المستخدم. يوضح الخطأ طريقة الإصلاح:
Error: rootlessport cannot expose privileged port 80, you can add 'net.ipv4.ip_unprivileged_port_start=80' to /etc/sysctl.conf (currently 1024), or choose a larger port number (>= 1024): listen tcp 0.0.0.0:80: bind: permission deniedيوجد حلان. خفّض الحد للنظام بأكمله:
echo 'net.ipv4.ip_unprivileged_port_start=80' | sudo tee /etc/sysctl.d/99-podman.conf
sudo sysctl --system
sysctl net.ipv4.ip_unprivileged_port_startيجب أن يعرض الأمر الأخير 80. انتبه إلى معنى هذا الإعداد: يمكن الآن لكل مستخدم على الجهاز ربط المنفذين 80 و443، وليس المستخدم الذي يشغّل الحاويات فقط. على VPS يديره مسؤول واحد، قد يكون هذا التنازل مقبولاً. أما على جهاز يحتوي على حسابات لأشخاص آخرين، فهو غير مناسب. الحل الآخر هو النشر على المنفذ 8080 ووضع Reverse Proxy أمامه. وهذا هو المكان المناسب لـالشهادات التي يصدرها ويجددها certbot على nginx.
يغيّر النشر بدون root أيضاً ما يراه تطبيقك. يستخدم Podman 4.x القيمة slirp4netns مع معالج المنافذ rootlesskit افتراضياً. تصل الاتصالات المُمرَّرة بعنوان مصدر أعيدت كتابته، لذلك يسجل سجل الوصول كل زائر على أنه 10.0.2.100. غيّر Podman 5.0 القيمة الافتراضية إلى pasta، ما يحافظ على عنوان العميل الحقيقي. في الإصدار 4.x، تعيد --network slirp4netns:port_handler=slirp4netns عنوان المصدر الحقيقي، لكن ذلك يقلل معدل نقل البيانات.
هناك جانب إيجابي مهم هنا. المنفذ المنشور بدون root هو مقبس استماع عادي تملكه عملية مستخدم عادي، لذلك تنطبق عليه قواعد الإدخال في جدارك الناري. ينشر Docker المنافذ عبر كتابة قواعد NAT (ترجمة عناوين الشبكة)، إضافة إلى قواعد قبول التمرير الخاصة به. ولهذا تحديداً يتجاهل منفذ Docker المنشور قاعدة ufw التي ظننت أنها تحجبه. يستخدم Podman مع root آلية مشابهة، ويقع في المشكلة نفسها. أما Podman بدون root فلا يفعل ذلك.
هل ستظل ملفات Docker Compose تعمل مع Podman؟
في الغالب، عبر مسارين مختلفين. الأول هو podman-compose، وهو تطبيق مستقل يقرأ الملف نفسه ويتحكم في واجهة Podman لسطر الأوامر:
sudo apt install -y podman-compose
podman-compose up -d
podman psالثاني هو استخدام Docker Compose الفعلي للتخاطب مع واجهة Podman المتوافقة مع Docker عبر مقبس خاص بكل مستخدم:
systemctl --user enable --now podman.socket
export DOCKER_HOST="unix:///run/user/$(id -u)/podman/podman.sock"
docker compose up -d
podman psيجب أن يعرض docker compose ps وpodman ps الحاويات نفسها، لأن هناك مجموعة واحدة منها فقط. ويعمل حل الأسماء أيضاً: إذ تشغّل واجهة الشبكة الخلفية الافتراضية في Podman، وهي netavark، aardvark-dns، لذلك تتمكن الحاويات الموجودة على شبكة يحددها المستخدم من العثور على بعضها بعضاً بالاسم.
لكن توجد قيود فعلية. أي شيء يركّب /var/run/docker.sock يجب توجيهه إلى مقبس Podman أو حذفه. يعمل network_mode: host بطريقة مختلفة ضمن مساحة أسماء المستخدم. ويختلف دعم depends_on مع condition: service_healthy بين إصدارات podman-compose. ولا يستمر restart: always بعد إعادة التشغيل تلقائياً، ويعالج القسم التالي ذلك. يظل Compose طريقة جيدة لوصف مكدس متعدد الحاويات في ملف واحد، لكنه يعمل مع Podman كطبقة ترجمة. أما إذا كنت تنوي الاحتفاظ بمكدس لسنوات، فحوّله إلى quadlets وأدر تجريداً واحداً بدلاً من اثنين.
Pods: الفكرة التي لا يقدّم Docker حلاً لها
الـpod هو مجموعة من الحاويات التي تشترك في مساحة أسماء شبكة واحدة. يشغّل Podman حاوية infra صغيرة لإبقاء مساحة الأسماء هذه مفتوحة، ثم تتصل الأعضاء ببعضها عبر 127.0.0.1 من دون شبكة يعرّفها المستخدم ومن دون الحاجة إلى اكتشاف الخدمات.
podman pod create --name app -p 8080:80
podman run -d --pod app --name app-cache docker.io/library/redis:7
podman run -d --pod app --name app-web docker.io/library/nginx:1.27
podman pod ps
podman ps --podيجب أن يعرض podman pod ps الـpod Running مع ثلاث حاويات، بما في ذلك حاوية البنية التحتية. تصل حاوية الويب الآن إلى Redis عبر 127.0.0.1:6379 بدلاً من app-cache:6379. وتترتب على مساحة الأسماء المشتركة قاعدتان: انشر المنافذ على الـpod وليس على أي عضو، ولا يجوز لعضوين الاستماع على المنفذ نفسه.
هذا هو نموذج Kubernetes، ويدعمه Podman بقوة. ينشئ podman kube generate app > app.yaml بيان Kubernetes من الحالة قيد التشغيل (وتكتب الحزم الأقدم الأمر بصيغة podman generate kube)، ويعيد podman kube play app.yaml إنشاءها على مضيف آخر. يحتوي Quadlet على نوع وحدة .kube يشغّل هذا الملف كخدمة systemd. هذه طريقة مختلفة فعلاً لتجميع الخدمات، وهي أقوى أسباب اختيار Podman إذا كان Kubernetes ضمن خططك المستقبلية.
بدء التشغيل تلقائياً دون daemon: وحدات quadlet
Quadlet هو مولِّد لـsystemd. يحوّل ملفاً قصيراً يصف حاوية إلى خدمة systemd فعلية عند الإقلاع. توضع الملفات في ~/.config/containers/systemd/ للمستخدم الذي يعمل دون root، أو في /etc/containers/systemd/ للحساب root.
~/.config/containers/systemd/caddy.container:
[Unit]
Description=Caddy web server
After=network-online.target
[Container]
Image=docker.io/library/caddy:2
ContainerName=caddy
PublishPort=8080:80
Volume=caddy-data.volume:/data
Environment=TZ=UTC
AutoUpdate=registry
[Service]
Restart=always
MemoryMax=512M
[Install]
WantedBy=default.targetيمكن أن يكون ~/.config/containers/systemd/caddy-data.volume شبه فارغ، لأن عنوان القسم هو الذي ينشئ وحدة التخزين:
[Volume]systemctl --user daemon-reload
systemctl --user start caddy
systemctl --user status caddy
journalctl --user -u caddy -n 50يأتي اسم الخدمة من اسم الملف: يتحول caddy.container إلى caddy.service. لا تشغّل systemctl --user enable caddy. لا يمكن تفعيل الوحدات المُولَّدة، ويجيب systemd بـFailed to enable unit: Unit /run/user/1000/systemd/generator/caddy.service is transient or generated.. قسم [Install] هو الذي يبدأ الحاوية عند الإقلاع، وdaemon-reload هو الذي يعيد توليد الوحدة بعد تعديل الملف.
والآن الإعداد الذي يربك الجميع تقريباً:
sudo loginctl enable-linger deploy
loginctl show-user deploy --property=Lingerتوقّع Linger=yes. من دون linger، ينهي systemd جلسة المستخدم بالكامل عند إغلاق آخر اتصال SSH، لذلك تتوقف كل حاوية تعمل دون root معه، ولا تعود أي منها عند الإقلاع. الحاويات التي تختفي عند تسجيل الخروج تكون المشكلة فيها دائماً هنا.
بما أنّ الحاوية هي العملية الرئيسية لوحدة خدمة عادية، تنطبق عناصر تحكم systemd عليها مباشرة. يعمل MemoryMax= وCPUQuota= في قسم [Service] بالطريقة نفسها تماماً كما يعملان مع أي خدمة أخرى تضع لها حدوداً باستخدام systemd. يتطلب ذلك cgroup v2 (الإصدار 2 من مجموعة التحكم)، وقد استخدمه Ubuntu افتراضياً منذ 22.04. تحقّق باستخدام podman info | grep -i cgroup.
توجد آلية مماثلة للتحديثات. يفحص AutoUpdate=registry مع systemctl --user enable --now podman-auto-update.timer السجل بحثاً عن صورة أحدث تحمل الوسم نفسه، ثم يعيد تشغيل الوحدة، ويعود إلى الصورة السابقة إذا فشلت الحاوية الجديدة في البدء. شغّل podman auto-update --dry-run أولاً لمعرفة التغييرات التي سيجريها. لا يزال الأمر الأقدم podman generate systemd موجوداً، لكنه مهجور، لذلك اكتب quadlets لكل ما هو جديد.
أين يعمل الاسم المستعار docker، وأين لا يعمل
sudo apt install -y podman-docker
sudo touch /etc/containers/nodocker
docker psيثبّت podman-docker غلاف /usr/bin/docker يستدعي Podman. من دون ملف nodocker، تطبع كل استدعاءات الأداة أولاً Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.. يغطي الغلاف الأوامر التي تكتبها طوال اليوم: run، ps، logs، exec، build، pull، push، inspect، cp، volume، network.
لكن ما لا ينتقل إلى Podman هو قائمة أقصر وأكثر تحديداً. لا يوجد بديل لوضع Swarm، لذلك لا يمكن تشغيل مكدس Swarm عليه. تحتاج الأدوات التي تتصل بـDocker socket إلى تصدير Podman socket، وبعضها يلاحظ الفرق رغم ذلك؛ يعمل موفّر Docker في Traefik عند توجيهه إلى /run/user/<uid>/podman/podman.sock، بينما لا مكان لـWatchtower إطلاقاً، لأن podman auto-update يتولى هذه المهمة. التخزين منفصل، لذلك لا يستطيع Podman رؤية الصور التي سبق أن نزّلتها باستخدام Docker، ويبدأ podman images فارغاً على مضيف Docker مشغول.
ترحيل حزمة قيد التشغيل، خطوةً بخطوة
- أنشئ المستخدم غير ذي الامتيازات الذي سيملك الحاويات أو اختره، وتأكد من أن له نطاقاً في
/etc/subuid. - أعد سحب كل ما جاء من سجل، باستخدام أسماء مؤهلة بالكامل. لدى Podman مخزن صور خاص به، ولن يقرأ مخزن Docker.
- انقل الصور المبنية محلياً باستخدام
docker save app:1.4 | podman load. - أوقف حاوية Docker، وانسخ محتويات كل volume من
/var/lib/docker/volumes/<name>/_data، ثم أصلح الملكية باستخدامpodman unshare chown -R 1000:1000 <path>. - احسم مسألة المنفذ: انشر منفذاً أعلى من 1024 خلف Reverse Proxy، أو اضبط
net.ipv4.ip_unprivileged_port_start. - اكتب ملف quadlet واحداً لكل حاوية، وشغّل
systemctl --user daemon-reload، ثم ابدأ كل خدمة. - شغّل
sudo loginctl enable-linger <user>، وأعد تشغيل VPS، وسجّل الدخول مجدداً، وتحقق من أنpodman psيسرد كل خدمة مرة أخرى.
لا يشترك المحركان في أي موارد: فلكل منهما تخزين صور وشبكات منفصلة. لذلك يمكنك تشغيلهما معاً أثناء الترحيل، والشيء الوحيد الذي يمكن أن يتنافسا عليه هو رقم منفذ على المضيف. انقل خدمة واحدة، وراقبها لمدة يوم، ثم انقل الخدمة التالية.
Podman أم Docker: أيهما مناسب لخادم VPS لديك؟
ابقَ على Docker إذا كانت مكدستك تعتمد على ملفات compose التي يديرها أشخاص آخرون أيضاً، أو إذا كنت تعتمد على أدوات تتصل بـDocker socket. التوافق مع ما يكتبه الآخرون ميزة فعلية، ويمتلك Docker قدراً أكبر منه. كما يستفيد الفريق الذي تعمل جميع أجهزته المحمولة بـDocker من تشغيل المحرك نفسه في بيئة الإنتاج.
انتقل إلى Podman إذا كان خادم VPS يشغّل عدداً قليلاً من الخدمات التي تتحكم بها من البداية إلى النهاية، أو إذا كنت تريد تشغيل كل تطبيق ضمن مستخدم غير مميّز خاص به، من دون وجود مجموعة docker على الخادم إطلاقاً. كما أن توافق التوزيعة عامل مهم: تُصدر RHEL وإعادة بنائها Podman بوصفه المحرك المدعوم، لذلك يكون Podman في هذه الأنظمة المسار الأقل عرضة للمفاجآت. وإذا كنت تدير كل ما عدا ذلك باستخدام وحدات systemd، فستبدو quadlets كأنها جزء مفقود وصل أخيراً، لا كأداة جديدة يجب تعلّمها.
تجدر الإشارة إلى خيار متوسط. يعمل Podman بصلاحيات root بطريقة تشبه Docker إلى حد كبير، ويحافظ على الأمر docker عبر الغلاف، ويزيل مع ذلك البرنامج الخفي الذي يعمل دائماً. لكنه يتخلى أيضاً عن جانب التشغيل من دون root، وهو الجانب الذي يغيّر وضعك الأمني، لذلك تعامل معه كمحطة مؤقتة في الطريق.
إذا كنت لا تزال تنشئ أول خادم حاويات لك، فإن مسار إعداد Docker وتأمينه على خادم VPS جديد أقصر، ولن تذهب أي من تلك المعرفة سدى. الصور وvolumes هي الكائنات نفسها في كلا المحركين، لذلك يغيّر الانتقال طريقة إدارة خدماتك فقط، ولا يغيّر شيئاً يُذكر في الجوانب الأخرى.
FAQ
هل يُعد Podman بديلاً مباشراً لـ Docker؟
بالنسبة إلى الأوامر التي تكتبها، نعم إلى حد كبير. يؤدي تثبيت podman-docker إلى توفير غلاف /usr/bin/docker، وتعمل run وps وbuild وlogs وexec بالطريقة نفسها. لكنه ليس بديلاً عن الـdaemon. لا يملك Swarm نظيراً له، ويجب توجيه الأدوات التي تتصل بـ/var/run/docker.sock إلى socket الخاص بـPodman لكل مستخدم بدلاً من ذلك. كما تبقى الصور التي يسحبها Docker غير مرئية لـPodman لأن البرنامجين يستخدمان وحدتي تخزين منفصلتين.
لماذا تتوقف حاويات Podman التي تعمل دون root عند تسجيل الخروج من SSH؟
لأن systemd يوقف جلسة المستخدم وكل خدمة مستخدم معها عند إغلاق آخر جلسة تسجيل دخول لك. شغّل sudo loginctl enable-linger <user>، ثم تحقق من أن loginctl show-user <user> --property=Linger يطبع Linger=yes. يحافظ Linger على تشغيل مثيل systemd الخاص بذلك المستخدم من دون جلسة نشطة. وهذا ما يجعل الحاويات تبدأ مجدداً بعد إعادة التشغيل أيضاً.
لماذا تملك الملفات في volume لدي UID 100999؟
يحوّل Podman الذي يعمل دون root معرّف UID 0 داخل الحاوية إلى مستخدمك على المضيف، ثم يطابق UID 1 وما بعده داخل الحاوية مع نطاق subuid الخاص بك. عند بدء النطاق من 100000، يصبح UID 1000 داخل الحاوية هو 100999 على المضيف. صحّح ذلك من داخل مساحة الأسماء باستخدام podman unshare chown 1000:1000 /path/to/data، أو نفّذ mount باستخدام الخيار :U عند التشغيل الأول، أو استخدم --userns=keep-id لكي تطابق UIDs داخل الحاوية UIDs الخاصة بك.
هل يمكنني الاستمرار في استخدام docker-compose.yml مع Podman؟
نعم، بطريقتين. يقرأ podman-compose الملف ويتحكم مباشرة في Podman CLI. أو فعّل socket الخاص بالتوافق باستخدام systemctl --user enable --now podman.socket، واضبط DOCKER_HOST=unix:///run/user/$(id -u)/podman/podman.sock، ثم شغّل docker compose الفعلي باستخدامه. توقّع بعض المشكلات مع network_mode: host، ومع الخدمات التي تعمل على mount لـDocker socket، ومع restart: always، الذي يحتاج إلى وحدة quadlet وlinger لكي يستمر بعد إعادة التشغيل.
هل يجعل التشغيل دون root الحاويات أكثر أماناً فعلاً؟
يزيل خطراً محدداً واحداً: إذا خرجت عملية من حاوية تعمل دون root، فستملك صلاحيات المستخدم غير المميّز بدلاً من صلاحيات root. وهذا أمر مهم، ولذلك لا توجد مجموعة docker المكافئة لـroot ضمن Podman الذي يعمل دون root. لكنه لا يوقف ثغرات kernel، ولا يحمي الملفات التي يستطيع مستخدمك نفسه قراءتها. لذلك واصل تطبيق إجراءات التحصين الأخرى التي ستنفذها على أي خادم.