इस लेख में, Bazel में सैंडबॉक्सिंग, sandboxfs को इंस्टॉल करने, और सैंडबॉक्सिंग एनवायरमेंट को डीबग करने के बारे में बताया गया है.
सैंडबॉक्सिंग, अनुमति को सीमित करने की एक रणनीति है. यह प्रोसेस को एक-दूसरे से या सिस्टम के संसाधनों से अलग करती है. Bazel के लिए, इसका मतलब फ़ाइल सिस्टम के ऐक्सेस को सीमित करना है.
Bazel का फ़ाइल सिस्टम सैंडबॉक्स, प्रोसेस को वर्किंग डायरेक्ट्री में चलाता है. इसमें सिर्फ़ जाने-पहचाने इनपुट होते हैं, ताकि कंपाइलर और अन्य टूल ऐसी सोर्स फ़ाइलें न देख पाएं जिन्हें उन्हें ऐक्सेस नहीं करना चाहिए. ऐसा तब तक होता है, जब तक उन्हें उन फ़ाइलों के पूरे पाथ पता न हों.
सैंडबॉक्स की प्रोसेस, होस्ट एनवायरमेंट को किसी भी तरह से नहीं छिपाती है. प्रोसेस, फ़ाइल सिस्टम में मौजूद सभी फ़ाइलों को बिना किसी पाबंदी के ऐक्सेस कर सकती हैं. हालांकि, जिन प्लैटफ़ॉर्म पर उपयोगकर्ता नेमस्पेस काम करते हैं वहां प्रोसेस, अपनी वर्किंग डायरेक्ट्री से बाहर की किसी भी फ़ाइल में बदलाव नहीं कर सकतीं. इससे यह पक्का किया जाता है कि बिल्ड ग्राफ़ में ऐसी छिपी हुई डिपेंडेंसी न हों जो बिल्ड को फिर से बनाने की प्रोसेस पर असर डाल सकती हैं.
खास तौर पर, Bazel हर कार्रवाई के लिए एक execroot/ डायरेक्ट्री बनाता है. यह डायरेक्ट्री, कार्रवाई के एक्ज़ीक्यूशन के समय, कार्रवाई की वर्क डायरेक्ट्री के तौर पर काम करती है. execroot/
इसमें कार्रवाई के लिए सभी इनपुट फ़ाइलें होती हैं. साथ ही, यह जनरेट किए गए किसी भी आउटपुट के लिए कंटेनर के तौर पर काम करता है. इसके बाद, Bazel, ऑपरेटिंग सिस्टम की ओर से उपलब्ध कराई गई तकनीक का इस्तेमाल करता है. जैसे, Linux पर कंटेनर और macOS पर sandbox-exec. इससे कार्रवाई को execroot/ के दायरे में सीमित किया जा सकता है.
सैंडबॉक्सिंग की वजहें
ऐक्शन सैंडबॉक्सिंग के बिना, Bazel को यह पता नहीं चलता कि कोई टूल, बिना बताए इनपुट फ़ाइलों का इस्तेमाल करता है या नहीं. ये ऐसी फ़ाइलें होती हैं जिन्हें किसी ऐक्शन की डिपेंडेंसी में साफ़ तौर पर शामिल नहीं किया जाता. जब बिना बताई गई किसी इनपुट फ़ाइल में बदलाव होता है, तब भी Bazel को लगता है कि बिल्ड अप-टू-डेट है. इसलिए, वह कार्रवाई को फिर से नहीं बनाता. इस वजह से, इंक्रीमेंटल बिल्ड गलत हो सकता है.
कैश मेमोरी की एंट्री का गलत तरीके से फिर से इस्तेमाल करने पर, रिमोट कैशिंग के दौरान समस्याएं आती हैं. शेयर की गई कैश मेमोरी में मौजूद गलत कैश मेमोरी एंट्री से, प्रोजेक्ट पर काम करने वाले हर डेवलपर पर असर पड़ता है. साथ ही, पूरी रिमोट कैश मेमोरी को मिटाना एक सही समाधान नहीं है.
सैंडबॉक्सिंग, रिमोट एक्सीक्यूशन की तरह काम करती है. अगर कोई बिल्ड सैंडबॉक्सिंग के साथ अच्छी तरह से काम करता है, तो वह रिमोट एक्सीक्यूशन के साथ भी काम करेगा. रिमोट एक्ज़ीक्यूशन को सभी ज़रूरी फ़ाइलें (लोकल टूल भी शामिल हैं) अपलोड करने की अनुमति देकर, कंपाइल क्लस्टर के रखरखाव की लागत को काफ़ी हद तक कम किया जा सकता है. ऐसा इसलिए, क्योंकि हर बार जब आपको कोई नया कंपाइलर आज़माना हो या किसी मौजूदा टूल में बदलाव करना हो, तो आपको क्लस्टर में मौजूद हर मशीन पर टूल इंस्टॉल नहीं करने पड़ेंगे.
सैंडबॉक्स की किस रणनीति का इस्तेमाल करना है
रणनीति के फ़्लैग के साथ, आपको किस तरह की सैंडबॉक्सिंग का इस्तेमाल करना है, यह चुना जा सकता है. sandboxed रणनीति का इस्तेमाल करने पर, Bazel नीचे दिए गए सैंडबॉक्स के तरीकों में से किसी एक को चुनता है. साथ ही, यह ओएस के हिसाब से सैंडबॉक्स को कम हर्मेटिक जेनेरिक सैंडबॉक्स से ज़्यादा प्राथमिकता देता है.
परसिस्टेंट वर्कर, सामान्य सैंडबॉक्स में चलते हैं. हालांकि, ऐसा तब होता है, जब --worker_sandboxing फ़्लैग पास हो जाता है.
local (इसे standalone भी कहा जाता है) रणनीति में किसी भी तरह की सैंडबॉक्सिंग नहीं होती है.
यह सिर्फ़ कार्रवाई की कमांड लाइन को एक्ज़ीक्यूट करता है. इसमें वर्किंग डायरेक्ट्री को आपके वर्कस्पेस के execroot पर सेट किया जाता है.
processwrapper-sandbox एक सैंडबॉक्सिंग रणनीति है. इसके लिए, किसी "ऐडवांस" सुविधा की ज़रूरत नहीं होती. यह किसी भी POSIX सिस्टम पर काम करती है. यह एक सैंडबॉक्स डायरेक्ट्री बनाता है. इसमें ऐसे सिमलंक होते हैं जो ओरिजनल सोर्स फ़ाइलों की ओर इशारा करते हैं. इसके बाद, यह execroot के बजाय इस डायरेक्ट्री पर सेट की गई वर्किंग डायरेक्ट्री के साथ, कार्रवाई की कमांड लाइन को एक्ज़ीक्यूट करता है. इसके बाद, यह सैंडबॉक्स से जाने-पहचाने आउटपुट आर्टफ़ैक्ट को execroot में ले जाता है और सैंडबॉक्स को मिटा देता है. इससे, कार्रवाई के दौरान ऐसी किसी भी इनपुट फ़ाइल का गलती से इस्तेमाल नहीं किया जा सकेगा जिसके बारे में बताया नहीं गया है. साथ ही, execroot में अनजान आउटपुट फ़ाइलें भी नहीं जोड़ी जा सकेंगी.
linux-sandbox, processwrapper-sandbox से एक कदम आगे है और इसे processwrapper-sandbox के आधार पर बनाया गया है. यह Docker की तरह ही काम करता है. यह होस्ट से कार्रवाई को अलग करने के लिए, Linux नेमस्पेस (उपयोगकर्ता, माउंट, पीआईडी, नेटवर्क, और आईपीसी नेमस्पेस) का इस्तेमाल करता है. इसका मतलब है कि यह सैंडबॉक्स डायरेक्ट्री को छोड़कर, पूरे फ़ाइल सिस्टम को सिर्फ़ पढ़ने के लिए उपलब्ध कराता है. इसलिए, इस कार्रवाई से होस्ट फ़ाइल सिस्टम में गलती से कोई बदलाव नहीं होता. इससे ऐसी स्थितियों से बचा जा सकता है जहां कोई गड़बड़ी वाला टेस्ट, गलती से आपकी $HOME डायरेक्ट्री को rm
-rf कर देता है. आपके पास कार्रवाई को नेटवर्क ऐक्सेस करने से रोकने का विकल्प भी होता है. linux-sandbox, PID नेमस्पेस का इस्तेमाल करता है, ताकि कार्रवाई किसी अन्य प्रोसेस को न देख सके. साथ ही, कार्रवाई के आखिर में सभी प्रोसेस (कार्रवाई से शुरू होने वाले डेमॉन भी) को भरोसेमंद तरीके से बंद किया जा सके.
darwin-sandbox भी इसी तरह का है, लेकिन यह macOS के लिए है. यह Apple के sandbox-exec टूल का इस्तेमाल करता है, ताकि Linux सैंडबॉक्स की तरह ही काम किया जा सके.
ऑपरेटिंग सिस्टम की ओर से उपलब्ध कराए गए तरीकों में मौजूद पाबंदियों की वजह से, "नेस्ट किए गए" परिदृश्य में linux-sandbox और darwin-sandbox, दोनों काम नहीं करते. Docker भी अपने कंटेनर के लिए Linux नेमस्पेस का इस्तेमाल करता है. इसलिए, linux-sandbox का इस्तेमाल किए बिना, Docker कंटेनर में linux-sandbox को आसानी से नहीं चलाया जा सकता.docker run --privileged macOS पर, sandbox-exec को ऐसी प्रोसेस में नहीं चलाया जा सकता जिसे पहले से ही सैंडबॉक्स किया जा रहा है. इसलिए, ऐसे मामलों में Bazel अपने-आप processwrapper-sandbox का इस्तेमाल करने लगता है.
अगर आपको बिल्ड से जुड़ी गड़बड़ी चाहिए, ताकि गलती से कम सख्त एक्ज़ीक्यूशन रणनीति का इस्तेमाल करके बिल्ड न किया जा सके, तो Bazel की ओर से इस्तेमाल की जाने वाली एक्ज़ीक्यूशन रणनीतियों की सूची में साफ़ तौर पर बदलाव करें. उदाहरण के लिए, bazel build
--spawn_strategy=worker,linux-sandbox.
डाइनैमिक एक्ज़ीक्यूशन के लिए, आम तौर पर लोकल एक्ज़ीक्यूशन के लिए सैंडबॉक्सिंग की ज़रूरत होती है. ऑप्ट आउट करने के लिए, --experimental_local_lockfree_output फ़्लैग पास करें. डाइनैमिक एक्ज़ीक्यूशन, पर्सिस्टेंट वर्कर को साइलेंट मोड में सैंडबॉक्स करता है.
सैंडबॉक्सिंग की कमियां
सैंडबॉक्सिंग के लिए, सेटअप और टीयरडाउन का अतिरिक्त शुल्क लगता है. यह लागत कितनी ज़्यादा है, यह कई बातों पर निर्भर करती है. जैसे, बिल्ड का आकार और होस्ट ओएस का परफ़ॉर्मेंस. Linux के लिए, सैंडबॉक्स किए गए बिल्ड, कुछ प्रतिशत से ज़्यादा धीमे नहीं होते.
--reuse_sandbox_directoriesसेट अप करने से, सेटअप और बंद करने की लागत कम हो सकती है.सैंडबॉक्स की प्रोसेस, टूल की किसी भी कैश मेमोरी को बंद कर देती है. पर्सिस्टेंट वर्कर का इस्तेमाल करके, इस समस्या को कम किया जा सकता है. हालांकि, इससे सैंडबॉक्स की सुरक्षा की गारंटी कम हो जाती है.
मल्टीप्लेक्स वर्कर को सैंडबॉक्स करने के लिए, वर्कर की सहायता की ज़रूरत होती है. मल्टीप्लेक्स सैंडबॉक्सिंग की सुविधा के साथ काम न करने वाले वर्कर, डाइनैमिक एक्ज़ीक्यूशन के तहत सिंगलप्लेक्स वर्कर के तौर पर काम करते हैं. इससे ज़्यादा मेमोरी खर्च हो सकती है.
sandboxfs
sandboxfs एक FUSE फ़ाइल सिस्टम है. यह समय के हिसाब से फ़ाइल सिस्टम को अपडेट किए बिना, उसके किसी भी व्यू को दिखाता है. Bazel, हर कार्रवाई के लिए तुरंत sandboxfs जनरेट करने के लिए sandboxfs का इस्तेमाल करता है. इससे हज़ारों सिस्टम कॉल जारी करने की लागत से बचा जा सकता है.execroot/ ध्यान दें कि FUSE ओवरहेड की वजह से, execroot/ में आगे की I/O प्रोसेस धीमी हो सकती है.
sandboxfs इंस्टॉल करना
sandboxfs इंस्टॉल करने और इसकी मदद से Bazel बिल्ड करने के लिए, यह तरीका अपनाएं:
डाउनलोड करें
डाउनलोड और इंस्टॉल करें
sandboxfs, ताकि sandboxfs बाइनरी आपके PATH में खत्म हो जाए.
sandboxfs रन करें
- (सिर्फ़ macOS के लिए) OSXFUSE इंस्टॉल करें.
(सिर्फ़ macOS के लिए) यह कमांड चलाएं:
sudo sysctl -w vfs.generic.osxfuse.tunables.allow_other=1आपको यह काम इंस्टॉलेशन के बाद और हर रीबूट के बाद करना होगा, ताकि यह पक्का किया जा सके कि macOS की मुख्य सिस्टम सेवाएं sandboxfs के ज़रिए काम करती हैं.
--experimental_use_sandboxfsकी मदद से Bazel बिल्ड चलाएं.bazel build target --experimental_use_sandboxfs
समस्या का हल
अगर आपको कार्रवाइयों के लिए एनोटेशन के तौर पर darwin-sandbox या linux-sandbox के बजाय local दिखता है, तो इसका मतलब यह हो सकता है कि सैंडबॉक्सिंग बंद है. इसे चालू करने के लिए, --genrule_strategy=sandboxed --spawn_strategy=sandboxed पास करें.
डीबग करना
सैंडबॉक्सिंग से जुड़ी समस्याओं को डीबग करने के लिए, यहां दी गई रणनीतियों का पालन करें.
बंद किए गए नेमस्पेस
कुछ प्लैटफ़ॉर्म पर, जैसे कि Google Kubernetes Engine क्लस्टर नोड या Debian पर, सुरक्षा से जुड़ी चिंताओं की वजह से उपयोगकर्ता नेमस्पेस डिफ़ॉल्ट रूप से बंद होते हैं. अगर /proc/sys/kernel/unprivileged_userns_clone फ़ाइल मौजूद है और इसमें 0 है, तो उपयोगकर्ता नेमस्पेस चालू करने के लिए, यह कमांड चलाएं:
sudo sysctl kernel.unprivileged_userns_clone=1नियम लागू न होने की वजहें
सिस्टम सेटअप की वजह से, सैंडबॉक्स में नियमों को लागू नहीं किया जा सकता. अगर आपको namespace-sandbox.c:633: execvp(argv[0], argv): No such file or
directory जैसा कोई मैसेज दिखता है, तो --strategy=Genrule=local की मदद से, सामान्य नियमों के लिए सैंडबॉक्स को बंद करने की कोशिश करें. साथ ही, अन्य नियमों के लिए --spawn_strategy=local का इस्तेमाल करें.
बिल्ड फ़ेल होने की वजहों को डीबग करने की सुविधा
अगर आपकी बिल्ड प्रोसेस पूरी नहीं हुई है, तो --verbose_failures और --sandbox_debug का इस्तेमाल करें. इससे Bazel, बिल्ड प्रोसेस पूरी न होने पर इस्तेमाल की गई कमांड दिखाएगा. इसमें सैंडबॉक्स सेट अप करने वाला हिस्सा भी शामिल होगा.
गड़बड़ी के मैसेज का उदाहरण:
ERROR: path/to/your/project/BUILD:1:1: compilation of rule
'//path/to/your/project:all' failed:
Sandboxed execution failed, which may be legitimate (such as a compiler error),
or due to missing dependencies. To enter the sandbox environment for easier
debugging, run the following command in parentheses. On command failure, a bash
shell running inside the sandbox will then automatically be spawned
namespace-sandbox failed: error executing command
(cd /some/path && \
exec env - \
LANG=en_US \
PATH=/some/path/bin:/bin:/usr/bin \
PYTHONPATH=/usr/local/some/path \
/some/path/namespace-sandbox @/sandbox/root/path/this-sandbox-name.params --
/some/path/to/your/some-compiler --some-params some-target)
अब जनरेट की गई सैंडबॉक्स डायरेक्ट्री की जांच की जा सकती है. साथ ही, यह देखा जा सकता है कि Bazel ने कौनसी फ़ाइलें बनाई हैं. इसके अलावा, कमांड को फिर से चलाकर यह देखा जा सकता है कि यह कैसे काम करती है.
ध्यान दें कि --sandbox_debug का इस्तेमाल करने पर, Bazel सैंडबॉक्स डायरेक्ट्री को नहीं मिटाता. अगर आपको डिबग नहीं करना है, तो आपको --sandbox_debug को बंद कर देना चाहिए. ऐसा इसलिए, क्योंकि समय के साथ यह आपकी डिस्क को भर देता है.