FreeBSD Jails और Docker Containers में क्या अंतर है?
FreeBSD Jails एक पूर्ण userland को अलग करती हैं जबकि Docker layered images का उपयोग करता है। इनके networking, state और resource limits के मुख्य अंतरों को विस्तार से समझें।
FreeBSD jails और Docker containers एक ही समस्या को दो अलग-अलग रूपों में हल करते हैं। दोनों एक साझा kernel पर isolated userlands चलाते हैं, इसलिए इनमें से कोई भी virtual machine नहीं है। अंतर इस बात में है कि इनके भीतर क्या होता है। एक Docker container किसी registry से pull की गई layered image से एक process चलाता है। एक jail एक पूर्ण FreeBSD userland चलाती है: अपना स्वयं का /etc, अपनी rc startup scripts, अपना स्वयं का pkg database, और जितनी चाहें उतनी processes। इस पृष्ठ पर मौजूद लगभग हर अन्य अंतर इसी एक मुख्य अंतर से उत्पन्न होता है।
SSD Nodes FreeBSD images प्रदान नहीं करता है। आप इस platform पर FreeBSD server किराए पर नहीं ले सकते, और नीचे दी गई जानकारी आपके द्वारा यहाँ खरीदी जा सकने वाली किसी मशीन के लिए install guide नहीं है। यह दो isolation models की तुलना है, जिसे इसलिए लिखा गया है ताकि आप यह समझ सकें कि किसी workload को वास्तव में किसकी आवश्यकता है, और ताकि आप FreeBSD टीम के setup को बिना किसी अनुमान के पढ़ सकें।
Jail वास्तव में क्या है
FreeBSD 4.0 में Jails मार्च 2000 में आए थे, जो इन्हें cgroups से पुराना और Docker से लगभग एक दशक पुराना बनाता है। यह तंत्र एक kernel call है। jail(8) एक directory tree लेता है और उसके अंदर एक jail ID के साथ processes शुरू करता है, और फिर kernel उस ID वाली किसी भी process के लिए निश्चित operations करने से मना कर देता है। एक jailed process अपने jail के बाहर की processes को नहीं देख सकती, filesystem को mount या unmount नहीं कर सकती, kernel modules लोड नहीं कर सकती, और उन network addresses से bind नहीं हो सकती जो jail को नहीं दिए गए हैं। इसमें सीखने के लिए कोई अलग namespace type नहीं है और न ही प्रति-feature कोई opt-in है: ये प्रतिबंध एक इकाई के रूप में आते हैं, जिन्हें jail की config में parameters द्वारा समायोजित किया जाता है।
Host पर, jls चल रहे jails की सूची दिखाता है और jexec web sh आपको web नाम के jail के अंदर एक shell में ले जाता है।
आप एक directory में FreeBSD userland रखकर jail बनाते हैं। base system आपके लिए ऐसा करता है:
sudo bsdinstall jail /usr/local/jails/containers/webयह आपके release के लिए base distribution set लाता है और सामान्य post-install steps चलाता है, ताकि आप root password सेट कर सकें और timezone चुन सकें, ठीक वैसे ही जैसे आप एक नए सर्वर पर करते। इसका परिणाम एक folder में स्थित FreeBSD installation है। फिर आप इसे /etc/jail.conf में वर्णित करते हैं:
web {
host.hostname = "web.example.internal";
path = "/usr/local/jails/containers/web";
ip4.addr = "10.0.0.10";
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
mount.devfs;
}इसे शुरू करें, फिर जाँचें:
sudo service jail start web
jlsjls को अब JID, hostname और IP address के साथ web को सूचीबद्ध करना चाहिए। यदि jail दिखाई नहीं देता है, तो सीधे sudo jail -c web चलाएँ। यह foreground में वही configuration लागू करता है और वह parameter print करता है जिसे वह स्वीकार नहीं कर सका, बजाय इसके कि failure को service output में छोड़ दे।
वह पंक्ति जिसे दो बार पढ़ना चाहिए, वह exec.start = "/bin/sh /etc/rc" है। Jail शुरू करने पर उसके अंदर FreeBSD की सामान्य boot script चलती है, इसलिए jail अपने स्वयं के /etc/rc.conf में सक्षम हर service को शुरू कर देता है। Docker container में इसका कोई समकक्ष चरण नहीं है, क्योंकि यह image की entrypoint process को चलाता है और उस process के रुकने पर बंद हो जाता है।
सॉफ्टवेयर प्राप्त करने के तरीके: इमेजेस और रजिस्ट्री बनाम यूजरलैंड जिसे आप स्वयं भरते हैं
यह वह अंतर है जिसे आप पहले दिन ही महसूस करते हैं।
Docker के साथ आप सॉफ्टवेयर का नाम लेते हैं और उसे प्राप्त कर लेते हैं। docker pull nginx एक लेयर्ड, कंटेंट-एड्रेस्ड इमेज को फेच करता है जिसे किसी और ने बनाया और टेस्ट किया है, और docker compose up -d इसे इसके वॉल्यूम्स और नेटवर्क के साथ स्टार्ट कर देता है। रजिस्ट्री ही मुख्य प्रोडक्ट है। Docker वर्कफ़्लो का अधिकांश मूल्य इस बात में है कि हजारों प्रोजेक्ट्स एक वर्किंग इमेज पब्लिश करते हैं, जो VPS पर Docker चलाने को एक छोटा काम बना देता है, न कि एक लंबा प्रोजेक्ट।
FreeBSD में जेल इमेजेस की कोई डिफ़ॉल्ट पब्लिक रजिस्ट्री नहीं होती है। आप एक खाली यूजरलैंड बनाते हैं और उसमें इंस्टॉल करते हैं, ठीक वैसे ही जैसे आप एक बेयर सर्वर सेटअप करते हैं। इसमें टाइपिंग अधिक करनी पड़ती है। यह अधिक पारदर्शी भी है, क्योंकि जेल में वही चलता है जिसे pkg ने वहां रखा है, उसी पैकेज सेट से जिसका उपयोग होस्ट करता है।
टूलिंग इसे छोटा बना देती है। BastilleBSD एक सामान्य जेल मैनेजर है और यह एक पैकेज है:
sudo pkg install bastille
sudo sysrc bastille_enable=YES
sudo bastille setup
sudo bastille bootstrap 15.1-RELEASEbastille setup आपके लिए नेटवर्किंग, स्टोरेज और फायरवॉल को कॉन्फ़िगर करता है। bastille bootstrap एक रिलीज़ को एक बार डाउनलोड करता है, और उसके बाद आप जो भी जेल बनाते हैं, वह इसे पुनः उपयोग करती है। FreeBSD 15.1 वर्तमान प्रोडक्शन रिलीज़ है, जो जून 2026 में आई है; आप जो भी रिलीज़ चला रहे हैं उसे बदलें।
जेल बनाना फिर एक कमांड का काम है, और उसे भरना एक और कमांड का:
sudo bastille create web 15.1-RELEASE 10.17.89.10/24
sudo bastille pkg web install nginx
sudo bastille service web nginx start
sudo bastille console webbastille console web आपको जेल के अंदर एक लॉगिन शेल देता है, और bastille list दिखाता है कि होस्ट पर क्या मौजूद है। बिल्ड को दोहराने के लिए, Bastille टेम्पलेट्स स्टेप्स को एक फ़ाइल में रखते हैं और उन्हें जेल पर लागू करते हैं, जो इस दुनिया में Dockerfile के सबसे करीब है। एक टेम्पलेट को प्रत्येक जेल पर रिप्ले किया जाता है। कुछ भी पहले से बना हुआ नहीं आता है।
इसलिए ईमानदार सारांश संक्षिप्त है। Docker आपको दूसरों के बिल्ड्स देता है। जेल आपको अपने स्वयं के इंस्टॉल्स देती हैं। यदि आपकी शॉर्टलिस्ट का सॉफ्टवेयर केवल कंटेनर इमेज के रूप में आता है और किसी अन्य रूप में नहीं, तो यह किसी अन्य तर्क से पहले ही निर्णय तय कर देता है।
State और upgrades: ZFS द्वारा किए गए बदलाव
Docker जानबूझकर state को अलग रखता है। container का filesystem अस्थायी होता है, आपका डेटा एक named volume या bind mount में रहता है, और एक upgrade का मतलब docker compose pull के बाद docker compose up -d करना होता है। container को बदल दिया जाता है, और जो कुछ भी आपने volume में नहीं रखा था, वह नष्ट हो जाता है। यदि आप नियमों का पालन करते हैं तो यह एक विशेषता है, और यदि आप भूल जाते हैं तो यह डेटा हानि की घटना है। यही कारण है कि bind mounts और named volumes के बीच का चुनाव एक Compose stack में इतना महत्वपूर्ण होता है।
एक jail state को अलग नहीं करती है, और ZFS ही वह कारण है जिससे यह काम करता है। पूरी jail एक ही dataset होती है:
sudo zfs snapshot zroot/jails/containers/web@pre-upgrade
sudo pkg -j web upgrade
sudo zfs rollback zroot/jails/containers/web@pre-upgradeइसे चलाने से पहले zfs list के साथ वास्तविक dataset नाम की जाँच करें; ऊपर दिया गया path वह layout है जिसका handbook उपयोग करता है। snapshot में लगभग एक सेकंड का समय लगता है और जब तक jail की सामग्री नहीं बदलती, तब तक यह लगभग कोई space नहीं लेता है। यदि upgrade service को खराब कर देता है, तो rollback पूरे userland को उसकी पिछली स्थिति में लौटा देता है, जिसमें package database और वे config files भी शामिल हैं जिन्हें आपने रात के 2 बजे हाथ से edit किया था। Docker में इसका कोई इन-बिल्ट विकल्प नहीं है, क्योंकि इसका model यह मानकर चलता है कि आपको इसकी कभी आवश्यकता नहीं होगी।
zfs clone इसका दूसरा हिस्सा है। snapshot का एक clone एक नई writable jail होती है जो अपने parent के साथ अपरिवर्तित blocks साझा करती है, इसलिए 3 GB की jail की staging copy डिस्क पर लगभग कुछ भी खर्च नहीं करती जब तक कि आप उसे बदलना शुरू न करें। इसी तरह एक FreeBSD admin upgrade का पूर्वाभ्यास करने के लिए "production के समान" jail बनाता है।
Base system का upgrade packages से अलग होता है। userland की अपनी copy रखने वाली jail के लिए:
sudo freebsd-update -b /usr/local/jails/containers/web fetch installThin jails इस काम को दोहराने से बचती हैं। वे nullfs के माध्यम से एक shared read-only base को mount करती हैं और प्रत्येक jail को अपनी एक छोटी writable layer देती हैं, इसलिए आप base को एक बार patch करते हैं और हर jail को परिणाम दिखाई देता है। Bastille डिफ़ॉल्ट रूप से thin jails बनाता है।
Networking: published ports बनाम addressing का निर्णय
Docker आपके लिए networking का निर्णय लेता है और आपसे अपवादों (exceptions) को publish करने के लिए कहता है। Containers एक bridge पर स्थित होते हैं, वे user-defined network पर service name के माध्यम से एक-दूसरे तक पहुँचते हैं, और -p 8080:80 उनमें से किसी एक को host के लिए expose करता है। Docker इसे संभव बनाने के लिए अपने स्वयं के packet filter rules लिखता है, और यही कारण है कि a published container port walks straight past ufw।
एक jail आपको शुरुआत में ही मॉडल चुनने के लिए मजबूर करती है, और इसके दो विकल्प हैं।
Shared IP. ip4.addr = "10.0.0.10" उस address को एक मौजूदा host interface में जोड़ता है और jail को उसी तक सीमित कर देता है। Jail का अपना कोई network stack नहीं होता, इसलिए यह अपना firewall नहीं चला सकती। यह वास्तव में हर address पर bind भी नहीं हो सकती: एक jailed socket जो 0.0.0.0 के लिए request करता है, उसे kernel द्वारा jail के अपने address पर rewrite कर दिया जाता है। दो jails एक ही address के port 80 पर listen नहीं कर सकतीं, इसलिए आप प्रत्येक को एक address देते हैं, या आप सामने एक reverse proxy लगा देते हैं।
VNET. Jail में vnet; जोड़ें और इसे एक पूर्ण network stack मिल जाता है: इसके अपने interfaces, अपनी routing table, और अपने firewall rules। आप इसे host के साथ epair का उपयोग करके जोड़ते हैं, जो एक virtual cable है जिसका एक सिरा दोनों तरफ होता है, और host वाले सिरे को एक bridge पर रखते हैं। यह Docker द्वारा प्रदान की जाने वाली सुविधा के सबसे करीब है, और यही वह mode है जो Bastille के -V और -B jail types के पीछे काम करता है।
Host port को jail में forward करना एक pf redirect rule है। Bastille इसे इस प्रकार wrap करता है:
sudo bastille rdr web tcp 80 80यहाँ कोई EXPOSE नहीं है और न ही कोई automatic publishing होती है। Jail तक कुछ भी तब तक नहीं पहुँचता जब तक कि उसका address या redirect rule इसकी अनुमति न दे। यह एक धीमी शुरुआत है और एक बहुत ही शांत firewall है।
संसाधन सीमाएँ: cgroups बनाम rctl
Docker एक container को cgroups के साथ सीमित करता है, और ये सीमाएँ वहीं रहती हैं जहाँ container परिभाषित होता है: --memory=1g --cpus=1.5 command line पर, या Compose file में संबंधित keys के रूप में। यदि आप अपना stack पहले से ही a Docker Compose file on a VPS में रखते हैं, तो सीमा उस service के साथ रहती है जिस पर वह लागू होती है और git में उसके साथ ही चलती है।
FreeBSD rctl का उपयोग करता है, और यह एक ऐसा subsystem है जिसे आपको चालू करना पड़ता है। Resource accounting डिफ़ॉल्ट रूप से बंद रहता है क्योंकि यह हर allocation पर थोड़ी लागत लेता है। /boot/loader.conf में tunable जोड़ें और reboot करें:
kern.racct.enable=1फिर एक rule सेट करें और उस पर नज़र रखें:
sudo rctl -a jail:web:vmemoryuse:deny=1g
rctl -hu jail:webrctl -hu jail:web jail के वर्तमान उपयोग को human-readable units में प्रिंट करता है, ताकि आप देख सकें कि कुछ भी टूटने से पहले यह सीमा के कितना करीब है। deny action jail के अंदर over-limit allocation को विफल कर देता है, ताकि आप host पर kill message के बजाय application का अपना allocation error देख सकें।
rctl -a के साथ जोड़े गए नियम अगले reboot पर गायब हो जाते हैं। FreeBSD की rctl service उन्हें /etc/rctl.conf से reload करती है, इसलिए नियम को उस file में लिखें और service को enable करें:
sudo sysrc rctl_enable=YESयह वह बिंदु है जहाँ Docker स्पष्ट रूप से अधिक सुविधाजनक है। Compose file में दी गई सीमा की समीक्षा उस service के साथ की जाती है जिसे वह नियंत्रित करती है। rctl rule एक अलग file में लिखी गई एक पंक्ति है जो कहीं और परिभाषित jail का नाम बताती है।
जब उत्तर एक virtual machine हो: bhyve
एक jail होस्ट kernel को साझा करती है, इसलिए कुछ चीजें हमेशा पहुंच से बाहर रहती हैं। यह एक अलग kernel version नहीं चला सकती, यह kernel module लोड नहीं कर सकती, और यह Linux binaries को उस तरह नहीं चला सकती जैसे एक Linux container चलाता है। FreeBSD में एक Linux compatibility layer है, जिसे linuxulator कहते हैं, लेकिन यह Linux system calls के केवल एक subset को लागू करता है और यह किसी भी मनमाने Linux image के लिए एक सामान्य समाधान नहीं है।
bhyve, FreeBSD का hypervisor है, और जब आपको एक वास्तविक machine boundary की आवश्यकता हो तो यह सही उपकरण है: एक अलग operating system, एक अलग kernel, या कोई ऐसा tenant जिसके साथ आप kernel साझा नहीं करना चाहते। इसकी कीमत आपको उस memory के रूप में चुकानी पड़ती है जो साझा होने के बजाय reserved रहती है, और एक दूसरे kernel को patch करने के रूप में। यह वही निर्णय है जो आप Linux पर containers और full virtual machines के बीच लेते हैं, और यही वह निर्णय है जो यह तय करता है कि आपको नीचे एक VPS जो nested virtualization का समर्थन करता है की आवश्यकता है या नहीं।
इकोसिस्टम, जो कि वह वास्तविक कारण है जिसके लिए अधिकांश टीमें Docker का उपयोग करती हैं
ऊपर दी गई हर बात मॉडल के बारे में है। अधिकांश टीमों के लिए चुनाव का आधार यह है कि प्रत्येक के आसपास की दुनिया कितनी बड़ी है।
Docker अपने साथ Docker Hub और GHCR, docker compose, Kubernetes (जब एक बॉक्स पर्याप्त न रहे), कंटेनर सपोर्ट के साथ पहले से तैयार CI रनर्स, और लगभग हर प्रोजेक्ट की README में एक-कमांड क्विकस्टार्ट लाता है। Jails अपने साथ FreeBSD पोर्ट्स ट्री लाते हैं, जो विशाल और सावधानीपूर्वक मेंटेन किया गया है, साथ ही इसमें उपयोग के लिए तैयार एप्लिकेशन बंडलों का एक छोटा सेट भी है। जब कोई प्रोजेक्ट केवल कंटेनर इमेज पब्लिश करता है, तो FreeBSD का तरीका यह है कि आप उसके डॉक्यूमेंटेशन को पढ़ें और स्वयं पुर्जों को जोड़ें।
Jails इस सौदे के दूसरे पक्ष में अपनी जगह बनाते हैं। आप उन्हें तब चाहते हैं जब आप पहले से ही ZFS चला रहे हों और पूरी सर्विस के स्नैपशॉट और रोलबैक को महत्व देते हों, जब आपकी सर्विसेज FreeBSD नेटिव हों, जब आप एक सिंगल प्रोसेस के बजाय प्रति टेनेंट एक पूर्ण यूजरलैंड चाहते हों, या जब आप कर्नल, पैकेट फिल्टर, फाइलसिस्टम और डॉक्यूमेंटेशन को एक सिस्टम के रूप में एक साथ मेंटेन करना चाहते हों। अंतिम बिंदु का अर्थ वही है जिसे लोग FreeBSD के सुसंगत (coherent) होने के संदर्भ में कहते हैं, और इस पर सर्वर प्लेटफॉर्म के रूप में Linux और FreeBSD की व्यापक तुलना और FreeBSD 15 ने सर्वर उपयोग के लिए क्या बदला में अधिक विस्तार से चर्चा की गई है।
एक अंतिम निर्णय। यदि आपकी टीम पहले से ही Docker जानती है, तो माइग्रेशन की लागत वास्तविक है और इसका लाभ विशिष्ट होना चाहिए। केवल आइसोलेशन क्वालिटी के लिए स्विच न करें; दोनों मॉडल इतने करीब हैं कि आपका कॉन्फ़िगरेशन अधिक मायने रखता है। स्विच तब करें जब आप पूरी सर्विसेज के ZFS-आधारित रोलबैक चाहते हों, या क्योंकि आप पहले से ही FreeBSD पर हैं।
FAQ
क्या मैं FreeBSD पर Docker images चला सकता हूँ?
Linux images नहीं, और न ही यह एक समर्थित तरीका है। FreeBSD में OCI container support मौजूद है: sudo pkg install -y podman-suite, Podman को install करता है, जो ocijail के माध्यम से containers चलाता है। यह एक ऐसा runtime है जो अंदरूनी तौर पर वास्तविक jails बनाता है। इसके लिए container monitor हेतु fdescfs को /dev/fd पर mount करना आवश्यक है, और container NAT (network address translation) के लिए pf की आवश्यकता होती है। FreeBSD-native OCI images सबसे बेहतर काम करती हैं। Linux images के लिए अतिरिक्त रूप से Linux compatibility layer की आवश्यकता होती है, और अगस्त 2026 तक FreeBSD Podman port को अभी भी experimental माना जाता है। यदि आपका deployment Linux images का एक stack है, तो इसे Linux पर ही चलाएं। RHEL परिवार पर इसका अर्थ है Rocky Linux या AlmaLinux पर Docker install करना, जहाँ Podman उस package के रूप में दूसरी बार सामने आता है जो कुछ भी install करने से पहले ही docker command का स्वामी होता है।
क्या FreeBSD jails, Docker containers से अधिक सुरक्षित हैं?
दोनों एक ही host kernel साझा करते हैं, इसलिए kernel bug दोनों के लिए जोखिम है, और आप किसी भी तकनीक को पूरी तरह से अविश्वसनीय (untrusted) code के लिए boundary के रूप में नहीं चुनेंगे। अंतर शुरुआत के बिंदु में है। एक jail की शुरुआत operations के एक व्यापक समूह को अस्वीकार करने से होती है और आप उन्हें एक-एक parameter करके पुनः सक्षम (re-enable) करते हैं। एक Docker container की शुरुआत namespaces के एक समूह के भीतर root के रूप में होती है, जिसमें कुछ capabilities हटा दी जाती हैं, और आगे की hardening विकल्प पर आधारित (opt-in) होती है। व्यवहार में, configuration मॉडल से अधिक मायने रखती है: allow.mount और allow.raw_sockets के साथ चल रही एक jail, सावधानीपूर्वक configure किए गए container से अधिक सुरक्षित नहीं है।
मैं jail का backup कैसे लूँ?
Dataset का snapshot लें और उसे भेजें। sudo zfs snapshot zroot/jails/containers/web@backup करें, फिर उस snapshot को zfs send करके किसी अन्य pool में या ऐसी file में डालें जिसे आप box से बाहर copy कर सकें। चूंकि एक jail अपना पूरा userland एक ही dataset में रखती है, इसलिए snapshot installed packages और data को एक consistent point पर capture कर लेता है, साथ ही उन सभी config files को भी जिन्हें आपने हाथ से edit किया है। यह Docker की आदत के विपरीत है, जहाँ आप named volumes और Compose file का backup लेते हैं और बाकी सब कुछ image से फिर से बनाते हैं।
क्या मुझे BastilleBSD की आवश्यकता है, या base system पर्याप्त है?
Base system पर्याप्त है, और शुरुआत करने के लिए यह सबसे अच्छी जगह है। jail.conf, jls, jexec और service jail start पूरे मॉडल को कवर करते हैं, और एक बार जब आप उन्हें जान लेते हैं, तो आप किसी भी FreeBSD host को उस host के विशिष्ट tooling को सीखे बिना पढ़ सकते हैं। Bastille इसके ऊपर एक सुविधा परत (convenience layer) है: यह releases को bootstrap करती है, thin jails बनाती है, templates लागू करती है और आपके लिए pf redirect rules लिखती है। पहले base commands सीखें, फिर जब jails की संख्या के कारण typing थकाऊ लगने लगे, तब Bastille का उपयोग करें।