Dockerfile: 使用ADD/COPY指令时,$HOME无法正常工作。

61

在提交Bug报告之前,我想请某人确认一下我最近遇到的奇怪的docker build行为。

���虑我们有一个简单的Dockerfile,在其中我们试图将一些文件复制到非根用户的主目录中:

FROM ubuntu:utopic

ENV DEBIAN_FRONTEND=noninteractive

RUN sed -i.bak 's/http:\/\/archive.ubuntu.com\/ubuntu\//mirror:\/\/mirrors.ubuntu.com\/mirrors.txt\//g' /etc/apt/sources.list
RUN echo "deb http://repo.aptly.info/ squeeze main" >> /etc/apt/sources.list.d/_aptly.list
RUN apt-key adv --keyserver keys.gnupg.net --recv-keys e083a3782a194991
RUN apt-get update
RUN apt-get install -y aptly

RUN useradd -m aptly
RUN echo aptly:aptly | chpasswd

USER aptly
COPY ./.aptly.conf $HOME/.aptly.conf

COPY ./public.key $HOME/public.key
COPY ./signing.key $HOME/signing.key
RUN gpg --import $HOME/public.key $HOME/signing.key

RUN aptly repo create -comment='MAILPAAS components' -distribution=utopic -component=main mailpaas
CMD ["/usr/bin/aptly", "api", "serve"]

这是我在构建此镜像时遇到的错误信息:
    ...    
    Step 10 : USER aptly
     ---> Running in 8639f826420b
     ---> 3242919b2976
    Removing intermediate container 8639f826420b
    Step 11 : COPY ./.aptly.conf $HOME/.aptly.conf
     ---> bbda6e5b92df
    Removing intermediate container 1313b12ca6c6
    Step 12 : COPY ./public.key $HOME/public.key
     ---> 9a701a78d10d
    Removing intermediate container 3a6e40b8593a
    Step 13 : COPY ./signing.key $HOME/signing.key
     ---> 3d4eb847abe8
    Removing intermediate container 5ed8cf52b810
    Step 14 : RUN gpg --import $HOME/public.key $HOME/signing.key
     ---> Running in 6e481ec97f74
    gpg: directory `/home/aptly/.gnupg' created
    gpg: new configuration file `/home/aptly/.gnupg/gpg.conf' created
    gpg: WARNING: options in `/home/aptly/.gnupg/gpg.conf' are not yet active during this run
    gpg: keyring `/home/aptly/.gnupg/secring.gpg' created
    gpg: keyring `/home/aptly/.gnupg/pubring.gpg' created
    gpg: can't open `/home/aptly/public.key': No such file or directory
    gpg: can't open `/home/aptly/signing.key': No such file or directory
    gpg: Total number processed: 0

看起来$HOME是空的。但为什么呢?将绝对路径放在主目录而不是$HOME中并不是很方便。


4
我认为这不是一个 bug。我相信,通常情况下,$HOME 是由 shell 设置的,在 Dockerfile 中没有 shell。你可以使用 ENV HOME /home/aptly 来设置,那么上述代码就会生效。 - Abdullah Jibaly
3个回答

92

这是你的问题:

当你使用USER指令时,它会影响容器内启动新命令所使用的用户ID。例如,如果你这样做:

FROM ubuntu:utopic
RUN useradd -m aptly
USER aptly
RUN echo $HOME

你得到了这个:

Step 4 : RUN echo $HOME
 ---> Running in a5111bedf057
/home/aptly

由于RUN命令在容器内部启动了一个新的shell,该shell会受到之前USER指令的影响。

当您使用COPY指令时,您并没有在容器内部启动任何进程,Docker也无法了解一个shell将暴露哪些(如果有)环境变量。

最好的方法是在你的Dockerfile中设置ENV HOME / home/aptly,这样可以解决问题,或者将文件分阶段放入临时位置,然后执行以下操作:

RUN cp /skeleton/myfile $HOME/myfile

请记住,当您使用COPY命令复制文件时,这些文件将由root拥有;您需要显式地使用chown命令将其所有权更改为适当的用户。


谢谢你的提醒!对 ENV 的单独重新定义救了我一命! - Janis Peisenieks

7
根据 Docker 文档USER 只适用于 RUNCMDENTRYPOINT 命令。

USER 命令指定在运行镜像及随后的 Dockerfile 中的 RUNCMDENTRYPOINT 命令使用的用户名(或 UID),以及可选的用户组(或 GID)。


2

你需要使用绝对路径。


即使使用docker-compose构建,绝对路径也可能相对于您的docker-compose.yml上下文而言是相对路径。 - goonerify
这实际上就是我所要做的。 - juliangonzalez

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