सैंडबॉक्सिंग

इस लेख में, 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 से एक कदम आगे है और यह processwrapper-sandbox पर काम करती है. यह Docker की तरह ही, कार्रवाई को होस्ट से अलग करने के लिए, Linux नेमस्पेस (यूज़र, माउंट, पीआईडी, नेटवर्क, और आईपीसी नेमस्पेस) का इस्तेमाल करती है. इसका मतलब है कि यह सैंडबॉक्स डायरेक्ट्री को छोड़कर, पूरे फ़ाइल सिस्टम को रीड-ओनली बना देती है. इसलिए, कार्रवाई के दौरान, होस्ट फ़ाइल सिस्टम में कोई बदलाव नहीं किया जा सकता. इससे, ऐसी स्थितियां नहीं आतीं जिनमें गड़बड़ी वाला कोई टेस्ट, गलती से आपकी $HOME डायरेक्ट्री को rm -rf कर दे. आपके पास कार्रवाई को नेटवर्क ऐक्सेस करने से रोकने का विकल्प भी होता है. linux-sandbox , पीआईडी नेमस्पेस का इस्तेमाल करके, कार्रवाई को अन्य प्रोसेस देखने से रोकता है. साथ ही, यह सभी प्रोसेस (कार्रवाई से जनरेट हुए डेमॉन भी) को आखिर में बंद कर देता है.

darwin-sandbox भी इसी तरह काम करता है, लेकिन यह macOS के लिए है. यह Linux सैंडबॉक्स की तरह ही काम करने के लिए, Apple के sandbox-exec टूल का इस्तेमाल करता है.

ऑपरेटिंग सिस्टम की ओर से उपलब्ध कराए गए मैकेनिज़्म में मौजूद पाबंदियों की वजह से, linux-sandbox और darwin-sandbox, "नेस्टेड" सिनेरियो में काम नहीं करते. Docker भी अपने कंटेनर मैजिक के लिए Linux नेमस्पेस का इस्तेमाल करता है. इसलिए, docker run --privileged का इस्तेमाल किए बिना, linux-sandbox को Docker कंटेनर में आसानी से नहीं चलाया जा सकता. 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, तो genrules के लिए --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 को बंद कर दें, क्योंकि इससे समय के साथ आपकी डिस्क भर जाती है.