Podman أم Docker على VPS: ما الفرق فعلياً؟
يعمل Podman دون daemon وبصلاحيات مستخدم افتراضياً. تعرّف إلى أثر ذلك على ملفات Compose وquadlets والمنافذ وملكية volumes على خادم مستأجر.
ما الذي يختلف فعلياً بين Podman وDocker
يشغّل Podman وDocker صور OCI (مبادرة الحاويات المفتوحة) نفسها على VPS، لذلك لا يتعلق الاختيار بالبرنامج الذي يمكنك تشغيله. يكمن الاختلاف في نموذج العمليات. يشغّل Docker daemon بصلاحيات root يملك كل حاوية، بينما الأمر docker عبارة عن عميل صغير يطلب من ذلك daemon تنفيذ العمل. لا يستخدم Podman daemon؛ إذ يبدأ podman run الحاوية كعملية فرعية للعملية التي استدعته، وذلك ضمن حساب المستخدم غير المميّز الخاص بك.
تنتج كل الاختلافات الأخرى عن هذه الحقيقة. تصبح مهمة التشغيل التلقائي من مسؤولية systemd بدلاً من daemon. تمر ملكية volume عبر user namespace، لذلك لا يكون المالك الذي تراه باستخدام ls -l على المضيف هو المالك الذي تراه الحاوية. ترفض المنافذ الأقل من 1024 الارتباط إلى أن تغيّر إعداداً في kernel. تواصل واجهة docker (واجهة سطر الأوامر) العمل عبر wrapper، إلى أن يحاول شيء ما استخدام Docker socket.
لا يوجد daemon: ما الذي يعمل فعلياً عند بدء حاوية
على مضيف Docker، يعرض pstree -a العملية dockerd بصلاحيات root، ويعرض containerd بجانبها، وعملية containerd-shim-runc-v2 واحدة لكل حاوية قيد التشغيل. تطبيقك تابع لذلك الـshim، والـshim تابع لـPID 1. لا يوجد أي ارتباط بين الحاوية وshell الذي بدأها. أوقف الـ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 في Docker وعد يحافظ عليه الـdaemon عند الإقلاع. أما Podman فيستبدله بـsystemd، وهذا هو الغرض من قسم quadlet أدناه.
المقبس هو الجزء الآخر من الصورة. إنّ /var/run/docker.sock نقطة نهاية لواجهة API (واجهة برمجة التطبيقات) مملوكة لـ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 قبل نسخ مثال من وثائق المشروع المصدرية.
يحتاج كل مستخدم يشغّل Podman دون 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 على المضيف.
هذا هو حجم الفائدة الفعلي. إذا أصرّت صورة على التشغيل بصفة root، أو احتوت تطبيقات الويب على ثغرة تنفيذ تعليمات برمجية عن بُعد، أو احتاجت عملية الهروب إلى أن تكون UID 0 خارج الحاوية، فستحصل هذه الحالات كلها في النهاية على صلاحيات المستخدم غير المميّز لديك بدلاً من صلاحيات الجهاز. لكن التشغيل بلا root لا يحميك من أخطاء النواة، ولا يحمي ملفاتك أنت، لأن العملية التي خرجت من الحاوية تعمل بصفتك ويمكنها قراءة كل ما يمكنك قراءته. وتعتمد الحماية على الوحدة المعزولة بقدر اعتمادها على تعيين UID، ويمكن رؤية ذلك بسهولة أكبر في jail في FreeBSD، التي تغلف بيئة مستخدم كاملة تديرها مثل جهاز صغير بدلاً من صورة متعددة الطبقات تُسحب من سجل.
يمكن لـDocker أن يعمل بلا root أيضاً. dockerd-rootless-setuptool.sh install ينشئ daemon خاصاً بكل مستخدم، ويعمل ذلك جيداً. يكمن الفرق في الاتجاه الافتراضي. مع Podman تحصل على التشغيل بلا root من دون طلب ذلك، لذلك يكون أول فشل لديك حاوية لا تستطيع ربط المنفذ 80، بدلاً من خدمة تعمل بهدوء بصفة root لمدة عامين.
لماذا تملك ملفات volume المعرّف 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معرّف المستخدم على المضيف مع المعرّف نفسه داخل الحاوية، لذلك تُنشأ الملفات الجديدة مملوكةً لك. - يتجنب volume مُسمّى مثل
-v appdata:/dataهذه المشكلة، لأن Podman ينشئه داخل مساحة التخزين الخاصة بك مع ضبط الملكية مسبقاً.
إذا واجهت هذه المشكلة في Docker، فهي المشكلة نفسها ولكن على طبقة أخرى. متغيرا PUID وPGID اللذان توفرهما كثير من الصور يحددان UID الذي تستخدمه العملية داخل الحاوية، ثم تُطبَّق مطابقة هذا المعرّف مرة ثانية مع rootless Podman. لذلك يظل PUID=1000 داخل حاوية rootless يكتب ملفات على المضيف مملوكةً بالمعرّف 100999. اختر الأرقام مع مراعاة عملية المطابقة الثانية، أو انقل البيانات إلى volume مُسمّى وتوقف عن التفكير في هذه المشكلة.
ملاحظتان إضافيتان حول عمليات mount. الخياران :z و:Z اللذان تراهما في أمثلة Fedora وRHEL هما خيارا إعادة وسم لـSELinux، بينما يستخدم Ubuntu AppArmor، ولذلك لا يفعلان شيئاً هناك. لا يستطيع rootless Podman أيضاً إجراء mount لدليل على المضيف لا يملك المستخدم صلاحية قراءته، وهذا مقصود وليس عطلاً.
لماذا يرفض Podman غير الجذر نشر المنفذ 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 افتراضياً، وتصل الاتصالات المُعاد توجيهها بعنوان مصدر معاد كتابته، لذلك يسجّل access log كل زائر على أنه 10.0.2.100. غيّر Podman 5.0 القيمة الافتراضية إلى pasta، ما يحافظ على عنوان العميل الحقيقي. في الإصدار 4.x، تعيد --network slirp4netns:port_handler=slirp4netns عنوان المصدر الحقيقي، لكن ذلك يقلل معدل النقل إلى حد ما.
هناك جانب إيجابي مهم. منفذ منشور دون root هو socket استماع عادي تملكه عملية عادية، لذلك تنطبق عليه قواعد الإدخال في جدار الحماية. ينشر Docker المنافذ عبر كتابة قواعد NAT (ترجمة عناوين الشبكة) وقواعد قبول خاصة به لإعادة التوجيه. ولهذا تحديداً يتجاهل منفذ Docker المنشور قاعدة ufw التي ظننت أنها تمنعه. يستخدم Podman الذي يعمل بصلاحيات root آلية مشابهة، ويرث المشكلة نفسها. أما النشر دون root فلا يفعل ذلك.
هل ستظل ملفات Docker Compose لديك تعمل مع Podman؟
في الغالب، عبر مسارين مختلفين. المسار الأول هو podman-compose، وهو تطبيق منفصل يقرأ الملف نفسه ويتحكم في واجهة Podman لسطر الأوامر:
sudo apt install -y podman-compose
podman-compose up -d
podman psالمسار الثاني هو استخدام Docker Compose الفعلي للاتصال بواجهة Podman المتوافقة مع Docker عبر socket خاص بالمستخدم:
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 يجب توجيهه إلى socket الخاص بـ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 مع ثلاث حاويات، بما في ذلك حاوية infra. تصل حاوية web الآن إلى 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 generator. يحوّل ملفاً قصيراً يصف حاوية إلى خدمة 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.
لكن هناك قائمة أقصر وأكثر تحديداً لما لا ينتقل. لا يوجد مكافئ لوضع 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 على هذه الأنظمة المسار الأقل عرضة للمفاجآت. إذا أردت استخدام Docker على أحد هذه المضيفات رغم ذلك، فإن مسار dnf على Rocky Linux وAlmaLinux يبدأ بإزالة غلاف podman-docker الذي يملك الأمر docker هناك. وإذا كنت تدير كل ما عدا ذلك باستخدام وحدات systemd، فستبدو quadlets كأنها قطعة مفقودة وصلت، لا كأداة جديدة تحتاج إلى تعلمها.
يجدر ذكر خيار متوسط. يعمل Podman بنمط rootful بطريقة تشبه Docker كثيراً، ويحافظ على الأمر docker من خلال الغلاف، كما يزيل daemon الذي يعمل دائماً. لكنه يتخلى أيضاً عن جانب rootless، وهو الجزء الذي يغيّر وضعك الأمني، لذلك اعتبره محطة مؤقتة في الطريق.
إذا كنت لا تزال تنشئ أول مضيف للحاويات، فإن مسار إعداد Docker وتقويته على VPS جديد هو الطريق الأقصر، ولن تذهب أي من تلك المعرفة سدى. الصور وvolumes هي الكيانات نفسها في كلا المحركين، لذلك يغيّر الانتقال طريقة إدارة خدماتك والإشراف عليها، ولا يغيّر إلا القليل غير ذلك.
FAQ
هل يُعد Podman بديلاً مباشراً لـ Docker؟
بالنسبة إلى الأوامر التي تكتبها، يكاد يكون كذلك. يؤدي تثبيت podman-docker إلى توفير غلاف /usr/bin/docker، وتعمل run وps وbuild وlogs وexec بالطريقة نفسها. لكنه ليس بديلاً عن daemon. لا يوجد مكافئ لـ Swarm، ويجب توجيه الأدوات التي تتصل بـ /var/run/docker.sock إلى مقبس 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 معرّف المستخدم 0 داخل الحاوية إلى مستخدمك على المضيف، ثم يعيّن معرّف المستخدم 1 وما بعده داخل الحاوية إلى نطاق subuid الخاص بك. عند بدء النطاق من 100000، يصبح معرّف المستخدم 1000 داخل الحاوية هو 100999 على المضيف. صحّح ذلك من داخل namespace باستخدام podman unshare chown 1000:1000 /path/to/data، أو نفّذ عملية mount باستخدام العلم :U عند التشغيل الأول، أو استخدم --userns=keep-id بحيث تطابق معرّفات المستخدمين داخل الحاوية معرّف المستخدم الخاص بك.
هل يمكنني مواصلة استخدام docker-compose.yml مع Podman؟
نعم، بطريقتين. يقرأ podman-compose الملف ويتحكم مباشرة في واجهة Podman CLI. أو فعّل مقبس التوافق باستخدام systemctl --user enable --now podman.socket، واضبط DOCKER_HOST=unix:///run/user/$(id -u)/podman/podman.sock، ثم شغّل docker compose الفعلي من خلاله. توقّع بعض المشكلات مع network_mode: host، ومع الخدمات التي تُجري mount لمقبس Docker، ومع restart: always، الذي يحتاج إلى وحدة quadlet وإلى Linger ليستمر بعد إعادة التشغيل.
هل يجعل التشغيل دون root الحاويات أكثر أماناً فعلاً؟
إنه يزيل خطراً محدداً: إذا خرجت عملية من حاوية تعمل دون root، فستمتلك صلاحيات المستخدم غير المميّز لديك بدلاً من صلاحيات root. وهذا أمر مهم، ولذلك لا توجد مجموعة docker المكافئة لـ root تحت Podman الذي يعمل دون root. لكنه لا يوقف ثغرات kernel، ولا يحمي الملفات التي يستطيع مستخدمك نفسه قراءتها. لذلك واصل تطبيق إجراءات التحصين الأخرى التي ستنفذها على أي خادم.