简体   繁体   English

DockerFile :运行传递参数

[英]DockerFile : RUN Pass arguments

We need to change the JKS password for the Keystore inside our docker image.我们需要更改 docker 镜像中 Keystore 的 JKS 密码。

The following command in DockerFile works DockerFile 中的以下命令有效

1. RUN [\
2.  "/usr/lib/jvm/java-11-openjdk-amd64/bin/keytool",\
3.  "-storepasswd",\
4.  "-storepass",\
5.  "changeit",\
6.  "-new",\
7.  "NEW_JKS_PASSWORD",\
8.  "-cacerts"\
9.  ]

However, the changed password (line number 7) is still a hard-coded string.但是,更改后的密码(第 7 行)仍然是一个硬编码字符串。 We would like to read it from the environment and set in the command.我们想从环境中读取它并在命令中设置。 How can I use environment variables to achieve the same?如何使用环境变量来实现相同的目标?

You can use ARG and then the shell form of the RUN command:您可以使用ARG ,然后使用RUN命令的 shell 形式:

ARG jks_password
RUN "/usr/lib/jvm/java-11-openjdk-amd64/bin/keytool -storepasswd -storepass …"

then, when building use docker build --build-arg jks_password=XYZ .然后,在构建时使用docker build --build-arg jks_password=XYZ .

BUT this comes with a caveat, see the warning in the Docker docs:这种带有一个警告,请参阅泊坞文档的警告:

Warning: It is not recommended to use build-time variables for passing secrets like github keys, user credentials etc. Build-time variable values are visible to any user of the image with the docker history command.警告:不建议使用构建时变量来传递秘密,如 github 密钥、用户凭据等。使用 docker history 命令的图像的任何用户都可以看到构建时变量值。 Refer to the “build images with BuildKit” section to learn about secure ways to use secrets when building images.请参阅“使用 BuildKit 构建镜像”部分,了解在构建镜像时使用机密的安全方法。

Instead, the --secret flag should be used:相反,应该使用--secret标志

RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret

And the corresponding docker build arguments: --secret id=mysecret,src=mysecret.txt .以及相应的--secret id=mysecret,src=mysecret.txt .构建参数: --secret id=mysecret,src=mysecret.txt .

Think of the Dockerfile like the Java source code to your application, and the built image like a jar file.将 Dockerfile 视为应用程序的 Java 源代码,将构建的映像视为 jar 文件。 Anything you do in a RUN command will be fixed when you run container, and like a jar file, if you know how to use the host tools well it is very easy to extract the contents of the image (and in this case the corresponding secret).当你运行容器时,你在RUN命令中所做的任何事情都会被修复,就像一个 jar 文件一样,如果你知道如何很好地使用主机工具,那么很容易提取图像的内容(在这种情况下,相应的秘密)。

The easiest thing to do here is to remove this RUN directive.这里最简单的方法是删除这个RUN指令。 Instead, run the keytool command on the host system, and then use a docker run -v bind mount option to inject the file into the container when you run it.相反,在主机系统上运行keytool命令,然后在docker run -v使用docker run -v bind mount 选项将文件注入容器。

# Get the existing cacerts file out of the image
docker run --rm yourimage \
  cat /usr/lib/jvm/java-11-openjdk-amd64/lib/security/cacerts \
  > cacerts
# Change its password
keytool \
  -keystore cacerts \
  -storepass changeit \
  -storepasswd -new NEW_JKS_PASSWD
# Run the container, replacing the cacerts file with the local one
docker run \
  -v $PWD/cacerts:/usr/lib/jvm/java-11-openjdk-amd64/lib/security/cacerts \
  ...
  yourimage

If you really want to do this in the container, you need to use an entrypoint script to change the password.如果你真的想在容器中这样做,你需要使用一个入口点脚本来更改密码。 A typical pattern for using ENTRYPOINT and CMD together is to have the ENTRYPOINT be a wrapper script that does some required first-time setup, then runs the shell exec "$@" command to run the CMD (the rest of the command-line arguments) as the main container process.ENTRYPOINTCMD一起使用的典型模式是让ENTRYPOINT成为执行一些必需的首次设置的包装脚本,然后运行 ​​shell exec "$@"命令来运行CMD (其余的命令行参数) 作为主容器进程。

In this context, remember that anyone who has Docker access can docker inspect the container to find the environment variables and other options it was started with, and anyone who has root access to the system can find the environment variables of any process, so there is a not insignificant security risk of passing a password this way.在这种情况下,请记住,任何拥有 Docker 访问权限的人都可以docker inspect容器以查找其启动时使用的环境变量和其他选项,并且任何对系统具有 root 访问权限的人都可以找到任何进程的环境变量,因此有以这种方式传递密码的安全风险并非微不足道。

The entrypoint script would look something like:入口点脚本如下所示:

#!/bin/sh

# Set the password if it's provided
if [ -n "$NEW_JKS_PASSWORD" ]; then
  /usr/lib/jvm/java-11-openjdk-amd64/bin/keytool \
    -storepasswd \
    -storepass changeit \
    -new "$NEW_JKS_PASSWORD" \
    -cacerts
  # Prevent the password from leaking into the main process
  # (`docker inspect` _etc._ will still show it)
  unset NEW_JKS_PASSWORD
fi

# Run the main container process
exec "$@"

In your Dockerfile, you'd make this script be the entrypoint, and whatever java command runs the application be the command:在您的 Dockerfile 中,您可以将此脚本作为入口点,并且运行应用程序的任何java命令都是该命令:

FROM openjdk:11
COPY target/app.jar entrypoint.sh /
# MUST be JSON-array form
ENTRYPOINT ["/entrypoint.sh"]
# Can be either shell or JSON-array form
CMD ["java", "-jar", "/app.jar"]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM