Docker中的更改目录命令是什么?

408
在Docker中,我想要做到这一点:


git clone XYZ
cd XYZ
make XYZ

然而由于没有 cd 命令,我每次都必须传入完整路径(使用 make XYZ /fullpath)。有没有好的解决办法?


相关:https://dev59.com/JWMm5IYBdhLWcg3wFL04 - trcarden
7
WORKDIR 命令也被指出作为一个可能的解决方法。 - trcarden
3
不是变通方法,而是推荐的解决方案。https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#workdir - John John Pichler
6个回答

829

使用WORKDIR命令切换到另一个目录。在WORKDIR之后的所有RUN、CMD和ENTRYPOINT命令都将从该目录执行。

RUN git clone XYZ 
WORKDIR "/XYZ"
RUN make

68
使用WORKDIR也被引用为Dockerfile最佳实践之一。 - Martin Woolstenhulme
16
我相信这是对问题更恰当的回答。 - Juan Leni
1
请注意,这将创建多个层次(我想是这样的吧?) - Sebi
4
这应该是被接受的答案。已测试并确认其有效。 - user1258361
我认为这个答案不够充分。它没有帮助到我的情况,只有在标准情况下才有用,例如使用apt-get或其他在sh shell(= Dockerfile默认)中工作的命令。如果你需要bash而不是sh shell,因为许多bash命令在Dockerfile中也需要,你需要在使用命令之前调用bash shell。请参见下面的答案。在那个隔离的bash-RUN中,WORKDIR将不起作用,如果您不更改“.bashrc”,bash将从/root开始。 - questionto42
如果我想要进入其子文件夹,我可以这样做吗:WORKDIR "/XYZ/ABC" - alper

252
您可以运行一个脚本,或者是对RUN进行更复杂的参数设置。以下是我之前下载查看过的Dockerfile示例:
RUN cd /opt && unzip treeio.zip && mv treeio-master treeio && \
    rm -f treeio.zip && cd treeio && pip install -r requirements.pip

由于使用了 '&&',只有在所有前面的命令都成功执行后,才会执行最后的 'pip install' 命令。

实际上,因为每个 RUN 命令都会创建一个新的提交并且 (目前) 一个 AUFS 层,如果 Dockerfile 中有太多命令,就会用完限制,因此在文件稳定后合并 RUN 命令可以是非常有用的事情。


226
如果你有疑问,cd 的效果只在当前的 RUN 命令中持续生效。下一个 RUN 命令将从当前的 WORKDIR 开始。 - Ritchie
这对我不起作用。我收到一个错误,说目录不存在。只有 WORKDIR 起作用。 - mbomb007
4
这不应该是解决方案。问题仅仅是如何让CD工作。 - Jeremiah Adams
@Ritchie 正是我来这里的原因。谢谢! - Luka Govedič

26

我在想如果使用两次WORKDIR是否可行,但是它起作用了 :)

FROM ubuntu:18.04

RUN apt-get update && \
    apt-get install -y python3.6

WORKDIR /usr/src

COPY ./ ./

WORKDIR /usr/src/src

CMD ["python3", "app.py"]

对我来说,这个不起作用... - GitHunter0

5
您可以使用单个RUN命令来执行它们所有。
RUN git clone XYZ && \
    cd XYZ && \
    make XYZ

3

0

请注意,如果您必须在bash shell中运行,则不仅需要RUN make,还需要在之前调用bash shell,因为在Docker中,默认情况下您处于sh shell中。

取自/bin/sh: 1: gvm: not found,大致意思是:

您的shell是/bin/sh,但源代码期望的是/bin/bash,可能是因为它将其初始化放在~/.bashrc中。

换句话说,在任何使用“sh” shell而不是“bash” shell的设置中都可能出现此问题,导致"/bin/sh: 1: MY_COMMAND: not found"

在Dockerfile案例中,请使用推荐的

RUN /bin/bash -c 'source /opt/ros/melodic/setup.bash'

或者使用带有“[]”的方式(但我宁愿不使用):

RUN ["/bin/bash", "-c", "source /opt/ros/melodic/setup.bash"]

每次新运行bash时都是隔离的,"从0开始"。例如,请注意在Dockerfile中在bash命令之前设置WORKDIR /MY_PROJECT不会影响bash命令,因为起始文件夹必须再次在".bashrc"中设置。即使您已经设置了WORKDIR,也需要cd /MY_PROJECT

附注:不要忘记在"opt/../..."之前加上第一个"/"。否则,它会抛出错误:

/bin/bash: opt/ros/melodic/setup.bash: No such file or directory

工作:

 => [stage-2 18/21] RUN ["/bin/bash", "-c", "source /opt/ros/melodic/setup.bash"]                                  0.5s
 => [stage-2 19/21] [...]

请参考SuperUser上的{{link1:“/bin/sh: 1: MY_COMMAND: not found”}},了解如何处理多行代码或者如何在“.bashrc”中填写。但这有点超出了本问题的范围。

PS:您也可以将要执行的命令放入单个bash脚本中,并在Dockerfile中运行该bash脚本(尽管我更喜欢将bash命令放在Dockerfile中,这只是我的个人意见):

#!/bin/bash
set -e

source /opt/ros/melodic/setup.bash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接