为什么第一个docker参数值在COPY命令中不起作用?

huangapple go评论53阅读模式
英文:

Why isn't the first docker argument value working in the COPY command

问题

以下是您要翻译的内容:

这是最简单的可复现示例。 起初,我以为是我的多阶段dockerfile的问题,但我无法在我能创建的最简单的Dockerfile中使用echo输出ARG的值。 要复现,请创建一个名为test-data的子目录,并放入一个任何名称为25_31-linux64-redhat8-testbundle.zip的zip文件。

FROM registry.access.redhat.com/ubi8-micro
ARG swversion=25
ARG build=31
RUN set -e; \
    echo "swversion $swversion, Build $build"

COPY test-data/$swversion_$build-linux64-redhat8-testbundle.zip \
     ./
RUN yum -y install unzip; \
    unzip $swversion_$build-linux64-redhat8-testbundle.zip

输出仍然没有正确输出swversion的变量值。 看起来build的默认值被填充了。 使用命令"docker build -f Dockerfileargs ."

Step 1/6 : FROM registry.access.redhat.com/ubi8-micro
 ---> 62c33d061724
Step 2/6 : ARG swversion=25
 ---> Using cache
 ---> d15b4200fccc
Step 3/6 : ARG build=31
 ---> Using cache
 ---> 497601dff448
Step 4/6 : RUN set -e;  echo "swversion $swversion, Build $build"
 ---> Using cache
 ---> fc4df82f949a
Step 5/6 : COPY test-data/$swversion_$build-linux64-redhat8-testbundle.zip      ./
COPY failed: file not found in build context or excluded by .dockerignore: stat test-data/31-linux64-redhat8-testbundle.zip: file does not exist

为什么在执行COPY命令时缺少ARG swversion的值?

英文:

This is the simplest, reproducible example. At first, I thought it was a problem with my multi-stage dockerfile but I can't echo the value of an ARG using the simplest Dockerfile that I can create. To reproduce create a sub-directory named test-data and put a zip file with anything that has the name 25_31-linux64-redhat8-testbundle.zip

FROM registry.access.redhat.com/ubi8-micro
ARG swversion=25
ARG build=31
RUN set -e; \
    echo "swversion $swversion, Build $build"
	
COPY test-data/$swversion_$build-linux64-redhat8-testbundle.zip \
     ./
RUN yum -y install unzip; \
    unzip $swversion_$build-linux64-redhat8-testbundle.zip

Output still doesn't echo the correct variable value for swversion. It does appear that the default value of build is filled in. Used command "docker build -f Dockerfileargs ."

Step 1/6 : FROM registry.access.redhat.com/ubi8-micro
 ---> 62c33d061724
Step 2/6 : ARG swversion=25
 ---> Using cache
 ---> d15b4200fccc
Step 3/6 : ARG build=31
 ---> Using cache
 ---> 497601dff448
Step 4/6 : RUN set -e;  echo "swversion $swversion, Build $build"
 ---> Using cache
 ---> fc4df82f949a
Step 5/6 : COPY test-data/$swversion_$build-linux64-redhat8-testbundle.zip      ./
COPY failed: file not found in build context or excluded by .dockerignore: stat test-data/31-linux64-redhat8-testbundle.zip: file does not exist

Why is the value for the ARG swversion missing when the COPY command executes?

答案1

得分: 1

Variable names in code tend to be "greedy" and use as many characters as possible. Consider this example in Bash:

pax> export xxx=X
pax> export yyy=Y
pax> echo a: $xxx$yyy
a: XY
pax> echo b: $xxx_$yyy
b: Y
pax> echo c: ${xxx}_${yyy}
c: X_Y

The missing 7 in the b command happens because it evaluates ${xxx_}${yyy}. Enclosing variable names in braces, as in the c command, provides the expected output.

In a Docker context, use braces like this:

COPY test-data/${swversion}_${build}-linux64-redhat8-testbundle.zip ./

For consistency and safety, always use braces, even if not strictly necessary, like in:

COPY ${APP_NAME}/poetry.lock ${APP_NAME}/pyproject.toml ./

This ensures correct variable substitution and prevents issues if others modify the code. The build variable works correctly because - is not a valid character in variable names.

(1) Note: This example uses bash, but the concept applies similarly to Docker variable evaluation.

英文:

Variable names tend to be "greedy" as in they'll use as many characters as they can to make the name. Consider for example<sup>(1)</sup>:

pax&gt; export xxx=X
pax&gt; export yyy=Y
pax&gt; echo a: $xxx$yyy
a: XY
pax&gt; echo b: $xxx_$yyy
b: Y
pax&gt; echo c: ${xxx}_${yyy}
c: X_Y

The reason the 7 is missing in that b command above is because it's not evaluating the xxx variable then echoing a literal underscore. It is instead evaluating the xxx_ variable (not set to anything in this case, so evaluates to an empty string). In other words, it's effectively evaluating ${xxx_}${yyy}.

You would be better off enclosing all your variable names in braces to properly delineate them, such as with the c command above, which gives you the expected output.

In your (Docker) case, that would be:

COPY test-data/${swversion}_${build}-linux64-redhat8-testbundle.zip ./

As an aside, here's a very similar line from one of our own Docker files, showing how we do it:

COPY ${APP_NAME}/poetry.lock ${APP_NAME}/pyproject.toml ./

It's not actually needed in that case since / is not a valid character for environment variable names so it would not be absorbed into that name. However, we always use braces for consistency, and it's safer in case someone less knowledgeable modifies it later without realising.

This is also why your build variable is being substituted correctly, since the - character following it is also not a valid character for environment variable names.


<sup>(1)</sup> Yes, I realise this is bash rather than Docker but they act very similar in terms of evaluating variables, and I'm not going to go to the trouble of creating a whole Docker image just to illustrate the concept 为什么第一个docker参数值在COPY命令中不起作用?

huangapple
  • 本文由 发表于 2023年5月22日 06:35:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/76302198.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定