इस लेख में, Bazel में सैंडबॉक्सिंग और सैंडबॉक्सिंग एनवायरमेंट को डीबग करने के बारे में बताया गया है.
सैंडबॉक्सिंग, अनुमति को सीमित करने की एक रणनीति है. यह प्रोसेस को एक-दूसरे से या सिस्टम के संसाधनों से अलग करती है. 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 से एक कदम आगे बढ़कर काम करता है. यह Docker की तरह ही काम करता है. यह होस्ट से कार्रवाई को अलग करने के लिए, Linux नेमस्पेस (उपयोगकर्ता, माउंट, पीआईडी, नेटवर्क, और आईपीसी नेमस्पेस) का इस्तेमाल करता है. इसका मतलब है कि यह सैंडबॉक्स डायरेक्ट्री को छोड़कर, पूरे फ़ाइल सिस्टम को सिर्फ़ पढ़ने के लिए उपलब्ध कराता है. इसलिए, इस कार्रवाई से होस्ट फ़ाइल सिस्टम में गलती से कोई बदलाव नहीं होता. इससे ऐसी स्थितियों से बचा जा सकता है जहां गड़बड़ी वाला कोई टेस्ट, गलती से आपकी $HOME डायरेक्ट्री को rm
-rf कर देता है. आपके पास कार्रवाई को नेटवर्क ऐक्सेस करने से रोकने का विकल्प भी होता है. linux-sandbox, पीआईडी नेमस्पेस का इस्तेमाल करता है, ताकि कार्रवाई को कोई अन्य प्रोसेस न दिखे. साथ ही, कार्रवाई के आखिर में सभी प्रोसेस (कार्रवाई से शुरू होने वाले डेमॉन भी) को भरोसेमंद तरीके से बंद किया जा सके.
darwin-sandbox भी इसी तरह काम करता है, लेकिन यह macOS के लिए है. यह Apple के sandbox-exec टूल का इस्तेमाल करता है, ताकि Linux सैंडबॉक्स की तरह ही काम किया जा सके.
ऑपरेटिंग सिस्टम की ओर से उपलब्ध कराए गए तरीकों में मौजूद पाबंदियों की वजह से, "नेस्ट किए गए" परिदृश्य में linux-sandbox और darwin-sandbox, दोनों काम नहीं करते. Docker भी कंटेनर के लिए Linux नेमस्पेस का इस्तेमाल करता है. इसलिए, linux-sandbox को Docker कंटेनर में आसानी से नहीं चलाया जा सकता. हालांकि, 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सेट करने से, सेटअप और बंद करने की लागत कम हो सकती है.सैंडबॉक्स की प्रोसेस, टूल की किसी भी कैश मेमोरी को बंद कर देती है. पर्सिस्टेंट वर्कर का इस्तेमाल करके, इस समस्या को कम किया जा सकता है. हालांकि, इससे सैंडबॉक्स की सुरक्षा की गारंटी कम हो जाती है.
मल्टीप्लेक्स वर्कर को सैंडबॉक्स में रखने के लिए, वर्कर के लिए सहायता की ज़रूरत होती है. मल्टीप्लेक्स सैंडबॉक्सिंग की सुविधा के साथ काम न करने वाले वर्कर, डाइनैमिक एक्ज़ीक्यूशन के तहत सिंगलप्लेक्स वर्कर के तौर पर काम करते हैं. इससे ज़्यादा मेमोरी खर्च हो सकती है.
डीबग करना
सैंडबॉक्सिंग से जुड़ी समस्याओं को डीबग करने के लिए, यहां दी गई रणनीतियों का पालन करें.
बंद किए गए नेमस्पेस
कुछ प्लैटफ़ॉर्म, जैसे कि 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 की मदद से genrules के लिए और --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 ने कौनसी फ़ाइलें बनाई हैं. इसके अलावा, यह देखने के लिए कि Bazel कैसे काम करता है, कमांड को फिर से चलाया जा सकता है.
ध्यान दें कि --sandbox_debug का इस्तेमाल करने पर, Bazel सैंडबॉक्स डायरेक्ट्री को नहीं मिटाता. अगर आपको डिबग नहीं करना है, तो --sandbox_debug को बंद कर दें. ऐसा इसलिए, क्योंकि समय के साथ यह आपकी डिस्क को भर देता है.