Quel est l'intérêt de WORKDIR sur Dockerfile?

108

J'apprends Docker. Depuis de nombreuses fois, j'ai vu qui Dockerfilea la WORKDIRcommande:

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

Puis-je simplement omettre WORKDIRet Copyet simplement avoir mon Dockerfileà la racine de mon projet? Quels sont les inconvénients de cette approche?

Le garcon
la source
Au moment de la construction, vous changez de répertoire parWORKDIR
Ultraviolet
1
@Ultraviolet pourriez-vous s'il vous plaît expliquer cela. Je ne comprends pas tout à fait le point
Le garcon

Réponses:

119

Selon la documentation :

L'instruction WORKDIR définit le répertoire de travail pour toutes les instructions RUN, CMD, ENTRYPOINT, COPY et ADD qui le suivent dans le Dockerfile. Si le WORKDIR n'existe pas, il sera créé même s'il n'est utilisé dans aucune instruction Dockerfile ultérieure.

En outre, dans les bonnes pratiques de Docker, il vous recommande de l'utiliser:

... vous devriez utiliser WORKDIR au lieu d'instructions proliférantes comme RUN cd… && do-something, qui sont difficiles à lire, à dépanner et à maintenir.

Je suggérerais de le garder.

Je pense que vous pouvez refactoriser votre Dockerfile en quelque chose comme:

FROM node:latest
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY . ./
EXPOSE 3000
CMD [ “npm”, “start” ] 
Juanlumn
la source
2
@MarioGil Veuillez consulter la documentation COPY.
juanlumn
1
Lorsque j'utilise FROM ubuntu as builderet ensuite l'utilisation de l'image successive COPY, est-ce qu'il "sait" que j'ai utilisé WORKDIR dans l'image "constructeur" ou je dois supposer que non (et utiliser un chemin absolu)?
Alex 75 le
Selon la documentation de docker, je dirais qu'il conserve la WORKDIRvaleur car une instruction est exécutée dans le Dockerfile avant d'exécuter celle- COPYci
juanlumn
Votre RUN mkdircommande n'est pas nécessaire; c'est-à-dire que cette ligne pourrait être supprimée. Selon la documentation "Si le WORKDIR n'existe pas, il sera créé même s'il n'est utilisé dans aucune instruction Dockerfile ultérieure." - docs.docker.com/engine/reference/builder/#workdir
Purplejacket
@Purplejacket c'est correct, je vais mettre à jour la réponse
juanlumn
60

Tu n'as pas à

RUN mkdir -p /usr/src/app

Celui-ci sera créé automatiquement lorsque vous spécifiez votre WORKDIR

FROM node:latest
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY . ./
EXPOSE 3000
CMD [ “npm”, “start” ] 
Samuel Dare
la source
4
Cependant, RUN mkdir est parfois nécessaire car WORKDIR ne respecte pas USER lors de la création de répertoires - github.com/moby/moby/issues/20295
Joe Bowbeer
24
J'aime le fait que vous ayez spécifié WORKDIR créera le dossier automatiquement.
GingerBeer
32

Vous pouvez penser WORKDIRcomme un cdintérieur du récipient (il affecte les commandes qui viennent plus tard dans la Dockerfile, comme la RUNcommande). Si vous avez supprimé WORKDIRdans votre exemple ci-dessus, RUN npm installne fonctionnerait pas car vous ne seriez pas dans le /usr/src/apprépertoire à l'intérieur de votre conteneur.

Je ne vois pas comment cela serait lié à l'endroit où vous placez votre Dockerfile (puisque l'emplacement de votre Dockerfile sur la machine hôte n'a rien à voir avec le pwd à l'intérieur du conteneur). Vous pouvez placer le Dockerfile où vous le souhaitez dans votre projet. Cependant, le premier argument vers COPYest un chemin relatif, donc si vous déplacez votre Dockerfile, vous devrez peut-être mettre à jour ces COPYcommandes.

mkasberg
la source
3
Si WORKDIRajoute comme cd, les deux COPYdans l'exemple d'origine n'auront-ils pas la même source et la même destination?
Jonas Rosenqvist
5
Non WORKDIRaffecte le répertoire de travail à l'intérieur du conteneur . Dans l'exemple d'origine, les premières COPYcopies depuis package.json l'hôte (chemin relatif vers le Dockerfile) vers /usr/src/app/package.json le conteneur . En fait, le WORKDIRn'a aucun impact sur cette commande particulière car la destination (à l'intérieur du conteneur) n'utilise pas de chemin relatif (le chemin commence par /).
mkasberg
@mkasberg Si WORKDIRagit comme un cd. Alors, les 2 extraits ci-dessous sont-ils équivalents? WORKDIR /usr/src/app COPY package.json /usr/src/app/et WORKDIR /usr/src/app COPY package.json . merci
kcatstack
1
Oui, ce sont des équivalents.
mkasberg
1

Avant d'appliquer WORKDIR. Ici, le WORKDIR est au mauvais endroit et n'est pas utilisé à bon escient.

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

Nous avons corrigé le code ci-dessus pour mettre WORKDIR au bon endroit et optimisé les instructions suivantes en supprimant /Publish

FROM microsoft/aspnetcore:2
WORKDIR /publish
COPY --from=build-env /publish .
ENTRYPOINT ["dotnet", "/api.dll"]
Nuages ​​bleus
la source
1
Vous ne devriez pas avoir la barre oblique en face de api.dll car cela le mènerait à la racine du conteneur
Timothy c
1

Méfiez-vous de l'utilisation de vars comme nom de répertoire cible pour WORKDIR- faire cela semble entraîner une erreur fatale "ne peut rien normaliser". OMI, il convient également de souligner qu'il WORKDIRse comporte de la même manière que mkdir -p <path>c'est- à- dire que tous les éléments du chemin sont créés s'ils n'existent pas déjà.

MISE À JOUR: J'ai rencontré le problème lié aux variables (mentionné ci-dessus) lors de l'exécution d'une construction en plusieurs étapes - il semble maintenant que l'utilisation d'une variable convient - si elle (la variable) est "dans la portée", par exemple dans ce qui suit, la deuxième WORKDIRréférence échoue ...

FROM <some image>
ENV varname varval
WORKDIR $varname

FROM <some other image>
WORKDIR $varname

alors qu'il y parvient ...

FROM <some image>
ENV varname varval
WORKDIR $varname

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

.oO ( Peut-être que c'est dans la documentation et je l'ai manqué )

David Pointon
la source
0

Soyez prudent lorsque vous définissez, WORKDIRcar cela peut affecter le flux d'intégration continue. Par exemple, le paramétrer sur /home/circleci/projectprovoquera une erreur comme .sshou quoi que ce soit que fait le circleci distant au moment de l'installation.

truthadjustr
la source