การใช้คำสั่ง RUN ใน Dockerfile ด้วย 'แหล่งที่มา' ไม่ทำงาน


274

ฉันมี Dockerfile ที่ฉันรวมตัวกันเพื่อติดตั้งสภาพแวดล้อมของ vanilla python (ซึ่งฉันจะทำการติดตั้งแอพ แต่ในภายหลัง)

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

บิลด์รัน ok จนกระทั่งบรรทัดสุดท้ายที่ฉันได้รับข้อยกเว้นต่อไปนี้:

[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

หากฉันlsเข้าสู่ไดเรกทอรีนั้น (เพียงเพื่อทดสอบว่าขั้นตอนก่อนหน้านี้มีความมุ่งมั่น) ฉันสามารถเห็นไฟล์ที่มีอยู่ตามที่คาดไว้:

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

ฉันสามารถเรียกใช้สคริปต์จากที่นี่แล้วมีความสุขการเข้าถึงworkon, mkvirtualenvฯลฯ

ฉันได้ทำบางขุดและต้นมันดูเหมือนว่าปัญหาอาจอยู่ในความแตกต่างระหว่างทุบตีเป็นอูบุนตูเปลือกเข้าสู่ระบบและประเป็น Ubuntu ระบบเชลล์ , รีบไม่สนับสนุนsourceคำสั่ง

อย่างไรก็ตามคำตอบสำหรับสิ่งนี้ดูเหมือนจะใช้'.' แทนที่จะเป็นsourceเช่นนั้น แต่นี่เป็นสาเหตุให้รันไทม์ของ Docker ระเบิดด้วยข้อยกเว้นที่น่าตกใจ

เป็นวิธีที่ดีที่สุดในการรันเชลล์สคริปต์จากคำสั่ง Dockerfile RUN เพื่อแก้ไขปัญหานี้ (กำลังเรียกใช้อิมเมจพื้นฐานเริ่มต้นสำหรับ Ubuntu 12.04 LTS)


2
ดังนั้นอย่า 'แหล่งที่มา' เพียงแค่เรียกใช้คำสั่ง หรือเรียกใช้เชลล์สคริปต์โดยเฉพาะด้วย 'bash'
Alister Bulman

พยายามว่า - แม้ว่าสคริปต์จะไม่ล้มเหลว แต่ฉันก็ไม่สามารถเข้าถึงคำสั่งต่าง ๆ ซึ่งฉันต้องการได้ ปัญหานี้เป็นสิ่งเดียวกัน - github.com/dotcloud/docker/issues/2847
Hugo Rodger-Brown

2
ซึ่งคิดเกี่ยวกับมันถูกต้อง Virtualenvwrapper อาจไม่เหมาะสมในสภาพแวดล้อมของคอนเทนเนอร์ ฉันจะสำรองข้อมูลและใช้ virtualenv 'ดั้งเดิม' แทน
Hugo Rodger-Brown

1
วิธีพื้นฐานเพิ่มเติมในการเข้าถึงคือstackoverflow.com/questions/4732200/…
Gaurav Ojha

ลองCMD source activate django-py35
Belter

คำตอบ:


315

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


67
ใช่มั้ย? หากคุณแหล่งสคริปต์ภายในเชลล์ที่มีอยู่สำหรับคำสั่งเท่านั้นจะไม่สามารถมีผลกระทบยาวนานกับคำสั่งในอนาคตใด ๆ ที่เรียกใช้โดยสมมติว่าผลรวมของการกระทำคือการตั้งค่าตัวแปรสภาพแวดล้อม แล้วทำไมคุณถึงใช้sourceเลยbash /usr/local/bin/virtualenvwrapper.shในกรณีนั้น?
Charles Duffy

13
RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh; my_command; my_command; my_command;"
Leo

29
สิ่งนี้ไม่ถูกต้องแม้ว่าจะใช้งานได้ อ่านdocs.docker.com/engine/reference/builder/#runและอย่าหยุดหลังจากตัวอย่างโค้ดที่สอง อ่านหมายเหตุ:ที่ตามมาทันที เพราะ/bin/sh -cเป็นเปลือกเริ่มต้นนี้ฟอร์ม "เปลือก" ของ RUN RUN ["/bin/sh", "-c", "/bin/bash" "-c" "source /usr/local/bin/virtualenvwrapper.sh"]แปลว่า คุณควรจะไปข้างหน้าและใช้ "รูปแบบ exec" ของการทำงานเพื่อให้คุณสามารถใช้เวลาshออกเช่นดังนั้นRUN ["/bin/bash" "-c" "source /usr/local/bin/virtualenvwrapper.sh"]
บรูโน่ Bronosky

8
โปรดดูstackoverflow.com/a/45087082/117471เพื่อทำความเข้าใจว่าทำไมสิ่งนี้จึงสร้างbashซ้อนในshและควรหลีกเลี่ยง
Bruno Bronosky

4
คำตอบที่ดีกว่าอยู่ที่นี่: stackoverflow.com/a/42216046/1663462
Chris Stryczynski

150

คำตอบเดิม

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

สิ่งนี้ควรใช้ได้กับอิมเมจพื้นฐานของ Docker ทุกตัว โดยทั่วไปฉันจะเพิ่มบรรทัดนี้สำหรับทุก Dockerfile ที่ฉันเขียน

แก้ไขโดยผู้ดูที่เกี่ยวข้อง

หากคุณต้องการได้รับผลกระทบของ "การใช้งานbashแทนการใช้shตลอดทั้ง Dockerfile" โดยไม่ต้องเปลี่ยนแปลงและอาจทำให้ระบบปฏิบัติการ * เสียหายภายในคอนเทนเนอร์คุณสามารถบอกความตั้งใจของ Dockerได้ ที่ทำเช่นนั้น:

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

* ความเสียหายที่เป็นไปได้คือหลายสคริปต์ในลินุกซ์ (สดใหม่ Ubuntu ติดตั้งgrep -rHInE '/bin/sh' /ผลตอบแทนที่มากกว่า 2700 ผลการค้นหา) คาดว่าจะมีอย่างเต็มที่ POSIX /bin/shเปลือกที่ bash shell ไม่ได้เป็นเพียง POSIX บวกกับบิวด์อินเพิ่มเติม มี buildins (และอื่น ๆ ) ที่ทำงานแตกต่างไปจาก POSIX อย่างสิ้นเชิง ฉันสนับสนุนการหลีกเลี่ยง POSIX อย่างเต็มที่ (และการเข้าใจผิดว่าสคริปต์ใด ๆ ที่คุณไม่ได้ทดสอบบนเชลล์อื่นจะทำงานได้เพราะคุณคิดว่าคุณหลีกเลี่ยง basmisms) และเพียงแค่ใช้วิธีการ bashism แต่คุณทำอย่างนั้นกับ shebang ที่เหมาะสมในสคริปต์ของคุณ ไม่ใช่โดยการดึง POSIX shell ออกจากใต้ OS ทั้งหมด (เว้นแต่คุณจะมีเวลาในการตรวจสอบสคริปต์ทั้งหมด 2700 บวกสคริปต์ที่มาพร้อมกับ Linux และสคริปต์ทั้งหมดในแพ็คเกจที่คุณติดตั้ง)

รายละเอียดเพิ่มเติมในคำตอบนี้ด้านล่าง https://stackoverflow.com/a/45087082/117471


18
สามารถลดความซับซ้อนลงได้เล็กน้อย:ln -snf /bin/bash /bin/sh
apottere

2
@ user1442219 สิ่งนี้แทนที่ตัวแปลคำสั่งเริ่มต้นจากshถึงbash
Bhargav Nanekalva

27
ln -s /bin/bash /bin/shนี่เป็นความคิดที่แย่มาก ubuntu เป้าหมาย / bin / sh เพื่อประด้วยเหตุผล รีบเป็นเปลือก posix อย่างเต็มที่ซึ่งเป็นคำสั่งของขนาดเร็วกว่าทุบตี การลิงก์ / bin / sh เพื่อ bash จะลดประสิทธิภาพเซิร์ฟเวอร์ของคุณลงอย่างมาก อ้างถึง: wiki.ubuntu.com/DashAsBinSh
xero

7
นี่เป็นแฮ็คที่สกปรกไม่ใช่วิธีแก้ปัญหา ถ้าสคริปต์ของคุณจะถูกเรียกใช้โดยshเปลือก แต่คุณต้องการbashการแก้ปัญหาที่เหมาะสมเป็นอย่างใดอย่างหนึ่งที่จะมีshวิงวอนกระบวนการbashเป็น one-off เช่นbash -c 'source /script.sh && …', หรือคุณยังสามารถไปไกลที่สุดเท่าที่จะ bashisms หลีกเลี่ยง (ชอบsource) ทั้งหมดและแทน เลือกที่จะเท่านั้นที่เคยใช้เทียบเท่า POSIX . /script.shที่ถูกต้องเช่น ( .ระวังพื้นที่หลัง!) สุดท้ายถ้าสคริปต์ของคุณสามารถใช้งานได้ (ไม่ใช่แค่แหล่งข้อมูลเท่านั้น) อย่าทำให้สคริปต์ของคุณโกหกด้วย#!/bin/shshebang ถ้ามันไม่เข้ากันได้กับ sh ใช้#!/bin/bashแทน
Mark G.

7
และตอนนี้ฉันจะลงคะแนนคำตอบเดิมและแก้ไขโดย 'a กังวล' ได้อย่างไร
Slava

65

เปลือกเริ่มต้นสำหรับการเรียนการสอนคือRUN["/bin/sh", "-c"]

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

การใช้คำสั่ง SHELLคุณสามารถเปลี่ยนเชลล์เริ่มต้นสำหรับRUNคำแนะนำต่อไปใน Dockerfile:

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

ตอนนี้เชลล์เริ่มต้นมีการเปลี่ยนแปลงและคุณไม่จำเป็นต้องกำหนดอย่างชัดเจนในทุกคำสั่ง RUN

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

หมายเหตุเพิ่มเติม : คุณสามารถเพิ่ม--loginตัวเลือกที่จะเริ่มต้นเข้าสู่ระบบเชลล์ ~/.bachrcตัวอย่างนี้หมายความว่าจะถูกอ่านและคุณไม่จำเป็นต้องระบุแหล่งที่มาอย่างชัดเจนก่อนคำสั่งของคุณ


1
ตัวชี้ที่ยอดเยี่ยมสำหรับการใช้งาน--login- เพียงแค่คิดออกเอง
mattexx

1
ด้วยการใช้SHELL ["/bin/bash", "-c", "-l"] ฉันสามารถใช้การอัปเดตเพิ่มเติมในไฟล์. bashrc ซึ่งทำให้ฉันสามารถเรียกใช้คำสั่ง asdf ได้อย่างง่ายดาย
Rowinson Gallego

46

ฉันมีปัญหาเดียวกันและเพื่อดำเนินการติดตั้ง pip ภายใน virtualenv ฉันต้องใช้คำสั่งนี้:

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"

ฉันหวังว่ามันจะช่วย


ในกรณีที่คุณมาจากคำตอบ ROS ใช่ที่ได้ผล สิ่งที่ต้องการ:RUN /bin/bash -c "source /opt/ros/melodic/setup.bash && \ cd /home && \ git clone https://angelos.p:$password@gitlab.com/inno/grpc-comms.git && \ cd grpc-comms && \ mkdir build && \ cd build && \ cmake .. && make"
angelos.p

44

วิธีที่ง่ายที่สุดคือการใช้ตัวดำเนินการ dot แทนแหล่งกำเนิดซึ่งเทียบเท่ากับsourceคำสั่งshash :

แทน:

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

ใช้:

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

"source คือเชลล์ bourne builtin และPOSIX` builtin" พิเศษ "- ss64.com/bash/source.html linux.die.net/man/1/sh ... . / sourceยังยอมรับพารามิเตอร์ตำแหน่งหลังจากชื่อไฟล์
Wes ช่างกลึง

5
สิ่งนี้ไม่ทำงานเนื่องจากคำสั่ง RUN แต่ละคำสั่งทำงานอย่างอิสระ การเปลี่ยนแปลงจากsourceหรือ.หายไปเมื่อคำสั่ง RUN เสร็จสิ้น ดู: stackoverflow.com/a/40045930/19501
Amit

26

หากคุณกำลังใช้ Docker 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 อนุญาตให้เชลล์เริ่มต้นที่ใช้สำหรับเชลล์คำสั่งในรูปแบบถูกเขียนทับ เชลล์เริ่มต้นบน Linux คือ ["/ bin / sh", "-c"] และบน Windows คือ ["cmd", "/ S", "/ C"] คำสั่ง SHELL จะต้องเขียนในรูปแบบ JSON ใน Dockerfile

คำสั่ง SHELL นั้นมีประโยชน์อย่างยิ่งใน Windows ที่มีสองเชลล์ที่ใช้กันทั่วไปและเชลล์เนทีฟที่ต่างกัน: cmd และ powershell รวมถึงเชลล์สำรองที่มีให้เลือกรวมถึง sh

คำสั่ง SHELL สามารถปรากฏได้หลายครั้ง คำสั่ง SHELL แต่ละรายการจะแทนที่คำสั่ง 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 เมื่อใช้รูปแบบเชลล์ในคำสั่ง Dockerfile: RUN, CMD และ ENTRYPOINT

ตัวอย่างต่อไปนี้เป็นรูปแบบทั่วไปที่พบใน Windows ซึ่งสามารถปรับปรุงได้โดยใช้คำสั่ง SHELL:

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

คำสั่งที่เรียกใช้โดยนักเทียบท่าจะเป็น:

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

สิ่งนี้ไม่มีประสิทธิภาพด้วยเหตุผลสองประการ อันดับแรกมีตัวประมวลผลคำสั่ง cmd.exe ที่ไม่จำเป็น (เชลล์อาคา) กำลังถูกเรียกใช้ ประการที่สองคำสั่ง RUN แต่ละคำในรูปแบบเชลล์ต้องใช้ powershell พิเศษ - คำสั่งและคำนำหน้าคำสั่ง

เพื่อให้มีประสิทธิภาพมากขึ้นสามารถใช้หนึ่งในสองกลไก หนึ่งคือการใช้รูปแบบ JSON ของคำสั่ง RUN เช่น:

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

แม้ว่ารูปแบบ JSON นั้นจะไม่คลุมเครือและไม่ได้ใช้ cmd.exe ที่ไม่จำเป็น แต่ก็จำเป็นต้องใช้คำพูดที่ละเอียดมากขึ้นผ่านการโควต้าสองครั้งและหลบหนี กลไกทางเลือกคือการใช้คำสั่ง SHELL และรูปแบบเชลล์ทำให้มีไวยากรณ์ที่เป็นธรรมชาติมากขึ้นสำหรับผู้ใช้ Windows โดยเฉพาะอย่างยิ่งเมื่อรวมกับคำสั่ง escape parser:

# 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>

คำสั่ง SHELL สามารถใช้เพื่อปรับเปลี่ยนวิธีการทำงานของเชลล์ ตัวอย่างเช่นการใช้ SHELL cmd / S / C / V: เปิด | ปิดบน Windows ความหมายของตัวแปรสภาวะแวดล้อมที่ล่าช้าอาจถูกปรับเปลี่ยน

คำสั่ง SHELL สามารถใช้กับ Linux ได้หากต้องการเชลล์สำรองเช่น zsh, csh, tcsh และอื่น ๆ

เพิ่มคุณสมบัติ SHELL ใน Docker 1.12


20

การสร้างคำตอบในหน้านี้ฉันจะเพิ่มว่าคุณต้องระวังว่าคำสั่ง RUN แต่ละคำสั่งจะทำงานโดยอิสระจากคำสั่งอื่น ๆ ด้วย/bin/sh -cเหตุนี้จึงไม่ได้รับ vars ของสภาพแวดล้อมใด ๆ

วิธีที่ดีที่สุดที่ฉันได้พบคือการเพิ่มสคริปต์/etc/bash.bashrcและจากนั้นเรียกแต่ละคำสั่งเป็นการเข้าสู่ระบบทุบตี

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

คุณสามารถติดตั้งและตั้งค่า virtualenvwrapper เช่นสร้าง env เสมือนเปิดใช้งานเมื่อคุณใช้ bash เข้าสู่ระบบแล้วติดตั้งโมดูลหลามของคุณลงใน 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 ..."

การอ่านคู่มือเกี่ยวกับไฟล์ bash startupจะช่วยให้เข้าใจว่ามีแหล่งข้อมูลใด


1
เย็นขึ้นอยู่กับวิธีการแก้ปัญหาของคุณสิ่งที่ฉันได้เพียงเพื่อแสดงให้เห็นถึงถูก: ADD env-file /etc/profile.d/installerenv.sh RUN /bin/bash --login -c 'env' RUN /bin/bash -c 'rm /etc/profile.d/installerenv.sh' ถ้ากรณีการใช้งานของคนเพิ่มมากขึ้นของตัวแปรสภาพแวดล้อมฉีดเพื่อสร้างมุมมองนักเทียบท่าเช่นเหมืองไม่ผมอยากแนะนำให้มีลักษณะที่docs.docker.com/compose/yml / # env-fileเช่นกัน
daniel.kahlenberg

1
ฉันเชื่อว่าปัญหาของปัญหานี้คือคุณไม่ได้แคชผลลัพธ์ของแต่ละRUNคำสั่งซึ่งหมายความว่าคุณไม่สามารถติดตั้งการพึ่งพาโครงการทั้งหมดจำนวนมากแล้วคัดลอกรหัสต้นฉบับและใช้ประโยชน์จาก การแคชขั้นตอนระดับกลางของ Docker มันจะติดตั้งการอ้างอิงโครงการทั้งหมดทุกครั้ง
erewok

ใช้/etc/bashrcสำหรับ Redhat แทนที่จะ/etc/bash.bashrcเป็นที่กล่าวถึงข้างต้น (สำหรับ Ubuntu)
Jordan Gee

ฉันใช้ /root/.bashrc สำหรับ centos
schmudu

RUN echo "source /yourscript.bash" >> /etc/bash.bashrc ทำการหลอกลวง หากคุณใช้ ros inside docker และต้องการตั้งค่าสภาพแวดล้อมนี่คือสิ่งที่คุณควรทำ
user27221

17

ตามhttps://docs.docker.com/engine/reference/builder/#runเริ่มต้น [Linux] เปลือกมีRUN /bin/sh -cคุณดูเหมือนจะคาดหวังว่า bashisms ดังนั้นคุณควรใช้ "exec form" ของRUNเพื่อระบุเชลล์ของคุณ

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

มิฉะนั้นการใช้ "รูปแบบเปลือก" ของ RUN และการระบุเปลือกผลที่แตกต่างกันในเปลือกที่ซ้อนกัน

# 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และเปลี่ยนเชลล์เริ่มต้นของคุณโดยการวางไว้ข้างหน้าคำสั่ง RUN ของคุณ:

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

สุดท้ายหากคุณใส่อะไรลงใน.bashrcไฟล์ของผู้ใช้รูทที่คุณต้องการคุณสามารถเพิ่มการ-lตั้งค่าสถานะSHELLหรือRUNคำสั่งเพื่อให้มันเป็นเปลือกเข้าสู่ระบบและให้แน่ใจว่ามันได้รับมา

หมายเหตุ: ฉันเพิกเฉยต่อความจริงที่ว่ามันไม่มีประโยชน์ที่จะเขียนสคริปต์เป็นคำสั่งเดียวใน RUN


1
SHELL ["/bin/sh", "-c", "-l"]ดังนั้นจึงเป็นแหล่งที่มา ~ / .bashrc ฯลฯ ในกรณีที่คุณมีการตั้งค่าสภาพแวดล้อมจากฐานภาชนะ
MortenB

1
@MortenB แต่คุณระบุ (พิมพ์ผิด) /bin/shซึ่งจะไม่แก้ปัญหาการทุบตีไม่ได้ใช้งาน นอกจากนี้เมื่อทำเช่นdocker buildนั้นไม่น่าเป็นไปได้ที่จะมีสิ่งใดที่มีประโยชน์ใน. bashrc ของผู้ใช้รูทที่คุณต้องการ แต่ถ้าคุณใส่บางอย่างในนั้นก่อนหน้านี้ใน Dockerfile (เช่นอาจจะJAVA_HOMEใช่แล้วฉันจะใส่บันทึกไว้ในคำตอบของฉัน
Bruno Bronosky

ขออภัยสำหรับการพิมพ์ผิดฉันใช้ pyenv ซึ่งต้องใช้แหล่ง ~ / .bashrc เพื่อตั้งค่าพา ธ สำหรับเวอร์ชั่นไพ ธ อนที่ถูกต้องในภาพฐานของฉัน นี่ทำให้ฉันใช้ฐานลินุกซ์อะไรก็ตามที่มีและมีสองบรรทัดเพิ่มเวอร์ชันใด ๆ บน python เช่น python 3.7 บน ubuntu16.04 โดยที่ python พื้นฐานคือ 3.5.2
MortenB

11

ตามเอกสารของนักเทียบท่า

หากต้องการใช้เชลล์อื่นนอกเหนือจาก '/ bin / sh' ให้ใช้แบบฟอร์ม exec ที่ส่งผ่านในเชลล์ที่ต้องการ ตัวอย่างเช่น,

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

ดูhttps://docs.docker.com/engine/reference/builder/#run


นี่คือคำตอบที่ถูกต้องจริง ผู้เขียนคำตอบที่เลือกไว้stackoverflow.com/a/25086628/117471ดูเหมือนว่าจะได้อ่านเพียงตัวอย่างแรกในเอกสารที่คุณเชื่อมโยง พวกเขาดูเหมือนจะไม่ได้อ่านย่อหน้าถัดไปซึ่งเป็นสิ่งที่คุณยกมา
Bruno Bronosky

4

หากคุณมีSHELLให้ใช้งานคุณควรตอบด้วยคำตอบนี้ - อย่าใช้คำสั่งที่ยอมรับซึ่งบังคับให้คุณวางส่วนที่เหลือของ dockerfile ไว้ในคำสั่งเดียวต่อความคิดเห็นนี้

หากคุณใช้รุ่น Docker รุ่นเก่าและไม่สามารถเข้าถึงได้SHELLสิ่งนี้จะใช้ได้ตราบใดที่คุณไม่ต้องการอะไรจาก.bashrc(ซึ่งเป็นกรณีที่ไม่ค่อยพบใน Dockerfiles):

ENTRYPOINT ["bash", "--rcfile", "/usr/local/bin/virtualenvwrapper.sh", "-ci"]

หมายเหตุ-iจำเป็นต้องทำการทุบตีอ่านไฟล์ rc เลย


3

คุณอาจต้องการเรียกใช้bash -vเพื่อดูว่ามีแหล่งที่มา

ฉันจะทำสิ่งต่อไปนี้แทนที่จะเล่นกับ symlinks:

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


3

ฉันยังมีปัญหาในการทำงานsourceใน Dockerfile

สิ่งนี้ทำงานได้อย่างสมบูรณ์แบบสำหรับการสร้าง CentOS 6.6 Docker container แต่ให้ปัญหาในคอนเทนเนอร์ Debian

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

2

สิ่งนี้อาจเกิดขึ้นเพราะsourceมีการทุบตีในตัวแทนที่จะเป็นเลขฐานสองในระบบไฟล์ ความตั้งใจของคุณที่มีต่อสคริปต์ที่คุณจัดหาเพื่อเปลี่ยนคอนเทนเนอร์เป็นอย่างไร?


1
สคริปต์อัปเดตคอนเทนเนอร์ - แต่จริงๆแล้วฉันพยายามทำสิ่งที่ไม่สมเหตุสมผลดังนั้นจึงได้ข้ามปัญหาไป
Hugo Rodger-Brown

1

ฉันลงเอยด้วยการใส่สิ่งของ env .profileและกลายพันธุ์SHELLบางอย่างเช่น

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

3
"-c" จำเป็นที่จะต้องโต้แย้งสุดท้าย (ก่อนที่จะดำเนินการ command.to)
peterk

0

หากคุณเพียงแค่พยายามใช้ pip เพื่อติดตั้งบางอย่างใน virtualenv คุณสามารถแก้ไข PATH env เพื่อค้นหาในโฟลเดอร์ bin ของ virtualenv ก่อน

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

จากนั้นpip installคำสั่งใด ๆที่ตามมาใน Dockerfile จะค้นหา / path / to / venv / bin / pip ก่อนและใช้คำสั่งนั้นซึ่งจะติดตั้งลงใน virtualenv นั้นและไม่ใช่ Python ของระบบ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.