¿Cuál es el punto de WORKDIR en Dockerfile?

105

Estoy aprendiendo a Docker. Muchas veces he visto que Dockerfiletiene el WORKDIRmando:

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

¿No puedo simplemente omitir WORKDIRy Copytener mi Dockerfileen la raíz de mi proyecto? ¿Cuáles son las desventajas de utilizar este enfoque?

Le garcon
fuente
En el momento de la compilación, cambia de directorio porWORKDIR
Ultraviolet
1
@Ultraviolet, ¿podrías explicar esto? No entiendo bien el punto
Le garcon

Respuestas:

118

Según la documentación :

La instrucción WORKDIR establece el directorio de trabajo para cualquier instrucción RUN, CMD, ENTRYPOINT, COPY y ADD que la siga en el Dockerfile. Si el WORKDIR no existe, se creará incluso si no se usa en ninguna instrucción posterior de Dockerfile.

Además, en las mejores prácticas de Docker, le recomienda que lo use:

... debe usar WORKDIR en lugar de proliferar instrucciones como RUN cd ... && do-something, que son difíciles de leer, solucionar y mantener.

Sugeriría mantenerlo.

Creo que puedes refactorizar tu Dockerfile a algo como:

FROM node:latest
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY . ./
EXPOSE 3000
CMD [ “npm”, “start” ] 
juanlumn
fuente
2
@MarioGil Por favor, eche un vistazo a la documentación de COPY.
juanlumn
1
Cuando uso FROM ubuntu as buildery luego el uso sucesivo de la imagen COPY, ¿"sabe" que usé WORKDIR en la imagen del "constructor" o debo asumir que no (y usar una ruta absoluta)?
Alex 75
De acuerdo con la documentación deWORKDIR la ventana acoplable , diría que mantiene el valor porque es una instrucción que se ejecuta en el Dockerfile antes de ejecutar la COPYúnica
juanlumn
Tu RUN mkdircomando no es necesario; es decir, esa línea podría eliminarse. Según la documentación "Si el WORKDIR no existe, se creará incluso si no se utiliza en ninguna instrucción posterior de Dockerfile". - docs.docker.com/engine/reference/builder/#workdir
Purplejacket
@Purplejacket eso es correcto, actualizaré la respuesta
juanlumn
60

No tienes que

RUN mkdir -p /usr/src/app

Esto se creará automáticamente cuando especifique su WORKDIR

FROM node:latest
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY . ./
EXPOSE 3000
CMD [ “npm”, “start” ] 
Samuel Dare
fuente
4
Sin embargo, a veces se necesita RUN mkdir porque WORKDIR no respeta al USUARIO al crear directorios - github.com/moby/moby/issues/20295
Joe Bowbeer
23
Me gusta el hecho de que especificó WORKDIR creará la carpeta automáticamente.
GingerBeer
32

Puede pensar en WORKDIRcomo cddentro del contenedor (afecta a los comandos que vienen más adelante en el Dockerfile, como el RUNcomando). Si eliminó WORKDIRen su ejemplo anterior, RUN npm installno funcionaría porque no estaría en el /usr/src/appdirectorio dentro de su contenedor.

No veo cómo esto se relacionaría con el lugar donde coloca su Dockerfile (ya que su ubicación de Dockerfile en la máquina host no tiene nada que ver con el pwd dentro del contenedor). Puede colocar el Dockerfile donde desee en su proyecto. Sin embargo, el primer argumento de COPYes una ruta relativa, por lo que si mueve su Dockerfile, es posible que deba actualizar esos COPYcomandos.

mkasberg
fuente
3
Si WORKDIRagrega like cd, ¿no tendrán los dos COPYen el ejemplo original el mismo origen y destino?
Jonas Rosenqvist
5
No. WORKDIRafecta el directorio de trabajo dentro del contenedor . En el ejemplo original, las primeras COPYcopias del package.json host (ruta relativa al Dockerfile) /usr/src/app/package.json en el contenedor . De hecho, WORKDIRno tiene ningún impacto en ese comando en particular porque el destino (dentro del contenedor) no utiliza una ruta relativa (la ruta comienza con /).
mkasberg
@mkasberg If WORKDIRactúa como un cd. Entonces, ¿los 2 fragmentos a continuación equivalen? WORKDIR /usr/src/app COPY package.json /usr/src/app/y WORKDIR /usr/src/app COPY package.json . gracias
kcatstack
1
Sí, esos son equivalentes.
mkasberg
1

Antes de aplicar WORKDIR. Aquí el WORKDIR está en el lugar equivocado y no se usa con prudencia.

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

Corregimos el código anterior para poner WORKDIR en la ubicación correcta y optimizamos las siguientes declaraciones eliminando /Publish

FROM microsoft/aspnetcore:2
WORKDIR /publish
COPY --from=build-env /publish .
ENTRYPOINT ["dotnet", "/api.dll"]
Nubes azules
fuente
1
No debería tener la barra inclinada delante de api.dll, ya que la ruta a la raíz del contenedor
Timothy c
1

Tenga cuidado con el uso de vars como el nombre del directorio de destino para WORKDIR- hacer eso parece resultar en un error fatal "no se puede normalizar nada". En mi opinión, también vale la pena señalar que se WORKDIRcomporta de la misma manera que, mkdir -p <path>es decir, todos los elementos de la ruta se crean si aún no existen.

ACTUALIZACIÓN: Encontré el problema relacionado con la variable (mencionado anteriormente) mientras ejecutaba una compilación de varias etapas; ahora parece que usar una variable está bien, si (la variable) está "dentro del alcance", por ejemplo, en lo siguiente, la segunda WORKDIRreferencia falla ...

FROM <some image>
ENV varname varval
WORKDIR $varname

FROM <some other image>
WORKDIR $varname

mientras que tiene éxito en esto ...

FROM <some image>
ENV varname varval
WORKDIR $varname

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

.oO ( Quizás esté en los documentos y me lo perdí )

David Pointon
fuente
0

Tenga cuidado donde lo establece WORKDIRporque puede afectar el flujo de integración continuo. Por ejemplo, configurarlo en /home/circleci/projectprovocará un error como .ssho lo que sea que esté haciendo el círculo remoto en el momento de la configuración.

Truthadjustr
fuente