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




shell docker (12)

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

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 एलटीएस के लिए डिफ़ॉल्ट आधार छवि को बंद कर रहा हूं)।


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

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"

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


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

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

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

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


मुझे डॉकरफ़ाइल में source चलाने में भी समस्याएं थीं

यह CentOS 6.6 डॉकर कंटेनर बनाने के लिए पूरी तरह से ठीक है, लेकिन डेबियन कंटेनर में समस्याएं दीं

RUN cd ansible && source ./hacking/env-setup

इस तरह मैंने इसका सामना किया, यह एक शानदार तरीका नहीं हो सकता है लेकिन यह मेरे लिए काम करता है

RUN echo "source /ansible/hacking/env-setup" >> /tmp/setup
RUN /bin/bash -C "/tmp/setup"
RUN rm -f /tmp/setup

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

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

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


मैंने अपनी 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

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


मूल उत्तर

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


इस पृष्ठ पर दिए गए उत्तरों पर बिल्डिंग मैं जोड़ूंगा कि आपको यह पता होना चाहिए कि प्रत्येक रन स्टेटमेंट दूसरों के /bin/sh -c स्वतंत्र रूप से /bin/sh -c साथ स्वतंत्र रूप से चलता है और इसलिए कोई भी पर्यावरण वार्स नहीं मिलेगा जो आमतौर पर लॉगिन शैल में सोर्स किया जाएगा।

अब तक का सबसे अच्छा तरीका है कि स्क्रिप्ट को /etc/bash.bashrc जोड़ना है और फिर प्रत्येक कमांड को बैश लॉगिन के रूप में आमंत्रित करना है।

RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc
RUN /bin/bash --login -c "your command"

उदाहरण के लिए आप Virtualenvwrapper को स्थापित और सेटअप कर सकते हैं, वर्चुअल एनवी बना सकते हैं, जब आप बैश लॉगिन का उपयोग करते हैं तो इसे सक्रिय करते हैं, और फिर अपने पाइथन मॉड्यूल को इस env में इंस्टॉल करें:

RUN pip install virtualenv virtualenvwrapper
RUN mkdir -p /opt/virtualenvs
ENV WORKON_HOME /opt/virtualenvs
RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc
RUN /bin/bash --login -c "mkvirtualenv myapp"
RUN echo "workon mpyapp" >> /etc/bash.bashrc
RUN /bin/bash --login -c "pip install ..."

बैश स्टार्टअप फ़ाइलों पर मैन्युअल को पढ़ने में मदद मिलती है कि कब सोर्स किया जाता है।


शेल कमांड की जांच करें। लिनक्स पर डिफ़ॉल्ट खोल है ["/ bin / sh", "-c"]

RUN "source file"      # translates to: RUN /bin/sh -c "source file"

आप SHELL का उपयोग करके डिफ़ॉल्ट खोल बदल सकते हैं जो डॉकरफ़ाइल में बाद के RUN निर्देशों के लिए उपयोग किए जाने वाले खोल को बदलता है

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

अब, डिफ़ॉल्ट खोल बदल गया है और आपको इसे हर रन निर्देश में स्पष्ट रूप से परिभाषित करने की आवश्यकता नहीं है

RUN "source file"    # now translates to: RUN /bin/bash -c "source file"

अतिरिक्त नोट : आप --login विकल्प भी जोड़ सकते हैं जो लॉगिन खोल शुरू करेगा। इसका मतलब है ~/.bachrc उदाहरण के लिए पढ़ा जाएगा और आपको अपने आदेश से पहले इसे स्पष्ट रूप से स्रोत करने की आवश्यकता नहीं है


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"]

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


यदि आप डॉकर 1.12 या नए का उपयोग कर रहे हैं, तो बस SHELL उपयोग करें!

संक्षिप्त जवाब:

सामान्य:

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

पायथन vituralenv के लिए:

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

लंबा जवाब:

https://docs.docker.com/engine/reference/builder/#/shell से

SHELL ["executable", "parameters"]

SHELL निर्देश कमांड को खोलने के लिए कमांड के खोल रूप के लिए उपयोग किए जाने वाले डिफ़ॉल्ट खोल को अनुमति देता है। लिनक्स पर डिफ़ॉल्ट खोल ["/ bin / sh", "-c"] है, और विंडोज़ पर ["cmd", "/ S", "/ c"] है। शेल निर्देश JSON रूप में एक डॉकरफ़ाइल में लिखा जाना चाहिए।

शेल निर्देश विशेष रूप से विंडोज़ पर उपयोगी होता है जहां दो आम तौर पर उपयोग किए जाते हैं और काफी अलग देशी गोले होते हैं: सीएमडी और पावरहेल, साथ ही साथ वैकल्पिक शैल भी उपलब्ध हैं।

शेल निर्देश कई बार प्रकट हो सकता है। प्रत्येक शेल निर्देश सभी पिछले SHELL निर्देशों को ओवरराइड करता है, और बाद के सभी निर्देशों को प्रभावित करता है। उदाहरण के लिए:

FROM microsoft/windowsservercore

# Executed as cmd /S /C echo default
RUN echo default

# Executed as cmd /S /C powershell -command Write-Host default
RUN powershell -command Write-Host default

# Executed as powershell -command Write-Host hello
SHELL ["powershell", "-command"]
RUN Write-Host hello

# Executed as cmd /S /C echo hello
SHELL ["cmd", "/S"", "/C"]
RUN echo hello

निम्नलिखित निर्देश SHELL निर्देश से प्रभावित हो सकते हैं जब उनमें से खोल का रूप डॉकरफ़ाइल: RUN, CMD और ENTRYPOINT में उपयोग किया जाता है।

निम्न उदाहरण विंडोज पर एक आम पैटर्न है जिसे SHELL निर्देश का उपयोग करके सुव्यवस्थित किया जा सकता है:

...
RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
...

डॉकर द्वारा बुलाया गया आदेश होगा:

cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"

यह दो कारणों से अक्षम है। सबसे पहले, एक अनिवार्य cmd.exe कमांड प्रोसेसर (उर्फ खोल) लगाया जा रहा है। दूसरा, खोल फ़ॉर्म में प्रत्येक रन निर्देश के लिए अतिरिक्त शक्ति-आवश्यकता होती है - कमांड को उपसर्ग करना।

इसे और अधिक कुशल बनाने के लिए, दो तंत्रों में से एक को नियोजित किया जा सकता है। एक रन कमांड के JSON रूप का उपयोग करना है जैसे कि:

...
RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\\foo.txt\""]
...

जबकि JSON प्रपत्र स्पष्ट है और un-required cmd.exe का उपयोग नहीं करता है, इसके लिए डबल-उद्धरण और भागने के माध्यम से अधिक क्रियाशक्ति की आवश्यकता होती है। वैकल्पिक तंत्र SHELL निर्देश और खोल फ़ॉर्म का उपयोग करना है, जो विंडोज उपयोगकर्ताओं के लिए एक अधिक प्राकृतिक वाक्यविन्यास बनाता है, खासकर जब बचने वाले पार्सर निर्देश के साथ संयुक्त होता है:

# escape=`

FROM microsoft/nanoserver
SHELL ["powershell","-command"]
RUN New-Item -ItemType Directory C:\Example
ADD Execute-MyCmdlet.ps1 c:\example\
RUN c:\example\Execute-MyCmdlet -sample 'hello world'

जिसके परिणामस्वरूप:

PS E:\docker\build\shell> docker build -t shell .
Sending build context to Docker daemon 4.096 kB
Step 1/5 : FROM microsoft/nanoserver
 ---> 22738ff49c6d
Step 2/5 : SHELL powershell -command
 ---> Running in 6fcdb6855ae2
 ---> 6331462d4300
Removing intermediate container 6fcdb6855ae2
Step 3/5 : RUN New-Item -ItemType Directory C:\Example
 ---> Running in d0eef8386e97


    Directory: C:\


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       10/28/2016  11:26 AM                Example


 ---> 3f2fbf1395d9
Removing intermediate container d0eef8386e97
Step 4/5 : ADD Execute-MyCmdlet.ps1 c:\example\
 ---> a955b2621c31
Removing intermediate container b825593d39fc
Step 5/5 : RUN c:\example\Execute-MyCmdlet 'hello world'
 ---> Running in be6d8e63fe75
hello world
 ---> 8e559e9bf424
Removing intermediate container be6d8e63fe75
Successfully built 8e559e9bf424
PS E:\docker\build\shell>

शेल निर्देश का उपयोग उस तरीके को संशोधित करने के लिए भी किया जा सकता है जिसमें एक खोल संचालित होता है। उदाहरण के लिए, विंडोज़ पर शेल सेमीड / एस / सी / वी: ऑन | ऑफएफ का उपयोग करके, देरी वाले पर्यावरण परिवर्तनीय विस्तार अर्थशास्त्र को संशोधित किया जा सकता है।

शेल निर्देश का उपयोग लिनक्स पर भी किया जा सकता है, वैकल्पिक शेल की आवश्यकता होनी चाहिए जैसे कि zsh, csh, tcsh और अन्य।

शेल सुविधा डॉकर 1.12 में जोड़ा गया था।





docker