Mam plik Docker, który przygotowuję, aby zainstalować waniliowe środowisko python (w którym będę instalować aplikację, ale w późniejszym terminie).
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
Kompilacja działa poprawnie do ostatniej linii, gdzie otrzymuję następujący wyjątek:
[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
Jeśli przejdę ls
do tego katalogu (tylko w celu sprawdzenia, czy poprzednie kroki zostały popełnione), widzę, że pliki istnieją zgodnie z oczekiwaniami:
$ 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
Jeśli spróbuję po prostu uruchomić source
polecenie, pojawia się ten sam błąd „nie znaleziono” jak powyżej. Jeśli jednak uruchomię interaktywną sesję powłoki, źródło działa:
$ docker run 3a87 bash
source
bash: line 1: source: filename argument required
source: usage: source filename [arguments]
Mogę uruchomić skrypt stąd, a następnie szczęśliwie dostępu workon
, mkvirtualenv
itd.
Zrobiłem trochę kopania i początkowo wydawało się, że problem może polegać na różnicy między bash jako powłoką logowania Ubuntu , a dash jako powłoką systemu Ubuntu , dash nie obsługuje source
polecenia.
Jednak wydaje się, że odpowiedzią na to jest użycie „”. zamiast source
, ale to tylko powoduje, że środowisko wykonawcze Dockera wysadza się w powietrze z wyjątkiem paniki typu go.
Jaki jest najlepszy sposób na uruchomienie skryptu powłoki z instrukcji RUN Dockerfile, aby obejść ten problem (uruchamiam domyślny obraz podstawowy dla Ubuntu 12.04 LTS).
CMD source activate django-py35
Odpowiedzi:
RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh"
źródło
source
w ogóle używałbyś , a nie tylkobash /usr/local/bin/virtualenvwrapper.sh
, w takim przypadku?RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh; my_command; my_command; my_command;"
/bin/sh -c
jest to domyślna powłoka, ta „forma powłoki” RUN tłumaczyRUN ["/bin/sh", "-c", "/bin/bash" "-c" "source /usr/local/bin/virtualenvwrapper.sh"]
. Powinieneś iść dalej i użyć „formularzash
RUN ["/bin/bash" "-c" "source /usr/local/bin/virtualenvwrapper.sh"]
bash
zagnieżdżenie wsh
i dlatego należy tego unikać.Oryginalna odpowiedź
Powinno to działać dla każdego podstawowego obrazu dokera Ubuntu. Zazwyczaj dodam ten wiersz do każdego pliku Dockerfile, który piszę.
Edytuj przez zainteresowanego obserwatora
Jeśli chcesz uzyskać efekt „używania
bash
zamiast przezsh
cały ten plik Docker”, bez zmiany i prawdopodobnie uszkodzenia * systemu operacyjnego w kontenerze, możesz po prostu powiedzieć Dockerowi o swoim zamiarze . Odbywa się to w następujący sposób:Więcej szczegółów w tej odpowiedzi poniżej. https://stackoverflow.com/a/45087082/117471
źródło
ln -snf /bin/bash /bin/sh
sh
dobash
ln -s /bin/bash /bin/sh
to okropny pomysł. ubuntu target / bin / sh do dash z jakiegoś powodu. dash jest całkowicie posixową powłoką, która jest o rząd wielkości szybsza niż bash. linkowanie / bin / sh do bash drastycznie obniży wydajność twojego serwera. przytoczyć: wiki.ubuntu.com/DashAsBinShsh
skorupkach, ale chceszbash
, prawidłowe rozwiązanie jest albo miećsh
Invoke procesubash
jako jednorazowy, npbash -c 'source /script.sh && …'
, lub można nawet iść tak daleko, aby bashisms uniknąć (jaksource
) w całości, a zamiast zdecyduj się na używanie tylko prawidłowych odpowiedników POSIX, np. /script.sh
. (Przestrzegaj miejsca po.
!) Na koniec, jeśli skrypt jest wykonywalny (nie tylko źródłowy), nigdy nie zmuszaj skryptu do#!/bin/sh
shebang, jeśli w rzeczywistości nie jest zgodny z sh. Użyj#!/bin/bash
zamiast tego.Domyślną powłoką
RUN
instrukcji jest["/bin/sh", "-c"]
.Korzystając z instrukcji SHELL , możesz zmienić domyślną powłokę dla kolejnych
RUN
instrukcji w Dockerfile:Teraz domyślna powłoka uległa zmianie i nie trzeba jej jawnie definiować w każdej instrukcji RUN
Dodatkowa uwaga : Możesz również dodać
--login
opcję, która uruchomi powłokę logowania. Oznacza to~/.bachrc
na przykład, że zostanie przeczytany i nie musisz go jawnie pozyskiwać przed wydaniem poleceniaźródło
--login
- właśnie sam toSHELL ["/bin/bash", "-c", "-l"]
mogłem korzystać z dalszych aktualizacji pliku .bashrc, co pozwoliło mi na łatwe uruchamianie poleceń asdf.Miałem ten sam problem i aby wykonać instalację pip w virtualenv musiałem użyć tego polecenia:
Mam nadzieję, że to pomoże.
źródło
RUN /bin/bash -c "source /opt/ros/melodic/setup.bash && \ cd /home && \ git clone https://angelos.p:[email protected]/inno/grpc-comms.git && \ cd grpc-comms && \ mkdir build && \ cd build && \ cmake .. && make"
Najprostszym sposobem jest użycie operatora kropki zamiast źródła, który jest odpowiednikiem sh
source
polecenia bash :Zamiast:
Posługiwać się:
źródło
.
/source
akceptuje również parametry pozycyjne po nazwie plikusource
lub.
są tracone po zakończeniu polecenia RUN. Zobacz: stackoverflow.com/a/40045930/19501Jeśli używasz Dockera 1.12 lub nowszego, po prostu użyj
SHELL
!Krótka odpowiedź:
generał:
dla python vituralenv:
Długa odpowiedź:
z https://docs.docker.com/engine/reference/builder/#/shell
źródło
Opierając się na odpowiedziach na tej stronie, dodam, że musisz pamiętać, że każda instrukcja RUN działa niezależnie od innych
/bin/sh -c
i dlatego nie otrzyma żadnych zmiennych środowiskowych, które normalnie byłyby pozyskiwane w powłokach logowania.Najlepszym sposobem, jaki do tej pory znalazłem, jest dodanie skryptu,
/etc/bash.bashrc
a następnie wywołanie każdego polecenia jako logowania bash.Możesz na przykład zainstalować i skonfigurować virtualenvwrapper, utworzyć wirtualną env, aktywować ją podczas korzystania z logowania bash, a następnie zainstalować moduły python w tej env:
Czytanie instrukcji na temat plików startowych bash pomaga zrozumieć, co jest pozyskiwane.
źródło
ADD env-file /etc/profile.d/installerenv.sh
RUN /bin/bash --login -c 'env'
RUN /bin/bash -c 'rm /etc/profile.d/installerenv.sh'
Jeśli czyjś przypadek użycia dodaje więcej zmiennych środowiskowych wstrzykiwania do perspektywy budowania okna dokowanego, tak jak moje, polecam zajrzeć na docs.docker.com/compose/yml / # plik env też.RUN
polecenia, co oznacza, że nie możesz zainstalować wielu zależności projektu, a następnie skopiować kod źródłowy i skorzystać z zalet Buforowanie pośredniego kroku Dockera. Za każdym razem będzie ponownie instalować wszystkie zależności projektu./etc/bashrc
dla Redhat, zamiast/etc/bash.bashrc
jak wspomniano powyżej (dla Ubuntu)Według https://docs.docker.com/engine/reference/builder/#run domyślną powłoką [Linux]
RUN
jest/bin/sh -c
. Wygląda na to, że spodziewasz się bashism, więc powinieneś użyć „exec formularza”,RUN
aby określić swoją powłokę.W przeciwnym razie użycie „formy powłoki” programu RUN i określenie innej powłoki spowoduje utworzenie zagnieżdżonych powłok.
Jeśli masz więcej niż 1 polecenie wymagające innej powłoki, powinieneś przeczytać https://docs.docker.com/engine/reference/builder/#shell i zmienić domyślną powłokę, umieszczając ją przed poleceniami RUN:
Na koniec, jeśli umieściłeś coś w
.bashrc
pliku użytkownika root , którego potrzebujesz, możesz dodać-l
flagę do poleceniaSHELL
lub,RUN
aby uczynić z niego powłokę logowania i upewnić się, że zostanie pozyskana.Uwaga: Celowo zignorowałem fakt, że nie ma sensu pozyskiwać skryptu jako jedynego polecenia w poleceniu RUN.
źródło
SHELL ["/bin/sh", "-c", "-l"]
więc źródła ~ / .bashrc itp. na wypadek, gdybyś miał ustawienia środowiska z podstawowego kontenera/bin/sh
Co nie rozwiąże problemu, że bash nie będzie używany. Ponadto, podczas wykonywaniadocker build
nie jest prawdopodobne, aby w pliku root użytkownika .bashrc znajdowało się coś, czego potrzebujesz. Ale jeśli umieścisz coś tam wcześniej w Dockerfile (na przykład możeJAVA_HOME
, a potem tak). W mojej odpowiedziZgodnie z dokumentacją Dockera
Zobacz https://docs.docker.com/engine/reference/builder/#run
źródło
Jeśli masz
SHELL
dostęp, powinieneś skorzystać z tej odpowiedzi - nie używaj tej, która zmusi cię do umieszczenia reszty pliku docker w jednym poleceniu dla tego komentarza .Jeśli używasz starej wersji Dockera i nie masz do niej dostępu
SHELL
, będzie to działać, dopóki niczego nie potrzebujesz.bashrc
(co jest rzadkim przypadkiem w Dockerfiles):Zauważ, że
-i
jest potrzebne, aby bash w ogóle odczytał plik rc.źródło
Możesz pobiec,
bash -v
aby zobaczyć, co jest pozyskiwane.Wykonałbym następujące czynności zamiast bawić się dowiązaniami symbolicznymi:
RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc
źródło
Miałem również problemy z uruchomieniem
source
w DockerfileDziała to doskonale w przypadku budowania kontenera Docker CentOS 6.6, ale powodowało problemy w kontenerach Debian
Tak sobie z tym poradziłem, może nie jest to elegancki sposób, ale to działało dla mnie
źródło
Może się tak zdarzyć, ponieważ
source
jest to wbudowany system bash zamiast pliku binarnego w systemie plików. Czy chcesz, aby skrypt, który pozyskujesz, zmienił później kontener?źródło
Skończyło się na tym, że włożyłem swoje rzeczy związane z env
.profile
i zmutowałemSHELL
coś takiegoźródło
Jeśli próbujesz tylko użyć pipa, aby zainstalować coś w virtualenv, możesz zmodyfikować env PATH, aby najpierw przeglądał folder bin virtualenv
ENV PATH="/path/to/venv/bin:${PATH}"
Następnie wszelkie
pip install
polecenia znajdujące się w pliku Docker najpierw znajdą / path / to / venv / bin / pip i użyją tego, który zainstaluje się w tym virtualenv, a nie w Pythonie systemowym.źródło