Dockerfile上的WORKDIR有什么意义?


105

我正在学习Docker。对于很多次,我已经看到了DockerfileWORKDIR命令:

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

我不能只是省略WORKDIRCopy仅将我Dockerfile作为项目的根源吗?使用这种方法的缺点是什么?


在构建时,您通过WORKDIR
Ultraviolet

1
@Ultraviolet,请您解释一下。我不太明白这一点
Le garcon

Answers:


118

根据文档

WORKDIR指令为Dockerfile中跟在其后的所有RUN,CMD,ENTRYPOINT,COPY和ADD指令设置工作目录。如果WORKDIR不存在,即使以后的Dockerfile指令中未使用它,也将创建它。

另外,在Docker最佳实践中,它建议您使用它:

...您应该使用WORKDIR而不是增加诸如RUN cd…&& do-something之类的指令,这些指令难以阅读,排除故障和维护。

我建议保留它。

我认为您可以将Dockerfile重构为以下形式:

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

2
@MarioGil请查看COPY文档。
juanlumn

1
当我使用FROM ubuntu as builder,然后是连续的图像使用时COPY,是否“知道”我在“生成器”图像中使用了WORKDIR,或者我不得不假设不使用(并且使用绝对路径)?
亚历克斯75

根据Docker文档,我会说它保留了该WORKDIR值,因为在运行COPY一个文件之前,在Dockerfile中运行了一条指令
juanlumn

您的RUN mkdir命令不是必需的。即该行可以删除。根据文档“如果WORKDIR不存在,即使以后的Dockerfile指令中未使用它,也将创建它。” - docs.docker.com/engine/reference/builder/#workdir
Purplejacket

@Purplejacket是正确的,我将更新答案
juanlumn


32

你可以认为WORKDIR像一个cd容器内(它会影响稍后在Dockerfile,像命令RUN命令)。如果您WORKDIR在上面的示例RUN npm install中将其删除,则将无法使用,因为您将不在/usr/src/app容器内的目录中。

我看不到这与您放置Dockerfile的位置有什么关系(因为您在主机上的Dockerfile位置与容器内的pwd无关)。您可以将Dockerfile放置在项目中的任何位置。但是,第一个参数COPY是相对路径,因此,如果移动Dockerfile,则可能需要更新这些COPY命令。


3
如果WORKDIR加上cdCOPY原始示例中的两个源和目的地是否不会相同?
乔纳斯·罗森奎斯特

5
WORKDIR会影响容器内的工作目录。在原始示例中,第一个COPY副本从package.json 主机(Dockerfile的相对路径)从主机复制到/usr/src/app/package.json container。实际上,这WORKDIR对该特定命令没有影响,因为目标(容器内)未使用相对路径(路径以开头/)。
mkasberg '18 -10-25

@mkasberg如果WORKDIR行为像cd。那么下面的2个片段是否相等? WORKDIR /usr/src/app COPY package.json /usr/src/app/WORKDIR /usr/src/app COPY package.json . 感谢
kcatstack

1
是的,这些是等效的。
mkasberg '18

1

在应用WORKDIR之前。这里的WORKDIR放置在错误的位置,不明智地使用。

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

我们更正了以上代码,将WORKDIR放在正确的位置,并通过删除以下内容优化了以下语句 /Publish

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

1
您不应在api.dll前面加上斜线,否则会将其路径到容器的根目录
Timothy c

1

当心使用vars作为目标目录名称WORKDIR-这样做似乎会导致“无法将所有内容均标准化”致命错误。海事组织,值得一提的WORKDIRmkdir -p <path>创建路径中的所有元素(如果尚不存在)相同。

更新:我在运行多阶段构建时遇到了与变量相关的问题(如上所述)-现在看来使用变量是可以的-如果它(变量)在“范围内”,例如,在下面,第二个WORKDIR引用将失败...

FROM <some image>
ENV varname varval
WORKDIR $varname

FROM <some other image>
WORKDIR $varname

然而,它成功地...

FROM <some image>
ENV varname varval
WORKDIR $varname

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

.oO(也许是在文档中,但我错过了


0

请小心设置,WORKDIR因为它会影响连续的集成流程。例如,将其设置为/home/circleci/project会导致类似错误.ssh或远程Circleci在设置时正在执行的操作。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.