bash - 'स्रोत' के साथ डॉकरफ़ाइल में रन निर्देश का उपयोग करना काम नहीं करता है




shell docker (10)

मेरे पास एक डॉकफाइल है जो मैं एक वेनिला पायथन पर्यावरण स्थापित करने के लिए एक साथ रख रहा हूं (जिसमें मैं एक ऐप इंस्टॉल करूँगा, लेकिन बाद की तारीख में)।

FROM ubuntu:12.04

# required to build certain python libraries
RUN apt-get install python-dev -y

# install pip - canonical installation instructions from pip-installer.org
# http://www.pip-installer.org/en/latest/installing.html
ADD https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py /tmp/ez_setup.py
ADD https://raw.github.com/pypa/pip/master/contrib/get-pip.py /tmp/get-pip.py
RUN python /tmp/ez_setup.py
RUN python /tmp/get-pip.py
RUN pip install --upgrade pip 

# install and configure virtualenv
RUN pip install virtualenv 
RUN pip install virtualenvwrapper
ENV WORKON_HOME ~/.virtualenvs
RUN mkdir -p $WORKON_HOME
RUN source /usr/local/bin/virtualenvwrapper.sh

बिल्ड अंतिम पंक्ति तक ठीक है, जहां मुझे निम्नलिखित अपवाद मिलता है:

[previous steps 1-9 removed for clarity]
...
Successfully installed virtualenvwrapper virtualenv-clone stevedore
Cleaning up...
 ---> 1fc253a8f860
Step 10 : ENV WORKON_HOME ~/.virtualenvs
 ---> Running in 8b0145d2c80d
 ---> 0f91a5d96013
Step 11 : RUN mkdir -p $WORKON_HOME
 ---> Running in 9d2552712ddf
 ---> 3a87364c7b45
Step 12 : RUN source /usr/local/bin/virtualenvwrapper.sh
 ---> Running in c13a187261ec
/bin/sh: 1: source: not found

अगर मैं उस निर्देशिका में हूं (केवल यह जांचने के लिए कि पिछले चरण किए गए थे) मैं देख सकता हूं कि फाइलें अपेक्षित हैं:

$ docker run 3a87 ls /usr/local/bin
easy_install
easy_install-2.7
pip
pip-2.7
virtualenv
virtualenv-2.7
virtualenv-clone
virtualenvwrapper.sh
virtualenvwrapper_lazy.sh

अगर मैं केवल source कमांड को चलाने का प्रयास करता हूं तो मुझे ऊपर जैसा ही 'नहीं मिला' त्रुटि मिलती है। यदि मैं एक इंटरैक्टिव शैल सत्र चलाता हूं, तो स्रोत काम करता है:

$ docker run 3a87 bash
source
bash: line 1: source: filename argument required
source: usage: source filename [arguments]

मैं यहां से स्क्रिप्ट चला सकता हूं, और फिर खुशी से mkvirtualenv , mkvirtualenv आदि तक पहुंच सकता mkvirtualenv

मैंने कुछ खुदाई की है, और शुरुआत में ऐसा लगता है कि समस्या उबंटू लॉगिन खोल के रूप में बाश के बीच के अंतर में झूठ बोल सकती है, और उबंटू सिस्टम शैल के रूप में डैश हो सकता है, डैश source कमांड का समर्थन नहीं कर रहा है।

हालांकि, इसका उत्तर '।' का उपयोग करना प्रतीत होता है source बजाय, लेकिन यह सिर्फ डॉकर रनटाइम को पैनिक अपवाद के साथ उड़ने का कारण बनता है।

डॉकरफाइल रन निर्देश से शेल स्क्रिप्ट चलाने के लिए सबसे अच्छा तरीका क्या है (इस बारे में उबंटू 12.04 एलटीएस के लिए डिफ़ॉल्ट आधार छवि को बंद कर रहा हूं)।


मूल उत्तर

FROM ubuntu:14.04
RUN rm /bin/sh && ln -s /bin/bash /bin/sh

यह हर उबंटू डॉकर बेस छवि के लिए काम करना चाहिए। मैं आम तौर पर लिखने वाले प्रत्येक डॉकरफाइल के लिए यह लाइन जोड़ता हूं।

एक संबंधित बाईस्टैंडर द्वारा संपादित करें

यदि आप कंटेनर के अंदर ओएस को बदलने और संभावित रूप से हानिकारक किए बिना, "पूरे डॉकरफाइल भर में sh बजाय bash उपयोग करें" का प्रभाव प्राप्त करना चाहते हैं, तो आप केवल डॉकर को अपना इरादा बता सकते हैं। ऐसा ऐसा किया जाता है:

SHELL ["/bin/bash", "-c"]

* संभावित नुकसान यह है कि लिनक्स में कई स्क्रिप्ट्स (ताजा उबंटू इंस्टॉल grep -rHInE '/bin/sh' / 2700 परिणामों से अधिक रिटर्न) एक पूरी तरह से POSIX खोल /bin/sh पर उम्मीद करते हैं। बैश खोल सिर्फ पॉज़िक्स प्लस अतिरिक्त बिल्टिन नहीं है। ऐसे बिल्टिन (और अधिक) हैं जो पॉज़िक्स में उनसे अलग व्यवहार करते हैं। मैं पूरी तरह से POSIX से बचने का समर्थन करता हूं (और यह कि किसी भी स्क्रिप्ट जिसे आपने किसी अन्य शेल पर परीक्षण नहीं किया है, काम करने जा रहा है क्योंकि आपको लगता है कि आप बेसमिज्म से परहेज करते हैं) और बस बैशिज्म का उपयोग करते हैं। लेकिन आप अपनी लिपि में उचित शेबांग के साथ ऐसा करते हैं। पूरे ओएस के नीचे से POSIX खोल खींचकर नहीं। (जब तक आपके पास लिनक्स के साथ आने वाली सभी 2700 प्लस स्क्रिप्ट्स को सत्यापित करने का समय न हो, तब तक आपके द्वारा इंस्टॉल किए गए किसी भी पैकेज में।)

नीचे इस जवाब में अधिक जानकारी। .com/a/45087082/117471


आप यह देखने के लिए bash -v चला सकते हैं कि क्या किया जा रहा है।

मैं symlinks के साथ खेलने के बजाय निम्नलिखित करना होगा:

RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc


ऐसा हो रहा है क्योंकि source फाइल सिस्टम पर कहीं भी बाइनरी के बजाए बैश करने के लिए अंतर्निहित है। क्या आप उस स्क्रिप्ट के लिए अपना इरादा रखते हैं जिसे आप कंटेनर को बाद में बदलने के लिए सोर्सिंग कर रहे हैं?


डॉकर दस्तावेज के अनुसार

'/ Bin / sh' के अलावा, एक अलग खोल का उपयोग करने के लिए, वांछित खोल में गुजरने वाले निष्पादन फॉर्म का उपयोग करें। उदाहरण के लिए,

RUN ["/bin/bash", "-c", "echo hello"]

docs.docker.com/engine/reference/builder/#run देखें


मुझे वही समस्या थी और वर्चुअलएन्व के अंदर पाइप इंस्टॉल निष्पादित करने के लिए मुझे इस कमांड का उपयोग करना पड़ा:

RUN pip install virtualenv virtualenvwrapper
RUN mkdir -p /opt/virtualenvs
ENV WORKON_HOME /opt/virtualenvs
RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh \
    && mkvirtualenv myapp \
    && workon myapp \
    && pip install -r /mycode/myapp/requirements.txt"

मुझे उम्मीद है यह मदद करेगा।


मैंने अपनी env सामग्री को .profile में डाल दिया और कुछ हद तक बदल दिया

SHELL ["/bin/bash", "-c", "-l"]

# Install ruby version specified in .ruby-version
RUN rvm install $(<.ruby-version)

# Install deps
RUN rvm use $(<.ruby-version) && gem install bundler && bundle install

CMD rvm use $(<.ruby-version) && ./myscript.rb

यदि आप वर्चुअलएन्व में कुछ स्थापित करने के लिए बस पीआईपी का उपयोग करने की कोशिश कर रहे हैं, तो आप पहले वर्चुअलएन्ग के बिन फ़ोल्डर को देखने के लिए पाथ एनवी को संशोधित कर सकते हैं

ENV PATH="/path/to/venv/bin:${PATH}"

फिर डॉकरफाइल में अनुसरण किए जाने वाले किसी भी pip install इंस्टॉलेशन कमांड को पहले / पथ / से / venv / bin / pip मिलेगा और इसका उपयोग करें, जो उस वर्चुअलएन्व में स्थापित होगा और सिस्टम पायथन नहीं होगा।


स्रोत के स्थान पर डॉट ऑपरेटर का उपयोग करने का सबसे आसान तरीका है, जो बैश source कमांड के बराबर है:

के बजाय:

RUN source /usr/local/bin/virtualenvwrapper.sh

उपयोग:

RUN . /usr/local/bin/virtualenvwrapper.sh

docs.docker.com/engine/reference/builder/#run के अनुसार डिफ़ॉल्ट के लिए डिफ़ॉल्ट [Linux] खोल /bin/sh -c । आप bashisms की अपेक्षा करते हैं, इसलिए आपको अपना खोल निर्दिष्ट करने के लिए RUN के "exec form" का उपयोग करना चाहिए।

RUN ["/bin/bash", "-c", "source /usr/local/bin/virtualenvwrapper.sh"]

अन्यथा, रन के "खोल फ़ॉर्म" का उपयोग करके और नेस्टेड गोले में एक अलग शैल परिणाम निर्दिष्ट करना।

# don't do this...
RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh"
# because it is the same as this...
RUN ["/bin/sh", "-c", "/bin/bash" "-c" "source /usr/local/bin/virtualenvwrapper.sh"]

यदि आपके पास 1 से अधिक कमांड हैं जिन्हें एक अलग खोल की आवश्यकता है, तो आपको https://docs.docker.com/engine/reference/builder/#shell पढ़ना चाहिए और अपने रन कमांड से पहले इसे रखकर अपना डिफ़ॉल्ट खोल बदलना चाहिए:

SHELL ["/bin/sh", "-c"]

नोट: मैंने जानबूझकर इस तथ्य को अनदेखा कर दिया है कि एक स्क्रिप्ट को एक रन में एकमात्र कमांड के रूप में स्रोत करना असंभव है।


RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh"





docker