119

In my Dockerfile I have the following:

ARG a-version
RUN wget -q -O /tmp/alle.tar.gz http://someserver/server/$a-version/a-server-$a-version.tar.gz && \
    mkdir /opt/apps/$a-version

However when building this with:

--build-arg http_proxy=http://myproxy","--build-arg a-version=a","--build-arg b-version=b"

Step 10/15 : RUN wget... is shown with $a-version in the path instead of the substituted value and the build fails.

I have followed the instructions shown here but must be missing something else.

My questions is, what could be causing this issue and how can i solve it?

user3139545
  • 6,882
  • 13
  • 44
  • 87

8 Answers8

305

Another thing to be careful about is that after every FROM statement, all the ARGs get collected and are no longer available. Be careful with multi-stage builds.

You can reuse ARG with omitted default value inside FROM to get through this problem:

ARG VERSION=latest
FROM busybox:$VERSION
ARG VERSION
RUN echo $VERSION > image_version

Example taken from docs: https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact

Arad Alvand
  • 8,607
  • 10
  • 51
  • 71
Hongtao Yang
  • 3,059
  • 2
  • 6
  • 3
  • 3
    I think you can work around this by copying an ARG into an ENV. ```ARG OSVERSION ENV OSVERSION=${OSVERSION:10}``` – Dave Neeley Apr 18 '20 at 16:08
  • 11
    Gotta love the randomness of docker files. Of course ARGS would disappear after from... of course.... – Adam Hughes Feb 17 '22 at 23:22
  • so many tutorials use `ENV` workarounds because they haven't understand that `ARG` needs to be requested in every stage. Thanks for sharing, helped a lot! upvote – Aitch Jan 03 '23 at 01:39
44

Don't use - in variable names.

Docker build will always show you the line as is written down in the Dockerfile, despite the variable value.

So use this variable name a_version:

ARG a_version

See this example:

Dockerfile:

FROM alpine

ARG a_version
RUN echo $a_version

Build:

$ docker build . --build-arg a_version=1234
Sending build context to Docker daemon 2.048 kB
Step 1/3 : FROM alpine
 ---> a41a7446062d
Step 2/3 : ARG a_version
 ---> Running in c55e98cab494
 ---> 53dedab7de75
Removing intermediate container c55e98cab494
Step 3/3 : RUN echo $a_version                <<< note this <<
 ---> Running in 56b8aeddf77b
1234                                          <<<< and this <<
 ---> 89badadc1ccf
Removing intermediate container 56b8aeddf77b
Successfully built 89badadc1ccf
Robert
  • 33,429
  • 8
  • 90
  • 94
  • 1
    I got this problem as well. But - does not seem to be the cause. My ARG name is privKeyFile, no matter what I tried, the value while building is always empty. – Magicloud Mar 13 '19 at 04:15
  • 1
    As per @Oleg comment below, try adding quotes around the variable (e.g. `"$privKeyFile"`). This solved the same problem for me. Oddly, quotes seems to be a requirement only on Windows, because everything works fine on MacOS without quotes. – Devis L. Jun 18 '19 at 19:49
35

I had the same problem using Windows containers for Windows.

Instead of doing this (Which works in linux containers)

FROM alpine
ARG TARGETPLATFORM
RUN echo "I'm building for $TARGETPLATFORM"

You need to do this

FROM mcr.microsoft.com/windows/servercore
ARG TARGETPLATFORM
RUN echo "I'm building for %TARGETPLATFORM%"

Just change the variable resolution according to the OS.

Justin Lessard
  • 10,804
  • 5
  • 49
  • 61
  • 2
    This is also my solution with Docker 19.0.3 and Windows 10 v1809. I don't think this is mentioned in the Docker documentation. – jftuga Dec 19 '19 at 16:06
  • 1
    I tried the other suggestions with quotes like `RUN powershell -Command Expand-Archive "$NAME".zip` etc., but only this worked! `RUN powershell -Command Expand-Archive %NAME%.zip` – CodeManX Mar 03 '20 at 11:42
  • 1
    This is the only thing that works for me on a Windows container. Thanks! – RobbieK Apr 27 '20 at 20:38
  • 1
    What a life saver, I struggled a lot with variable substituition on Windows (running Windows Containers). This answer is the only place Ive found this information. Thanks a million. – Emil G Aug 20 '20 at 06:12
  • spent almost a day trying to find the reason whey ARG was not working on windows image... Thanks... "%ARG_NAME%" works on windows image. – irbash Nov 20 '20 at 05:24
  • 1
    Worth pointing out that the `%VAR%` substitution is only needed under `RUN`; for `ADD`, the Dockerfile expects the regular `${VAR}` substitution... – GaspardP Dec 10 '21 at 04:49
17

I spent much time to have the argument substitution working, but the solution was really simple. The substitution within RUN needs the argument reference to be enclosed in double quotes.

ARG CONFIGURATION=Debug
RUN dotnet publish "Project.csproj" -c "$CONFIGURATION" -o /app/publish
Oleg
  • 1,291
  • 13
  • 16
13

The only way I was able to substitute an ARG in a Windows Container was to prefix with $env:, as mentioned here.

An example of my Dockerfile is below. Notice that the ARG PAT is defined after the FROM so that it's in scope for its use in the RUN nuget sources add command (as Hongtao suggested). The only successful way I found to supply the personal access token was using $env:PAT

FROM mcr.microsoft.com/dotnet/framework/sdk:4.7.2 AS build
WORKDIR /app

ARG PAT

# copy csproj and restore as distinct layers
COPY *.sln .
COPY WebApi/*.csproj ./WebApi/
COPY WebApi/*.config ./WebApi/
RUN nuget sources add -name AppDev -source https://mysource.pkgs.visualstudio.com/_packaging/AppDev/nuget/v2 -username usern -password $env:PAT
RUN nuget restore

# copy everything else and build app
COPY WebApi/. ./WebApi/
WORKDIR /app/WebApi
RUN msbuild /p:Configuration=Release


FROM mcr.microsoft.com/dotnet/framework/aspnet:4.7.2 AS runtime
WORKDIR /inetpub/wwwroot
COPY --from=build /app/WebApi/. ./

The actual Docker command looks like this:

docker build --build-arg PAT=mypatgoeshere -t webapi .

nbrosz
  • 874
  • 12
  • 18
  • 1
    Might this have to do with difference in `SHELL` declarations? This was the only solution that worked for me and I'm not clear why. (FWIW, mine is `SHELL ["powershell", ...]`.) – Dan Sinclair Jan 14 '21 at 13:48
4

There are many answers, which make sense. But the main thing is missed.

The way, how to use build arguments depends on the base image.

  • For Linux image, it will work with $ARG
  • For Windows, depending on image, it can be either $env:ARG(e.g. for mcr.microsoft.com/dotnet/framework/sdk:4.8) or %ARG% (e.g. for mcr.microsoft.com/windows/nanoserver:1809)
Anton
  • 9,682
  • 11
  • 38
  • 68
3

I had the same problem accessing build-args in my RUN command. Turns out that the line containing the ARG definition should not be the first line. The working Dockerfile snippet looks like this:

FROM centos:7
MAINTAINER xxxxx

ARG SERVER_IPS

Earlier, I had placed the ARG definition as the first line of Dockerfile . My docker version is v19.

Binita Bharati
  • 5,239
  • 1
  • 43
  • 24
2

For me it was argument's order:

docker build . -f somepath/to/Dockerfile --build-arg FOO=BAR

did not work, but:

docker build --build-arg FOO=BAR . -f somepath/to/Dockerfile

did.

pbn
  • 2,406
  • 2
  • 26
  • 39