Was ist der Sinn von WORKDIR auf Dockerfile?

105

Ich lerne Docker. Ich habe schon oft gesehen, dass Dockerfiledas WORKDIRBefehl hat:

FROM node:latest
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package.json /usr/src/app/
RUN npm install
COPY . /usr/src/app
EXPOSE 3000
CMD [ “npm”, “start” ] 

Kann ich nicht einfach weglassen WORKDIRund Copymeine Dockerfilean der Wurzel meines Projekts haben? Was sind die Nachteile dieses Ansatzes?

Le garcon
quelle
Zur Erstellungszeit wechseln Sie das Verzeichnis umWORKDIR
Ultraviolett
1
@ Ultraviolett könnten Sie dies bitte erklären. Ich
verstehe

Antworten:

117

Laut Dokumentation :

Die Anweisung WORKDIR legt das Arbeitsverzeichnis für alle Anweisungen RUN, CMD, ENTRYPOINT, COPY und ADD fest, die in der Docker-Datei darauf folgen. Wenn das WORKDIR nicht vorhanden ist, wird es erstellt, auch wenn es in keiner nachfolgenden Dockerfile-Anweisung verwendet wird.

In den Best Practices von Docker wird außerdem empfohlen, Folgendes zu verwenden:

... Sie sollten WORKDIR verwenden, anstatt Anweisungen wie RUN cd zu verbreiten ... && etwas zu tun, die schwer zu lesen, zu beheben und zu warten sind.

Ich würde vorschlagen, es zu behalten.

Ich denke, Sie können Ihre Docker-Datei in Folgendes umgestalten:

FROM node:latest
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY . ./
EXPOSE 3000
CMD [ “npm”, “start” ] 
juanlumn
quelle
2
@MarioGil Bitte werfen Sie einen Blick in die COPY-Dokumentation.
Juanlumn
1
Wenn ich FROM ubuntu as builderund dann das nachfolgende Bild verwende COPY, "weiß" es, dass ich WORKDIR im "Builder" -Bild verwendet habe, oder muss ich nicht annehmen (und einen absoluten Pfad verwenden)?
Alex 75
Nach Angaben der Docker Dokumentation Ich würde sagen , dass es das hält WORKDIRWert , weil ein Befehl RAN in der Dockerfile ist , bevor Sie den Lauf COPYein
juanlumn
Ihr RUN mkdirBefehl ist nicht notwendig; dh diese Zeile könnte gelöscht werden. Gemäß der Dokumentation "Wenn das WORKDIR nicht vorhanden ist, wird es erstellt, auch wenn es in keiner nachfolgenden Dockerfile-Anweisung verwendet wird." - docs.docker.com/engine/reference/builder/#workdir
Purplejacket
@ Purplejacket das ist richtig, ich werde die Antwort aktualisieren
juanlumn
59

Das musst du nicht

RUN mkdir -p /usr/src/app

Dies wird automatisch erstellt, wenn Sie Ihre angeben WORKDIR

FROM node:latest
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY . ./
EXPOSE 3000
CMD [ “npm”, “start” ] 
Samuel Dare
quelle
4
Manchmal wird jedoch RUN mkdir benötigt, da WORKDIR USER beim Erstellen von Verzeichnissen nicht respektiert - github.com/moby/moby/issues/20295
Joe Bowbeer
22
Ich mag die Tatsache, dass Sie WORKDIR angegeben haben, wird den Ordner automatisch erstellen.
GingerBeer
32

Sie können sich WORKDIRwie in einem cdContainer vorstellen (dies wirkt sich auf Befehle aus, die später in der Docker-Datei eingehen, wie z. B. den RUNBefehl). Wenn Sie WORKDIRin Ihrem obigen Beispiel entfernt haben, RUN npm installwürde dies nicht funktionieren, da Sie sich nicht im /usr/src/appVerzeichnis in Ihrem Container befinden würden.

Ich sehe nicht, wie dies damit zusammenhängt, wo Sie Ihre Docker-Datei ablegen (da Ihr Docker-Datei-Speicherort auf dem Host-Computer nichts mit dem pwd im Container zu tun hat). Sie können die Docker-Datei an einer beliebigen Stelle in Ihrem Projekt ablegen. Das erste Argument COPYist jedoch ein relativer Pfad. Wenn Sie also Ihre Docker-Datei verschieben, müssen Sie diese COPYBefehle möglicherweise aktualisieren .

mkasberg
quelle
3
Wenn dies WORKDIRhinzugefügt cdwird, haben die beiden COPYim ursprünglichen Beispiel nicht dieselbe Quelle und dasselbe Ziel?
Jonas Rosenqvist
5
Nr. WORKDIRBeeinflusst das Arbeitsverzeichnis im Container . Im ursprünglichen Beispiel werden die ersten COPYKopien vom package.json Host (relativer Pfad zur Docker-Datei) /usr/src/app/package.json in den Container kopiert . Tatsächlich hat das WORKDIRkeine Auswirkungen auf diesen bestimmten Befehl, da das Ziel (innerhalb des Containers) keinen relativen Pfad verwendet (der Pfad beginnt mit /).
Mkasberg
@mkasberg Wenn verhält sich WORKDIRwie ein cd. Entsprechen die 2 Schnipsel darunter? WORKDIR /usr/src/app COPY package.json /usr/src/app/und WORKDIR /usr/src/app COPY package.json . danke
kcatstack
1
Ja, das sind gleichwertig.
Mkasberg
1

Vor dem Auftragen von WORKDIR. Hier ist der WORKDIR am falschen Ort und wird nicht mit Bedacht eingesetzt.

FROM microsoft/aspnetcore:2
COPY --from=build-env /publish /publish
WORKDIR /publish
ENTRYPOINT ["dotnet", "/publish/api.dll"]

Wir haben den obigen Code korrigiert, um WORKDIR an der richtigen Stelle zu platzieren, und die folgenden Anweisungen durch Entfernen optimiert /Publish

FROM microsoft/aspnetcore:2
WORKDIR /publish
COPY --from=build-env /publish .
ENTRYPOINT ["dotnet", "/api.dll"]
Blaue Wolken
quelle
1
Sie sollten den Schrägstrich nicht vor api.dll haben, da dies ihn zur Wurzel des Containers führen würde
Timothy c
1

Achten Sie darauf, dass Sie vars nicht als Zielverzeichnisnamen verwenden. WORKDIRDies scheint zu einem schwerwiegenden Fehler zu führen, bei dem nichts normalisiert werden kann. IMO, es ist auch erwähnenswert, dass es WORKDIRsich genauso verhält wie mkdir -p <path>alle Elemente des Pfades erstellt werden, wenn sie noch nicht vorhanden sind.

UPDATE: Ich bin beim Ausführen eines mehrstufigen Builds auf das oben erwähnte variable Problem gestoßen. Es scheint nun, dass die Verwendung einer Variablen in Ordnung ist. Wenn sie (die Variable) "im Gültigkeitsbereich" ist, z. B. im Folgenden, WORKDIRschlägt die zweite Referenz fehl ...

FROM <some image>
ENV varname varval
WORKDIR $varname

FROM <some other image>
WORKDIR $varname

in der Erwägung, dass dies gelingt ...

FROM <some image>
ENV varname varval
WORKDIR $varname

FROM <some other image>
ENV varname varval
WORKDIR $varname

.oO ( Vielleicht ist es in den Dokumenten und ich habe es verpasst )

David Pointon
quelle
0

Seien Sie vorsichtig, wo Sie einstellen, WORKDIRda dies den kontinuierlichen Integrationsfluss beeinträchtigen kann. Wenn Sie es beispielsweise so einstellen, /home/circleci/projectwird ein Fehler verursacht, wie .sshoder was auch immer der Remote Circleci zur Einrichtungszeit tut.

trueadjustr
quelle