VPS پر Podman بمقابلہ Docker: اصل فرق کیا ہے؟
Podman daemon کے بغیر اور عموماً rootless چلتا ہے۔ VPS پر اس سے compose files، quadlets، 1024 سے کم ports اور volume ownership کیسے بدلتے ہیں؟
Podman اور Docker میں عملی فرق کیا ہے
Podman اور Docker VPS پر ایک ہی OCI (open container initiative) images چلاتے ہیں، اس لیے انتخاب کا تعلق اس بات سے نہیں کہ آپ کون سا software چلا سکتے ہیں۔ فرق process model کا ہے۔ Docker ایک root daemon چلاتا ہے جو ہر container کا انتظام کرتا ہے، جبکہ docker command ایک چھوٹا client ہے جو اس daemon سے کام کرواتا ہے۔ Podman میں daemon نہیں ہوتا۔ podman run container کو اسے چلانے والے process کے child process کے طور پر، آپ کے اپنے unprivileged user کے تحت شروع کرتا ہے۔
باقی تمام فرق اسی بنیادی حقیقت سے پیدا ہوتے ہیں۔ Auto-start کی ذمہ داری daemon کے بجائے systemd کی ہوتی ہے۔ Volume ownership user namespace کے ذریعے منتقل ہوتی ہے، اس لیے host پر ls -l سے نظر آنے والا owner وہ owner نہیں ہوتا جسے container دیکھتا ہے۔ 1024 سے کم ports bind ہونے سے انکار کرتے ہیں، جب تک آپ kernel setting تبدیل نہ کریں۔ docker CLI (command line interface) wrapper کے ذریعے کام کرتا رہتا ہے، لیکن جب کسی component کو Docker socket درکار ہو تو یہ مطابقت ختم ہو جاتی ہے۔
کوئی daemon نہیں: container شروع کرنے پر حقیقت میں کیا چلتا ہے
Docker host پر، pstree -a، dockerd کو root کے طور پر دکھاتا ہے، اس کے ساتھ containerd دکھاتا ہے، اور ہر چلتے ہوئے container کے لیے ایک containerd-shim-runc-v2 دکھاتا ہے۔ آپ کی application اسی shim کی child ہوتی ہے، اور shim، PID 1 کی child ہوتی ہے۔ کوئی چیز container کو شروع کرنے والے shell سے منسلک نہیں کرتی۔ daemon روکنے سے اس host پر موجود ہر container کا control plane ختم ہو جاتا ہے، اور default live-restore setting بند ہونے کی صورت میں systemctl restart docker آپ کے containers کو بھی restart کرتا ہے۔
Podman میں اس کے مساوی کوئی process نہیں ہوتا۔ Container شروع کریں تو ایک conmon (container monitor) process ملتا ہے، جو container کے main process کو برقرار رکھتا ہے اور اس user کی ملکیت ہوتا ہے جس نے command چلائی تھی۔
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:8080ps میں conmon کو آپ کے login user کے طور پر چلتا ہوا دکھنا چاہیے، root کے طور پر نہیں، اور curl کو 200 پرنٹ کرنا چاہیے۔ چونکہ container کا مالک کوئی مرکزی service نہیں ہوتی، اس لیے sudo apt upgrade podman پہلے سے چلنے والی کسی چیز کو نہیں روکتا، اور ایک container کا monitor crash ہونے سے دوسرے containers بھی متاثر نہیں ہوتے۔
Daemon نہ ہونے کی ایک قیمت بھی ہے۔ Reboot کے بعد کوئی چیز آپ کے containers شروع نہیں کرتی۔ Docker کا --restart=always ایک ایسا وعدہ ہے جسے daemon boot کے وقت پورا کرتا ہے، جبکہ Podman میں اس کی جگہ systemd لیتا ہے۔ اسی مقصد کے لیے ذیل کا quadlet section ہے۔
Socket اس معاملے کا دوسرا حصہ ہے۔ /var/run/docker.sock ایک root-owned API (application programming interface) endpoint ہے، اور جو بھی process اس میں write کر سکتا ہے، وہ ایسا privileged container شروع کر سکتا ہے جو host filesystem کو mount کرے۔ کسی user کو docker group میں شامل کرنے سے اسے ایک نسبتاً سست راستے کے ذریعے root کی سطح کی رسائی مل جاتی ہے۔ اس موضوع کو ہر service account کو صرف درکار رسائی دینا کے ساتھ پڑھنا مفید ہے۔ Podman کوئی socket expose نہیں کرتا، جب تک آپ اس کی درخواست نہ کریں، اور جو socket آپ کو ملتا ہے وہ /run/user/<uid>/podman/podman.sock پر ایک single user سے متعلق ہوتا ہے۔
Ubuntu 24.04 پر Podman انسٹال کریں اور تصدیق کریں کہ rootless واقعی فعال ہے
sudo apt update
sudo apt install -y podman uidmap
podman --version
podman info | grep -i rootlessuidmap پیکیج newuidmap اور newgidmap فراہم کرتا ہے۔ یہ setuid معاون پروگرام ہیں جو عام صارف کو subordinate IDs کی ایک range حاصل کرنے دیتے ہیں۔ ان کے بغیر rootless containers شروع نہیں ہوتے۔ podman info کو rootless: true دکھانا چاہیے۔
Ubuntu 24.04 میں Podman 4.9 اور Debian 13 میں Podman 5.x شامل ہے؛ یہ معلومات August 2026 میں جانچی گئی تھیں۔ یہ فرق اہم ہے، کیونکہ quadlet files کے لیے 4.4 یا اس کے بعد کا ورژن درکار ہے، جبکہ .pod quadlet files کے لیے 5.0 درکار ہے۔ upstream documentation سے کوئی مثال نقل کرنے سے پہلے podman --version چلائیں۔
ہر rootless صارف کے لیے subordinate ID range ضروری ہے:
grep "$USER" /etc/subuid /etc/subgidUbuntu میں adduser کے ذریعے بنایا گیا صارف خودکار طور پر ایک range حاصل کرتا ہے۔ useradd -M کے ذریعے یا کسی configuration tool سے بنایا گیا صارف اکثر یہ range حاصل نہیں کرتا، اور failure message اس کی وجہ بتاتا ہے:
Error: cannot find UID/GID for user deploy: no subuid ranges found for user "deploy" in /etc/subuid - check rootless mode in man pages.ایک range assign کریں، پھر اس صارف کی storage reset کریں تاکہ نئی mapping استعمال ہو:
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 deploy
podman system migrateپہلی بار چلانے پر ایک اور غیر متوقع بات سامنے آتی ہے: Podman خودکار طور پر Docker Hub استعمال نہیں کرتا۔ مختصر image name کو /etc/containers/registries.conf میں موجود unqualified-search-registries کے خلاف resolve کیا جاتا ہے، اور terminal کے بغیر script میں pull، short-name resolution enforced but cannot prompt without a TTY کے ساتھ fail ہو جاتا ہے۔ ہر بار مکمل name لکھیں۔ nginx کے بجائے docker.io/library/nginx:1.27 استعمال کریں۔
رینٹ پر لیے گئے سرور پر rootless containers حقیقت میں کیا فائدہ دیتے ہیں
rootless container ایک user namespace کے اندر چلتا ہے۔ یہ kernel کی ایک سہولت ہے جو process کو user IDs کا اپنا نجی نقشہ فراہم کرتی ہے۔ namespace کے اندر container کا superuser UID (user ID) 0 ہوتا ہے۔ اس کے باہر، آپ کے VPS پر، یہی process آپ کے عام login user کے طور پر چلتا ہے۔ container کے اندر root، host پر root نہیں ہوتا۔
یہی اس فائدے کی حقیقی حد ہے۔ جو image root کے طور پر چلنے پر اصرار کرتی ہو، جس web application میں remote code execution کا bug ہو، یا ایسا escape جو باہر UID 0 ہونے پر منحصر ہو، ان سب کو machine کی permissions کے بجائے آپ کے unprivileged user کی permissions حاصل ہوتی ہیں۔ rootless آپ کو kernel bugs سے محفوظ نہیں رکھتا۔ یہ آپ کی اپنی files کو بھی محفوظ نہیں رکھتا، کیونکہ escaped process آپ کے user کے طور پر چل رہا ہوتا ہے اور وہ ہر وہ چیز پڑھ سکتا ہے جسے آپ پڑھ سکتے ہیں۔
Docker بھی rootless mode میں چل سکتا ہے۔ dockerd-rootless-setuptool.sh install فی user ایک daemon قائم کرتا ہے اور اچھی طرح کام کرتا ہے۔ فرق default رویے کا ہے۔ Podman میں rootless mode پہلے سے استعمال ہوتا ہے، اس لیے آپ کی پہلی ناکامی ایسا container ہوتا ہے جو port 80 پر bind نہیں کر سکتا، نہ کہ ایسی service جو خاموشی سے دو سال تک root کے طور پر چلتی رہی۔
میری volume فائلوں کی ملکیت UID 100999 کے پاس کیوں ہے؟
یہ اسی user namespace کی وجہ سے ہے۔ Container کا UID 0 آپ کے host UID سے map ہوتا ہے۔ Container کا UID 1 آپ کی subuid range کے پہلے ID سے map ہوتا ہے، اور وہاں سے تعداد بڑھتی جاتی ہے۔ 100000 سے شروع ہونے والی range میں container کا UID 1000، host پر 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"Container میں 1000 ظاہر ہوتا ہے۔ Host کی listing میں مالک 100999 ظاہر ہوتا ہے، کیونکہ 100000 جمع 1000 منفی 1 برابر 100999 ہے۔ کچھ خراب نہیں ہوا، اور عام chown اسے درست نہیں کرے گا، کیونکہ آپ کا unprivileged user namespace سے باہر فائلوں کی ملکیت تبدیل نہیں کر سکتا۔
اس مسئلے کے 4 حل ہیں:
podman unshare chown 1000:1000 "$PWD/data"اسی user namespace کے اندر chown چلاتا ہے، جہاں نمبرز وہی معنی رکھتے ہیں جو container کے لیے مقرر ہیں۔-v "$PWD/data:/data:U"Podman سے source directory کی ملکیت خود درست کرنے کو کہتا ہے۔ اسے نئی directory پر استعمال کریں، ایسے data پر نہیں جس کی آپ کو ضرورت ہو۔--userns=keep-idآپ کے host UID کو container کے اندر اسی UID سے map کرتا ہے، اس لیے نئی فائلوں کی ملکیت آپ کے پاس رہتی ہے۔-v appdata:/dataجیسا named volume اس سوال سے بچا لیتا ہے، کیونکہ Podman اسے آپ کے اپنے storage کے اندر بناتا ہے اور ملکیت پہلے ہی درست ہوتی ہے۔
اگر آپ Docker میں اس مسئلے سے نمٹ چکے ہیں تو یہ اسی مسئلے کی ایک اضافی mapping layer ہے۔ بہت سی images میں موجود PUID اور PGID variables container کے اندر process کے استعمال ہونے والا UID مقرر کرتے ہیں، اور rootless Podman میں یہ UID پھر دوسری بار map ہوتا ہے۔ rootless container کے اندر PUID=1000 چلانے سے بھی host پر ایسی فائلیں بنتی ہیں جن کی ملکیت 100999 ہوتی ہے۔ دوسری mapping کو مدنظر رکھتے ہوئے نمبرز منتخب کریں، یا data کو named volume میں منتقل کر دیں اور اس مسئلے کی فکر چھوڑ دیں۔
Mounts کے بارے میں 2 مزید نکات ہیں۔ Fedora اور RHEL کی مثالوں میں نظر آنے والے :z اور :Z flags SELinux relabel options ہیں، جبکہ Ubuntu میں AppArmor استعمال ہوتا ہے، اس لیے وہاں ان کا کوئی اثر نہیں ہوتا۔ Rootless Podman ایسی host directory بھی mount نہیں کر سکتا جسے آپ کا user پڑھ نہیں سکتا۔ یہی مطلوبہ حفاظتی رویہ ہے، کوئی خرابی نہیں۔
rootless Podman پورٹ 80 شائع کرنے سے انکار کیوں کرتا ہے؟
کیونکہ 1024 سے کم پورٹ پر bind کرنے کے لیے ایسی privilege درکار ہوتی ہے جو آپ کے user کے پاس نہیں ہے۔ Error message حل بھی بتاتا ہے:
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دونوں میں سے کوئی ایک حل کام کرتا ہے۔ پورے host کے لیے threshold کم کریں:
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آخری command کو 80 واپس echo کرنا چاہیے۔ واضح رہیں کہ یہ setting کیا کرتی ہے: اب machine کا ہر user 80 اور 443 پر bind کر سکتا ہے، صرف containers چلانے والا user نہیں۔ Single-admin VPS پر یہ قابل قبول سمجھوتا ہے۔ ایسے box پر جس میں دوسرے لوگوں کے accounts موجود ہوں، یہ مناسب نہیں۔ دوسرا حل یہ ہے کہ 8080 پر publish کریں اور سامنے reverse proxy رکھیں۔ یہی وہ جگہ ہے جہاں certbot کے ذریعے nginx پر جاری اور renew کیے جانے والے certificates رکھنے چاہییں۔
Rootless publishing سے یہ بھی بدل جاتا ہے کہ آپ کی application کو کیا نظر آتا ہے۔ Podman 4.x میں rootlesskit port handler کے ساتھ default طور پر slirp4netns استعمال ہوتا ہے، اور forwarded connections میں source address تبدیل ہو جاتا ہے۔ اس لیے access log ہر visitor کو 10.0.2.100 کے طور پر record کرتا ہے۔ Podman 5.0 نے default کو pasta کر دیا، جس سے اصل client address برقرار رہتا ہے۔ 4.x میں --network slirp4netns:port_handler=slirp4netns اصل source address بحال کرتا ہے، لیکن throughput کچھ کم ہو سکتی ہے۔
یہاں ایک اچھی بات بھی ہے۔ Rootless published port ایک عام listening socket ہوتا ہے جس کی ملکیت normal process کے پاس ہوتی ہے، اس لیے آپ کے firewall کے input rules اس پر لاگو ہوتے ہیں۔ Docker ports publish کرتے وقت NAT (network address translation) rules اور اپنے forwarding accepts لکھتا ہے۔ اسی وجہ سے published Docker port اس ufw rule کو نظرانداز کرتا ہے جس کے ذریعے آپ نے اسے روکنے کا خیال کیا تھا۔ Rootful Podman بھی اسی طرح کا plumbing استعمال کرتا ہے اور یہی مسئلہ پیدا کرتا ہے۔ Rootless ایسا نہیں کرتا۔
کیا میری Docker Compose فائلیں Podman کے تحت بھی کام کرتی ہیں؟
زیادہ تر صورتوں میں، دو مختلف طریقوں سے۔ پہلا طریقہ podman-compose ہے۔ یہ ایک الگ implementation ہے جو اسی فائل کو پڑھتی ہے اور Podman CLI چلاتی ہے:
sudo apt install -y podman-compose
podman-compose up -d
podman psدوسرا طریقہ حقیقی Docker Compose کو Podman کے Docker-compatible API سے فی صارف socket کے ذریعے جوڑنا ہے:
systemctl --user enable --now podman.socket
export DOCKER_HOST="unix:///run/user/$(id -u)/podman/podman.sock"
docker compose up -d
podman psdocker compose ps اور podman ps کو ایک ہی containers کی فہرست دینی چاہیے، کیونکہ containers کا صرف ایک ہی مجموعہ موجود ہے۔ ناموں کی resolution بھی کام کرتی ہے۔ Podman کا default network backend، netavark، aardvark-dns چلاتا ہے، اس لیے user-defined network پر موجود containers ایک دوسرے کو نام کے ذریعے تلاش کر لیتے ہیں۔
ان طریقوں کی کچھ حقیقی حدود ہیں۔ جو بھی چیز /var/run/docker.sock mount کرتی ہے، اسے Podman socket کی طرف point کرنا ہوگا یا ہٹا دینا ہوگا۔ network_mode: host user namespace کے تحت مختلف طریقے سے کام کرتا ہے۔ depends_on کو condition: service_healthy کے ساتھ podman-compose کے مختلف versions میں غیر یکساں support حاصل ہے۔ restart: always reboot کے بعد خود بخود برقرار نہیں رہتا، جسے اگلا section درست کرتا ہے۔ Compose اب بھی ایک ہی فائل میں multi-container stack بیان کرنے کا اچھا طریقہ ہے، اور Podman کے تحت یہ translation layer کے طور پر کام کرتا ہے۔ جس stack کو آپ کئی سال برقرار رکھنا چاہتے ہیں، اسے quadlets میں تبدیل کریں اور دو abstractions کے بجائے ایک ہی abstraction maintain کریں۔
Pods: وہ تصور جس کا Docker میں کوئی جواب نہیں
pod ایک ایسے containers کا گروپ ہے جو ایک ہی network namespace share کرتے ہیں۔ Podman اس namespace کو برقرار رکھنے کے لیے ایک چھوٹا infra container شروع کرتا ہے، اور پھر اس کے ارکان کسی user-defined network یا service discovery کے بغیر 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 --podpodman pod ps میں pod Running تین containers کے ساتھ دکھائی دینا چاہیے، جس میں infra container بھی شامل ہے۔ اب web container Redis تک 127.0.0.1:6379 کے ذریعے پہنچتا ہے، نہ کہ app-cache:6379 کے ذریعے۔ مشترکہ namespace سے دو اصول اخذ ہوتے ہیں: ports کو pod پر publish کریں، کسی رکن پر نہیں؛ اور کوئی بھی دو ارکان ایک ہی port پر listen نہیں کر سکتے۔
یہ Kubernetes کا ماڈل ہے، اور Podman اسے ترجیح دیتا ہے۔ podman kube generate app > app.yaml چل رہے setup سے Kubernetes manifest لکھتا ہے؛ پرانے packages میں اسے podman generate kube لکھا جاتا ہے۔ podman kube play app.yaml اسے کسی دوسرے host پر دوبارہ بناتا ہے۔ Quadlet میں .kube unit type موجود ہے، جو ایسی file کو systemd service کے طور پر چلاتا ہے۔ services کو group کرنے کا یہ واقعی مختلف طریقہ ہے، اور اگر آپ کے مستقبل میں Kubernetes کا کوئی بھی امکان ہے تو Podman منتخب کرنے کی یہ سب سے مضبوط وجہ ہے۔
daemon کے بغیر خودکار آغاز: quadlet units
Quadlet ایک systemd generator ہے۔ یہ container کو بیان کرنے والی مختصر file کو boot کے وقت حقیقی systemd service میں تبدیل کرتا ہے۔ Rootless user کے لیے files ~/.config/containers/systemd/ میں، یا root کے لیے /etc/containers/systemd/ میں رکھی جاتی ہیں۔
~/.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 تقریباً خالی ہو سکتی ہے، کیونکہ section header ہی volume بناتا ہے:
[Volume]systemctl --user daemon-reload
systemctl --user start caddy
systemctl --user status caddy
journalctl --user -u caddy -n 50Service کا نام filename سے آتا ہے: caddy.container، caddy.service بن جاتی ہے۔ systemctl --user enable caddy نہ چلائیں۔ Generated units کو enable نہیں کیا جا سکتا، اور systemd جواب دیتا ہے Failed to enable unit: Unit /run/user/1000/systemd/generator/caddy.service is transient or generated.۔ [Install] section boot کے وقت container شروع کرتا ہے، جبکہ daemon-reload file میں ترمیم کے بعد unit دوبارہ بناتا ہے۔
اب وہ setting جو تقریباً ہر کسی کو مشکل میں ڈالتی ہے:
sudo loginctl enable-linger deploy
loginctl show-user deploy --property=LingerLinger=yes کی توقع رکھیں۔ Linger کے بغیر، آخری SSH connection بند ہوتے ہی systemd پورا user session ختم کر دیتا ہے۔ اس کے ساتھ تمام rootless containers بھی رک جاتے ہیں، اور boot کے وقت ان میں سے کوئی دوبارہ شروع نہیں ہوتا۔ جو containers logout کرتے ہی غائب ہو جائیں، ان کی وجہ ہمیشہ یہی ہوتی ہے۔
چونکہ container عام service unit کا main process ہوتا ہے، اس لیے systemd کے اپنے controls براہِ راست لاگو ہوتے ہیں۔ [Service] section میں MemoryMax= اور CPUQuota= بالکل اسی طرح کام کرتے ہیں جیسے کسی بھی دوسری service پر جو آپ systemd کے ذریعے محدود کرتے ہیں۔ اس کے لیے cgroup v2 (control group version 2) درکار ہے، جسے Ubuntu نے 22.04 سے default کے طور پر استعمال کیا ہے۔ podman info | grep -i cgroup سے تصدیق کریں۔
Updates کے لیے متعلقہ mechanism موجود ہے۔ AutoUpdate=registry اور systemctl --user enable --now podman-auto-update.timer مل کر اسی tag پر registry میں نئی image تلاش کرتے ہیں، unit کو restart کرتے ہیں، اور اگر نیا container start نہ ہو تو پچھلی image پر واپس آ جاتے ہیں۔ یہ دیکھنے کے لیے پہلے podman auto-update --dry-run چلائیں کہ کیا تبدیلیاں ہوں گی۔ پرانا podman generate systemd command اب بھی موجود ہے، لیکن deprecated ہے۔ اس لیے نئی چیزوں کے لیے quadlets لکھیں۔
جہاں docker alias کام کرتا ہے، اور جہاں نہیں کرتا
sudo apt install -y podman-docker
sudo touch /etc/containers/nodocker
docker pspodman-docker ایک /usr/bin/docker wrapper انسٹال کرتا ہے جو Podman کو call کرتا ہے۔ nodocker فائل کے بغیر ہر call پہلے Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg. دکھاتی ہے۔ یہ wrapper ان commands کا احاطہ کرتا ہے جو آپ روزانہ استعمال کرتے ہیں: run، ps، logs، exec، build، pull، push، inspect، cp، volume، network۔
جو چیز منتقل نہیں ہوتی، اس کی فہرست مختصر مگر زیادہ اہم ہے۔ Swarm mode کا کوئی equivalent نہیں، اس لیے Swarm stack کے لیے کوئی target موجود نہیں ہوتا۔ Docker socket سے رابطہ کرنے والے tools کے لیے Podman socket کو export کرنا ضروری ہے، اور بعض tools پھر بھی فرق محسوس کرتے ہیں؛ Traefik کا Docker provider /run/user/<uid>/podman/podman.sock کی طرف point کرنے پر کام کرتا ہے، جبکہ Watchtower کے لیے کوئی جگہ نہیں، کیونکہ podman auto-update یہی کام کرتا ہے۔ Storage الگ ہوتا ہے، اس لیے Podman وہ images نہیں دیکھ سکتا جو آپ پہلے ہی Docker کے ذریعے pull کر چکے ہیں، اور مصروف Docker host پر podman images ابتدا میں خالی ہوتا ہے۔
چلتے ہوئے stack کو مرحلہ وار منتقل کرنا
- وہ غیر مراعات یافتہ user بنائیں یا منتخب کریں جو containers کا مالک ہوگا، اور تصدیق کریں کہ اس کے لیے
/etc/subuidمیں range موجود ہے۔ - registry سے حاصل کردہ ہر چیز کو مکمل نام استعمال کرتے ہوئے دوبارہ pull کریں۔ Podman کا اپنا image store ہوتا ہے، اور یہ Docker کے image store سے images نہیں پڑھتا۔
- مقامی طور پر build کی گئی images کو
docker save app:1.4 | podman loadکے ذریعے منتقل کریں۔ - Docker container کو stop کریں، ہر volume کے contents کو
/var/lib/docker/volumes/<name>/_dataسے باہر copy کریں، پھرpodman unshare chown -R 1000:1000 <path>کے ذریعے ownership درست کریں۔ - port کا فیصلہ کریں: reverse proxy کے پیچھے 1024 سے اوپر کا port publish کریں، یا
net.ipv4.ip_unprivileged_port_startset کریں۔ - ہر container کے لیے ایک quadlet file لکھیں،
systemctl --user daemon-reloadچلائیں، اور ہر service start کریں۔ sudo loginctl enable-linger <user>چلائیں، VPS کو reboot کریں، دوبارہ log in کریں، اور check کریں کہpodman psدوبارہ ہر service فہرست میں دکھاتا ہے۔
دونوں engines ایک دوسرے کے ساتھ کچھ share نہیں کرتے: image storage اور networks الگ الگ ہوتے ہیں۔ اس لیے migration کے دوران دونوں engines چلا سکتے ہیں، اور ان کے درمیان واحد ممکنہ تصادم host port number پر ہوگا۔ ایک service منتقل کریں، اسے ایک دن monitor کریں، پھر اگلی service منتقل کریں۔
Podman بمقابلہ Docker: آپ کے VPS پر کون سا ہونا چاہیے؟
اگر آپ کا stack ایسی compose files میں ہے جنہیں دوسرے لوگ بھی maintain کرتے ہیں، یا آپ ایسے tooling پر منحصر ہیں جو Docker socket سے رابطہ کرتا ہے، تو Docker ہی استعمال کرتے رہیں۔ دوسروں کے لکھے ہوئے configuration کے ساتھ compatibility ایک حقیقی سہولت ہے، اور Docker اس معاملے میں زیادہ بہتر ہے۔ جس team کے تمام laptops پر Docker چلتا ہو، اسے production میں بھی یہی engine چلانے سے عملی فائدہ ملتا ہے۔
اگر VPS پر چند ایسی services چل رہی ہوں جنہیں آپ ابتدا سے آخر تک control کرتے ہیں، یا آپ چاہتے ہیں کہ ہر application الگ unprivileged user کے تحت چلے اور machine پر docker group بالکل نہ ہو، تو Podman پر منتقل ہو جائیں۔ Distribution alignment بھی اہم ہے: RHEL اور اس کے rebuilds، Podman کو supported engine کے طور پر release کرتے ہیں، اس لیے ان systems پر Podman کم غیر متوقع مسائل والا راستہ ہے۔ اگر آپ باقی تمام services کو پہلے ہی systemd units کے ذریعے supervise کرتے ہیں، تو quadlets ایک نئے tool کے بجائے missing piece کے شامل ہونے جیسے محسوس ہوں گے۔
ایک درمیانی option کا ذکر بھی ضروری ہے۔ Rootful Podman، Docker کی طرح کام کرتا ہے، wrapper کے ذریعے docker command برقرار رکھتا ہے، اور پھر بھی ہمیشہ چلنے والے daemon کو ختم کر دیتا ہے۔ اس میں rootless استعمال کا حصہ بھی ختم ہو جاتا ہے، حالانکہ یہی حصہ آپ کی security position تبدیل کرتا ہے؛ اس لیے اسے عبوری مرحلہ سمجھیں۔
اگر آپ اب بھی اپنا پہلا container host تیار کر رہے ہیں تو نئے VPS پر Docker setup اور hardening کا طریقہ مختصر راستہ ہے، اور اس میں حاصل کیا گیا کوئی علم ضائع نہیں ہوگا۔ دونوں engines میں images اور volumes وہی objects ہوتے ہیں، اس لیے بعد میں منتقلی سے صرف یہ تبدیل ہوتا ہے کہ آپ کی services کو کیسے supervise کیا جاتا ہے؛ باقی تقریباً سب کچھ ویسا ہی رہتا ہے۔
FAQ
کیا Podman، Docker کا براہِ راست متبادل ہے؟
آپ جو commands ٹائپ کرتے ہیں، ان کے لیے کافی حد تک ہے۔ podman-docker انسٹال کرنے سے /usr/bin/docker wrapper دستیاب ہو جاتا ہے، اور run، ps، build، logs اور exec اسی طرح کام کرتے ہیں۔ یہ daemon کا متبادل نہیں ہے۔ اس کا کوئی Swarm equivalent نہیں، /var/run/docker.sock سے connect ہونے والے tools کو per-user Podman socket کی طرف point کرنا پڑتا ہے، اور Docker سے pull کی گئی images Podman کو نظر نہیں آتیں کیونکہ دونوں الگ storage استعمال کرتے ہیں۔
SSH سے logout کرنے پر میرے rootless Podman containers کیوں رک جاتے ہیں؟
کیونکہ آخری login بند ہونے پر systemd user session اور اس کے ساتھ ہر user service کو stop کر دیتا ہے۔ sudo loginctl enable-linger <user> چلائیں، پھر تصدیق کریں کہ loginctl show-user <user> --property=Linger، Linger=yes print کرتا ہے۔ Linger اس user کی systemd instance کو کسی active session کے بغیر بھی running رکھتا ہے۔ اسی کی وجہ سے reboot کے بعد containers دوبارہ start ہوتے ہیں۔
میرے volume میں موجود files کی ملکیت UID 100999 کے پاس کیوں ہے؟
Rootless Podman، container UID 0 کو آپ کے host user سے map کرتا ہے، پھر container UID 1 اور اس سے اوپر کی IDs کو آپ کی subuid range پر map کرتا ہے۔ 100000 سے شروع ہونے والی range میں container UID 1000، host پر 100999 بن جاتا ہے۔ اسے namespace کے اندر podman unshare chown 1000:1000 /path/to/data سے درست کریں، پہلی run پر :U flag کے ساتھ mount کریں، یا --userns=keep-id استعمال کریں تاکہ container UIDs آپ کی اپنی UID سے match کریں۔
کیا میں Podman کے ساتھ docker-compose.yml استعمال جاری رکھ سکتا ہوں؟
ہاں، دو طریقوں سے۔ podman-compose اس file کو پڑھ کر Podman CLI کو براہِ راست چلاتا ہے۔ یا systemctl --user enable --now podman.socket کے ساتھ compatibility socket enable کریں، DOCKER_HOST=unix:///run/user/$(id -u)/podman/podman.sock set کریں، اور اس کے خلاف حقیقی docker compose چلائیں۔ network_mode: host، Docker socket mount کرنے والی services، اور restart: always کے ساتھ مسائل کی توقع رکھیں۔ reboot کے بعد چلتے رہنے کے لیے restart: always کو quadlet unit اور linger درکار ہیں۔
کیا rootless واقعی containers کو زیادہ محفوظ بناتا ہے؟
یہ ایک مخصوص خطرہ ختم کرتا ہے: rootless container سے escape کرنے والا process، root کے بجائے آپ کے unprivileged user کی permissions رکھتا ہے۔ یہ فائدہ مند ہے، اور اسی لیے root کے مساوی docker group کا rootless Podman میں کوئی counterpart نہیں ہے۔ یہ kernel vulnerabilities کو نہیں روکتا، اور ان files کی حفاظت نہیں کرتا جنہیں آپ کا اپنا user پڑھ سکتا ہے۔ اس لیے وہ باقی hardening برقرار رکھیں جو آپ کسی بھی server پر کرتے ہیں۔