Qual é o objetivo do WORKDIR no Dockerfile?

105

Estou aprendendo Docker. Por muitas vezes eu vi que Dockerfiletem WORKDIRcomando:

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

Não posso simplesmente omitir WORKDIRe Copyter o meu Dockerfilena raiz do meu projeto? Quais são as desvantagens de usar essa abordagem?

Le garcon
fonte
No momento da construção, você altera o diretório porWORKDIR
Ultravioleta
1
@Ultraviolet você poderia explicar isso. Não estou entendendo bem
Le garcon

Respostas:

118

De acordo com a documentação :

A instrução WORKDIR define o diretório de trabalho para quaisquer instruções RUN, CMD, ENTRYPOINT, COPY e ADD que o seguem no Dockerfile. Se o WORKDIR não existir, ele será criado mesmo se não for usado em nenhuma instrução Dockerfile subsequente.

Além disso, nas práticas recomendadas do Docker, ele recomenda que você o use:

... você deve usar o WORKDIR em vez de proliferar instruções como RUN cd ... && do-something, que são difíceis de ler, solucionar problemas e manter.

Eu sugeriria mantê-lo.

Acho que você pode refatorar seu Dockerfile para algo como:

FROM node:latest
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY . ./
EXPOSE 3000
CMD [ “npm”, “start” ] 
juanlumn
fonte
2
@MarioGil Por favor, dê uma olhada na documentação do COPY.
janeiro
1
Quando eu uso FROM ubuntu as buildere depois uso a imagem sucessiva COPY, ela "sabe" que usei WORKDIR na imagem "builder" ou devo presumir que não (e usar um caminho absoluto)?
Alex 75
De acordo com a documentação janela de encaixe , eu diria que ele mantém o WORKDIRvalor, porque é um ran instrução na Dockerfile antes de executar a COPYum
juanlumn
Seu RUN mkdircomando não é necessário; ou seja, essa linha pode ser excluída. De acordo com a documentação "Se o WORKDIR não existir, ele será criado mesmo se não for usado em nenhuma instrução Dockerfile subsequente." - docs.docker.com/engine/reference/builder/#workdir
Purplejacket
@Purplejacket correto, atualizarei a resposta
juanlumn
59

Você não tem que

RUN mkdir -p /usr/src/app

Isso será criado automaticamente quando você especificar seu WORKDIR

FROM node:latest
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY . ./
EXPOSE 3000
CMD [ “npm”, “start” ] 
Samuel Dare
fonte
4
No entanto, às vezes RUN mkdir é necessário porque o WORKDIR não respeita o USUÁRIO ao criar diretórios - github.com/moby/moby/issues/20295
Joe Bowbeer
22
Gosto do fato de que você especificou que WORKDIR criará a pasta automaticamente.
GingerBeer
32

Você pode pensar em WORKDIRcomo cddentro do contêiner (isso afeta os comandos que vêm posteriormente no Dockerfile, como o RUNcomando). Se você removeu WORKDIRem seu exemplo acima, RUN npm installnão funcionaria porque você não estaria no /usr/src/appdiretório dentro de seu contêiner.

Não vejo como isso estaria relacionado a onde você coloca o Dockerfile (já que a localização do Dockerfile na máquina host não tem nada a ver com o pwd dentro do contêiner). Você pode colocar o Dockerfile onde quiser em seu projeto. No entanto, o primeiro argumento para COPYé um caminho relativo, portanto, se você mover o Dockerfile, pode ser necessário atualizar esses COPYcomandos.

mkasberg
fonte
3
Se WORKDIRadicionar like cd, os dois COPYno exemplo original não terão a mesma origem e destino?
Jonas Rosenqvist
5
Não. WORKDIRAfeta o diretório de trabalho dentro do contêiner . No exemplo original, as primeiras COPYcópias do package.json host (caminho relativo para o Dockerfile) para /usr/src/app/package.json o contêiner . Na verdade, o WORKDIRnão tem impacto naquele comando específico porque o destino (dentro do contêiner) não está usando um caminho relativo (o caminho começa com /).
mkasberg
@mkasberg If WORKDIRatua como um cd. Então, os 2 trechos abaixo são equivalentes? WORKDIR /usr/src/app COPY package.json /usr/src/app/e WORKDIR /usr/src/app COPY package.json . obrigado
kcatstack de
1
Sim, são equivalentes.
mkasberg de
1

Antes de aplicar o WORKDIR. Aqui, o WORKDIR está no lugar errado e não é usado com sabedoria.

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

Corrigimos o código acima para colocar WORKDIR no local correto e otimizamos as seguintes instruções removendo /Publish

FROM microsoft/aspnetcore:2
WORKDIR /publish
COPY --from=build-env /publish .
ENTRYPOINT ["dotnet", "/api.dll"]
Nuvens Azuis
fonte
1
Você não deve ter a barra na frente de api.dll, pois isso direcionaria para a raiz do contêiner
Timothy c
1

Cuidado ao usar vars como o nome do diretório de destino para WORKDIR- fazer isso parece resultar em um erro fatal "não pode normalizar nada". IMO, também é importante ressaltar que WORKDIRse comporta da mesma forma, mkdir -p <path>ou seja, todos os elementos do caminho são criados, caso ainda não existam.

ATUALIZAÇÃO: encontrei o problema relacionado à variável (mencionado acima) durante a execução de uma compilação de vários estágios - agora parece que usar uma variável está bem - se ela (a variável) estiver "no escopo", por exemplo, no seguinte, a 2ª WORKDIRreferência falha ...

FROM <some image>
ENV varname varval
WORKDIR $varname

FROM <some other image>
WORKDIR $varname

ao passo que ele consegue isso ...

FROM <some image>
ENV varname varval
WORKDIR $varname

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

.oO ( talvez esteja nos documentos e eu tenha esquecido )

David Pointon
fonte
0

Tenha cuidado onde você define WORKDIRporque pode afetar o fluxo de integração contínua. Por exemplo, configurá-lo para /home/circleci/projectcausará um erro semelhante .sshou o que quer que o circleci remoto esteja fazendo no momento da configuração.

Truthadjustr
fonte