Ich habe eine Docker-Datei, die ich zusammenstelle, um eine Vanille-Python-Umgebung zu installieren (in die ich eine App installieren werde, aber zu einem späteren Zeitpunkt).
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
Der Build läuft bis zur letzten Zeile in Ordnung, wo ich die folgende Ausnahme bekomme:
[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
Wenn ich ls
in dieses Verzeichnis gehe (nur um zu testen, ob die vorherigen Schritte festgeschrieben wurden), kann ich sehen, dass die Dateien wie erwartet vorhanden sind:
$ 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
Wenn ich versuche, nur den source
Befehl auszuführen, wird der gleiche Fehler wie oben angezeigt. Wenn ich jedoch eine interaktive Shell-Sitzung starte, funktioniert die Quelle:
$ docker run 3a87 bash
source
bash: line 1: source: filename argument required
source: usage: source filename [arguments]
Ich kann das Skript von hier laufen, und dann glücklich Zugang workon
, mkvirtualenv
usw.
Ich habe ein bisschen gegraben, und anfangs sah es so aus, als ob das Problem im Unterschied zwischen bash als Ubuntu- Login-Shell und dash als Ubuntu- System-Shell liegen könnte . Dash den source
Befehl nicht unterstützt .
Die Antwort darauf scheint jedoch zu sein '.' statt source
, aber dies führt nur dazu, dass die Docker-Laufzeit mit einer Go-Panic-Ausnahme explodiert.
Was ist der beste Weg, um ein Shell-Skript über eine Dockerfile-RUN-Anweisung auszuführen, um dies zu umgehen (ich verwende das Standard-Basis-Image für Ubuntu 12.04 LTS).
CMD source activate django-py35
Antworten:
RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh"
quelle
source
überhaupt, gegen nurbash /usr/local/bin/virtualenvwrapper.sh
in diesem Fall?RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh; my_command; my_command; my_command;"
/bin/sh -c
die Standard-Shell ist, wird diese "Shell-Form" von RUN in übersetztRUN ["/bin/sh", "-c", "/bin/bash" "-c" "source /usr/local/bin/virtualenvwrapper.sh"]
. Sie sollten gehen Sie vor und nutzen die „exec Form“ RUN , so dass Sie die nehmensh
sich wie soRUN ["/bin/bash" "-c" "source /usr/local/bin/virtualenvwrapper.sh"]
bash
verschachteltes in einem erstelltsh
und daher vermieden werden sollte.Ursprüngliche Antwort
Dies sollte für jedes Ubuntu-Docker-Basis-Image funktionieren. Im Allgemeinen füge ich diese Zeile für jede Docker-Datei hinzu, die ich schreibe.
Bearbeiten von einem betroffenen Zuschauer
Wenn Sie den Effekt "Verwenden
bash
statt in dersh
gesamten Docker-Datei" erzielen möchten, ohne das Betriebssystem im Container zu verändern und möglicherweise zu beschädigen , können Sie Docker einfach Ihre Absicht mitteilen . Das geht so:Weitere Details in dieser Antwort unten. https://stackoverflow.com/a/45087082/117471
quelle
ln -snf /bin/bash /bin/sh
sh
bisbash
ln -s /bin/bash /bin/sh
Das ist eine schreckliche Idee. Ubuntu Ziele / bin / sh aus einem Grund zu stürzen. dash ist eine vollständig posix-Shell, die um Größenordnungen schneller ist als bash. Durch das Verknüpfen von / bin / sh mit bash wird die Leistung Ihres Servers drastisch reduziert. Zitieren: wiki.ubuntu.com/DashAsBinShsh
Shell ausgeführt wird, Sie dies jedoch möchtenbash
, besteht die richtige Lösung darin, densh
Prozess entwederbash
einmalig aufzurufenbash -c 'source /script.sh && …'
, oder Sie können sogar so weit gehen, Bashismen (wiesource
) vollständig zu vermeiden , und stattdessen Verwenden Sie immer nur gültige POSIX-Entsprechungen, z. /script.sh
. (Achten Sie auf das Leerzeichen nach dem.
!) Wenn Ihr Skript ausführbar ist (nicht nur beschaffbar), lassen Sie Ihr Skript niemals mit einem Schebang liegen,#!/bin/sh
wenn es nicht wirklich sh-kompatibel ist. Verwenden Sie#!/bin/bash
stattdessen.Die Standard-Shell für die
RUN
Anweisung ist["/bin/sh", "-c"]
.Mit der SHELL-Anweisung können Sie die Standard-Shell für nachfolgende
RUN
Anweisungen in Dockerfile ändern:Jetzt hat sich die Standard-Shell geändert und Sie müssen sie nicht in jeder RUN-Anweisung explizit definieren
Zusätzlicher Hinweis : Sie können auch eine
--login
Option hinzufügen, mit der eine Anmeldeshell gestartet wird. Dies bedeutet, dass~/.bachrc
zum Beispiel gelesen wird und Sie es nicht explizit vor Ihrem Befehl beziehen müssenquelle
--login
SHELL ["/bin/bash", "-c", "-l"]
ich weitere Aktualisierungen der .bashrc-Datei verwenden, wodurch ich problemlos asdf-Befehle ausführen konnte.Ich hatte das gleiche Problem und um die Pip-Installation in virtualenv auszuführen, musste ich diesen Befehl verwenden:
Ich hoffe, es hilft.
quelle
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"
Am einfachsten ist es, den Punktoperator anstelle der Quelle zu verwenden, die dem sh-Äquivalent der Bash entspricht
source
Befehl:Anstatt:
Verwenden:
quelle
.
/source
akzeptiert auch Positionsparameter nach dem Dateinamensource
oder.
gehen verloren, wenn der Befehl RUN beendet wird. Siehe: stackoverflow.com/a/40045930/19501Wenn Sie Docker 1.12 oder höher verwenden, verwenden Sie einfach
SHELL
!Kurze Antwort:
Allgemeines:
für Python Vituralenv:
Lange Antwort:
von https://docs.docker.com/engine/reference/builder/#/shell
quelle
Aufbauend auf den Antworten auf dieser Seite möchte ich hinzufügen, dass Sie sich bewusst sein müssen, dass jede RUN-Anweisung unabhängig von den anderen mit ausgeführt wird
/bin/sh -c
und daher keine Umgebungsvariablen erhält, die normalerweise in Login-Shells verwendet werden.Der beste Weg, den ich bisher gefunden habe, besteht darin, das Skript zu
/etc/bash.bashrc
jedem Befehl hinzuzufügen und ihn dann als Bash-Login aufzurufen.Sie können beispielsweise virtualenvwrapper installieren und einrichten, die virtuelle Umgebung erstellen, sie aktivieren, wenn Sie ein Bash-Login verwenden, und dann Ihre Python-Module in dieser Umgebung installieren:
Das Lesen des Handbuchs zu Bash-Startdateien hilft zu verstehen, was wann bezogen wird.
quelle
ADD env-file /etc/profile.d/installerenv.sh
RUN /bin/bash --login -c 'env'
RUN /bin/bash -c 'rm /etc/profile.d/installerenv.sh'
Wenn der Anwendungsfall der Docker-Build-Perspektive mehr Injektionsumgebungsvariablen hinzufügt, wie ich es getan habe, würde ich empfehlen, einen Blick auf docs.docker.com/compose/yml zu werfen / # env-file auch.RUN
Befehls zwischenspeichern, was bedeutet, dass Sie nicht viele Projektabhängigkeiten installieren und dann über den Quellcode kopieren und die Vorteile von nutzen können Zwischenschritt-Caching von Docker. Alle Projektabhängigkeiten werden jedes Mal neu installiert./etc/bashrc
für Redhat, anstatt/etc/bash.bashrc
wie oben erwähnt (für Ubuntu)Nach https://docs.docker.com/engine/reference/builder/#run dem Standard [Linux] Shell für
RUN
ist/bin/sh -c
. Sie scheinen Bashismen zu erwarten, daher sollten Sie die "exec-Form" von verwendenRUN
, um Ihre Shell anzugeben.Andernfalls führt die Verwendung der "Shell-Form" von RUN und die Angabe einer anderen Shell zu verschachtelten Shells.
Wenn Sie mehr als einen Befehl haben, der eine andere Shell benötigt, sollten Sie https://docs.docker.com/engine/reference/builder/#shell lesen und Ihre Standard-Shell ändern, indem Sie diesen vor Ihren RUN-Befehlen platzieren:
Wenn Sie etwas in die
.bashrc
Datei des Root-Benutzers eingefügt haben, das Sie benötigen, können Sie das-l
Flag zumSHELL
oder hinzufügenRUN
Befehl , um es zu einer Anmeldeshell zu machen und sicherzustellen, dass es bezogen wird.Hinweis: Ich habe absichtlich die Tatsache ignoriert, dass es sinnlos ist, ein Skript als einzigen Befehl in einem RUN zu erstellen.
quelle
SHELL ["/bin/sh", "-c", "-l"]
so dass es ~ / .bashrc usw. beschafft, falls Sie Umgebungseinstellungen vom/bin/sh
das Problem der von Bash nicht löst. Außerdem istdocker build
es unwahrscheinlich, dass die .bashrc des Root-Benutzers etwas Nützliches enthält, das Sie benötigen. Aber wenn Sie dort früher in der Docker-Datei etwas eingefügt haben (wie vielleicht einJAVA_HOME
, dann ja. Ich werde in meiner Antwort eine Notiz darüberLaut Docker-Dokumentation
Siehe https://docs.docker.com/engine/reference/builder/#run
quelle
Wenn Sie
SHELL
verfügbar sind, sollten Sie mit dieser Antwort fortfahren - verwenden Sie nicht die akzeptierte, da Sie gezwungen sind, den Rest der Docker-Datei gemäß diesem Kommentar in einen Befehl zu setzen .Wenn Sie eine alte Docker-Version verwenden und keinen Zugriff darauf haben
SHELL
, funktioniert dies, solange Sie nichts von benötigen.bashrc
(was in Docker-Dateien selten vorkommt):Beachten Sie, dass dies
-i
erforderlich ist, damit bash die RC-Datei überhaupt liest.quelle
Vielleicht möchten Sie laufen, um
bash -v
zu sehen, was bezogen wird.Ich würde folgendes tun, anstatt mit Symlinks zu spielen:
RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc
quelle
Ich hatte auch Probleme beim Ausführen
source
in einer Docker-DateiDies funktioniert einwandfrei für die Erstellung von CentOS 6.6 Docker-Containern, hat jedoch Probleme in Debian-Containern verursacht
So habe ich es angegangen, vielleicht nicht elegant, aber das hat bei mir funktioniert
quelle
Dies kann passieren, weil
source
es sich um eine integrierte Bash-Funktion handelt und nicht um eine Binärdatei im Dateisystem. Beabsichtigen Sie, dass das Skript, das Sie beziehen, den Container anschließend ändert?quelle
Am Ende habe ich meine Env-Sachen reingelegt
.profile
und soSHELL
etwas wie mutiertquelle
Wenn Sie nur versuchen, mit pip etwas in die virtuelle Umgebung zu installieren, können Sie die PATH-Umgebung so ändern, dass sie zuerst im bin-Ordner der virtuellen Umgebung angezeigt wird
ENV PATH="/path/to/venv/bin:${PATH}"
Dann finden alle
pip install
Befehle, die in der Docker-Datei folgen, zuerst / path / to / venv / bin / pip und verwenden diese, die in dieser virtuellen Umgebung und nicht in der Systempython installiert werden.quelle