Jaki jest sens WORKDIR w Dockerfile?

114

Uczę się Dockera. Wiele razy widziałem, że Dockerfilema WORKDIRpolecenie:

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

Czy nie mogę po prostu pominąć WORKDIRi Copypo prostu mieć mojego Dockerfileu źródła mojego projektu? Jakie są wady stosowania tego podejścia?

Le garcon
źródło
W czasie kompilacji zmieniasz katalog oWORKDIR
Ultraviolet
1
@Ultraviolet, czy mógłbyś to wyjaśnić. Nie do końca rozumiem
Le garcon

Odpowiedzi:

124

Zgodnie z dokumentacją :

Instrukcja WORKDIR ustawia katalog roboczy dla wszelkich instrukcji RUN, CMD, ENTRYPOINT, COPY i ADD, które następują po niej w pliku Dockerfile. Jeśli WORKDIR nie istnieje, zostanie utworzony, nawet jeśli nie zostanie użyty w żadnej kolejnej instrukcji Dockerfile.

Ponadto w najlepszych rozwiązaniach dotyczących platformy Docker zaleca korzystanie z niej:

... powinieneś używać WORKDIR zamiast rozsyłać instrukcje, takie jak RUN cd… && zrób coś, które są trudne do odczytania, rozwiązania problemów i utrzymania.

Proponuję go zachować.

Myślę, że możesz refaktoryzować swój plik Dockerfile na coś takiego:

FROM node:latest
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY . ./
EXPOSE 3000
CMD [ “npm”, “start” ] 
juanlumn
źródło
2
@MarioGil Zapoznaj się z dokumentacją COPY.
czerwiec
1
Kiedy używam, FROM ubuntu as buildera potem kolejne użycie obrazu COPY, czy „wie”, że użyłem WORKDIR w obrazie „builder”, czy też muszę założyć, że nie (i użyć ścieżki bezwzględnej)?
Alex 75
Zgodnie z dokumentacją Döcker Powiedziałbym, że zachowuje WORKDIRwartość, ponieważ jest Ran instrukcja w Dockerfile przed uruchomieniem COPYjednego
juanlumn
Twoje RUN mkdirpolecenie nie jest konieczne; tj. ta linia mogłaby zostać usunięta. Zgodnie z dokumentacją „Jeśli plik WORKDIR nie istnieje, zostanie utworzony, nawet jeśli nie zostanie użyty w żadnej kolejnej instrukcji Dockerfile”. - docs.docker.com/engine/reference/builder/#workdir
Purplejacket
@Purplejacket że jest poprawna, będę aktualizować odpowiedź
juanlumn
61

Nie musisz

RUN mkdir -p /usr/src/app

Zostanie to utworzone automatycznie po określeniu pliku WORKDIR

FROM node:latest
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY . ./
EXPOSE 3000
CMD [ “npm”, “start” ] 
Samuel Dare
źródło
4
Jednak czasami RUN mkdir jest potrzebny, ponieważ WORKDIR nie szanuje użytkownika podczas tworzenia katalogów - github.com/moby/moby/issues/20295
Joe Bowbeer
24
Podoba mi się fakt, że podałeś WORKDIR automatycznie utworzy folder.
GingerBeer
33

Można myśleć o WORKDIRniczym cdwewnątrz pojemnika (wpływa na polecenia, które przychodzą później w Dockerfile, jak RUNpolecenia). Jeśli usunąłeś WORKDIRw powyższym przykładzie, RUN npm installnie zadziała, ponieważ nie będziesz w /usr/src/appkatalogu wewnątrz kontenera.

Nie widzę, jak to byłoby powiązane z miejscem umieszczenia pliku Dockerfile (ponieważ lokalizacja pliku Dockerfile na maszynie hosta nie ma nic wspólnego z pwd wewnątrz kontenera). Możesz umieścić plik Dockerfile w dowolnym miejscu w swoim projekcie. Jednak pierwszym argumentem COPYjest ścieżka względna, więc jeśli przeniesiesz plik Dockerfile, może być konieczne zaktualizowanie tych COPYpoleceń.

mkasberg
źródło
3
Jeśli WORKDIRdoda coś podobnego cd, czy dwa COPYw oryginalnym przykładzie nie będą miały tego samego źródła i celu?
Jonas Rosenqvist
5
Nie WORKDIRma wpływu na katalog roboczy wewnątrz kontenera . W oryginalnym przykładzie pierwsze COPYkopie z package.json na hoście (ścieżka względna do pliku Dockerfile) do /usr/src/app/package.json w kontenerze . W rzeczywistości WORKDIRnie ma to wpływu na to konkretne polecenie, ponieważ miejsce docelowe (wewnątrz kontenera) nie używa ścieżki względnej (ścieżka zaczyna się od /).
mkasberg
@mkasberg Jeśli WORKDIRdziała jak plik cd. Czy więc dwa poniższe fragmenty są równoważne? WORKDIR /usr/src/app COPY package.json /usr/src/app/i WORKDIR /usr/src/app COPY package.json . dzięki
kcatstack
1
Tak, to są równoważne.
mkasberg
1

Przed zastosowaniem WORKDIR. Tutaj WORKDIR znajduje się w niewłaściwym miejscu i nie jest używany mądrze.

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

Poprawiliśmy powyższy kod, aby umieścić WORKDIR we właściwej lokalizacji i zoptymalizowaliśmy poniższe instrukcje, usuwając /Publish

FROM microsoft/aspnetcore:2
WORKDIR /publish
COPY --from=build-env /publish .
ENTRYPOINT ["dotnet", "/api.dll"]
Niebieskie chmury
źródło
1
Nie powinieneś mieć ukośnika przed api.dll, ponieważ spowodowałoby to ścieżkę do katalogu głównego kontenera
Timothy c
1

Uważaj na używanie vars jako nazwy katalogu docelowego, WORKDIRco wydaje się skutkować błędem krytycznym „nie można niczego normalizować”. IMO, warto też zwrócić uwagę, że WORKDIRzachowuje się tak samo jak mkdir -p <path>np. Wszystkie elementy ścieżki są tworzone, jeśli jeszcze nie istnieją.

AKTUALIZACJA: Napotkałem problem związany ze zmienną (wspomniany powyżej) podczas uruchamiania kompilacji wieloetapowej - teraz wydaje się, że użycie zmiennej jest w porządku - jeśli ona (zmienna) znajduje się w „zakresie”, np. W poniższym, drugie WORKDIRodwołanie zawodzi ...

FROM <some image>
ENV varname varval
WORKDIR $varname

FROM <some other image>
WORKDIR $varname

podczas gdy to się udaje ...

FROM <some image>
ENV varname varval
WORKDIR $varname

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

.oO ( może to jest w dokumentacji i przegapiłem to )

David Pointon
źródło
0

Zachowaj ostrożność podczas ustawiania, WORKDIRponieważ może to wpłynąć na ciągły przepływ integracji. Na przykład ustawienie go na /home/circleci/projectspowoduje błąd podobny do .sshtego, co zdalny cirleci robi w czasie konfiguracji.

własne
źródło