【问题标题】:Dockerfile COPY command copies file as a directoryDockerfile COPY 命令将文件复制为目录
【发布时间】:2021-05-06 02:00:02
【问题描述】:

请注意:这个问题提到 Java 和 Java 密钥库,但实际上与 Java 无关,任何对 Docker 和写作有足够知识的人都应该回答Dockerfiles。


我有一个 Web 服务 (myservice),它是一个 Docker 化的 JVM 应用程序。 Dockerfile 看起来像这样:

FROM openjdk:8-jdk-alpine as myenv

COPY application.yml application.yml
COPY ${KS_FILE} mykeystore.p12
COPY build/libs/myservice.jar myservice.jar

EXPOSE 9200

ENTRYPOINT [ \
    "java", \
    "-Dspring.config=.", \
    "-Dkeystore.file=mykeystore.p12", \
    "-jar", \
    "myservice.jar" \
]

作为记录,mykeystore.p12 是一个文件(不是目录!),它存储了服务将返回给任何尝试与其建立连接的客户端的 SSL 证书。具体来说,它是一个加密的Java keystore,但这超出了这个问题的范围,而且不重要。重要的是你明白它是一个文件,而不是一个目录。 我将文件存储在本地计算机上。

我在这个项目的根目录中也有以下.env 文件:

MYENV=local
KS_FILE=../apprunner/certs/mykeystore.p12

因此,../apprunner/certs/mykeystore.p12 是我的文件系统上mykeystore.p12 所在位置的相对路径,我希望该URI 存储在.env 文件中并用作Dockerfile 内部的环境变量。

我像这样构建图像:

docker build -t myorg/myservice .

我像这样运行该图像的容器:

docker run -d -p9200:9200 --name myservice --net myrunner_default --env-file .env myorg/myservice

当我 SSH 进入正在运行的容器时,我确实在本地文件系统上看到了 mykeystore.p12除了...

它是一个目录!不是文件!

$ docker exec -it 8391601f451b /bin/sh
/ # ls -al
total 62936
drwxr-xr-x    1 root     root          4096 Feb  1 21:24 .
drwxr-xr-x    1 root     root          4096 Feb  1 21:24 ..
-rwxr-xr-x    1 root     root             0 Feb  1 21:24 .dockerenv
-rw-r--r--    1 root     root          1510 Jan 29 16:27 application.yml
drwxr-xr-x    2 root     root          4096 May  9  2019 bin
drwxr-xr-x    7 root     root          4096 Jan 30 22:50 mykeystore.p12
-rw-r--r--    1 root     root      64371878 Jan 29 16:27 myservice.jar
drwxr-xr-x    5 root     root           340 Feb  1 21:24 dev
drwxr-xr-x    1 root     root          4096 Feb  1 21:24 etc
... etc.

其中有很多奇怪的、意想不到的东西,比如我项目中其他目录的源文件!

很明显,在我的Dockerfile 中使用${KS_FILE} 或者在我的.env 文件中存储URI 值的方式有问题。无论如何,我必须改变什么:

  1. 我在.env 文件中指定了KS_FILE 环境变量的文件路径和名称;和
  2. 在我的 .envDockerfile 之间,文件路径 + 名称作为 文件 复制到正在运行的容器中,这样当我从容器内部 ls -al 时,我看到了作为文件?

【问题讨论】:

  • 是否应该将密钥库持久化到映像本身?我的想法是密钥库将作为一个卷安装到正在运行的容器中,从而将机密信息排除在应用程序之外。然后,如果您轮换证书,您就不必重新构建您的应用程序
  • 谢谢@C.Nivs (+1) 我当然愿意接受这种可能性,但需要看到一个有用的例子来说明你的意思,这样我才能看到“树林中的森林” .我对 Docker 还是很陌生。另外,对我来说,密钥库和配置文件 (application.yml) 都是构建/部署工件,所以我觉得你也可以对挂载配置文件提出相同的论点(所以我可以在不重建的情况下更改配置文件应用程序)。对此有什么想法?再次感谢!

标签: docker dockerfile docker-copy


【解决方案1】:

这里有两个问题。

您只能从构建目录复制文件

您不能复制存在于构建目录之外的文件(例如../apprunner/certs/mykeystore.p12)。如果您尝试在 Dockerfile 中引用此文件目录,如下所示:

FROM openjdk:8-jdk-alpine as myenv

COPY application.yml application.yml
COPY ../apprunner/certs/mykeystore.p12 mykeystore.p12

您将看到以下错误:

Step 3/6 : COPY ../apprunner/certs/mykeystore.p12 mykeystore.p12
COPY failed: forbidden path outside the build context: ../apprunner/certs/mykeystore.p12 ()

环境变量扩展不起作用

来自the documentation

环境变量(用ENV 声明声明)也可以是 在某些指令中用作要由 Dockerfile。还处理转义以包含类似变量 将语法按字面意思转化为语句。

由于您尚未在 Dockerfile 中声明任何 ENV 语句, 该环境扩展为一个空字符串,所以你得到, 效果:

COPY "" mykeystore.p12

这将简单地将构建目录的内容复制到 mykeystore.p12.

docker build 不使用.env 文件。

This article 可能会有所帮助。

【讨论】:

  • 感谢@larsks (+1)。 “构建目录”是Dockerfile 所在的目录吗?如果是这样,我假设我可以 (1) 在我的 Dockerfile 中添加一个 ENV 声明,然后 (2) 将我的 docker build 包装在 Makefile 或将密钥库文件复制到的 shell 脚本中build 目录,使用它来构建映像,然后将其删除。但这感觉很尴尬。您在这里看到任何其他解决方案吗?再次感谢!
  • build directorydocker build 命令的最后一个参数,通常是.,通常也是Dockerfile 所在的位置。如果使用 -f /path/to/Dockerfile 选项引用,Dockerfile 可以存在于其他位置。
  • W/r/t 关于密钥库的第二个问题,我想知道这是否应该在运行时注入(根据@C.Nivs 的评论)。
  • 作为记录,我从我的 Dockerfile(复制密钥库文件)中删除了第二个 COPY,重建了映像,获取了 .env 文件,然后运行了一个容器,添加了 -v ${KS_FILE}:/mykeystore.p12到运行调用。 效果很好。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2019-07-23
  • 1970-01-01
  • 2020-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多