Pass --build-arg to Dockerfile FROM instruction [duplicate] - docker

This question already has answers here:
Using ARG in FROM in dockerfile
(2 answers)
Closed 2 months ago.
How do I pass --build-arg to a Dockerfile in order to populate the version of the image?
e.g.
FROM <custom_Image>:$VERSION
Note: the docker build statement is inside a bash script.

You use the ARG statement in your Dockerfile like this
ARG myversion
FROM nginx:${myversion}
Then you can pass it from your build command like this
docker build --build-arg myversion=xyzzy .
It'll then complain that an 'xyzzy' version of nginx doesn't exist, proving that it's trying to get nginx:xyzzy.
It shouldn't matter that the docker build statement is in a bash script.

Related

Docker ARG tricky behavior

Docker build tricky behavior:
Dockerfile
ARG php_version="7.2"
ARG flavor="stretch"
FROM php:${php_version}-fpm-${flavor}
#ARG php_version="7.2"
ENV php_v $php_version
CMD echo $php_v
If you build it and run:
docker build -t args:1.0 .
docker run -it --name testargs args:1.0
Output is empty string instead of the expected "7.2"
But if the third ARG line is uncommented we get "7.2"
Why does it behave this way?
Each FROM in a Dockerfile represents a new build stage and an ARG declared before the FROM is not available for use in the newer build stages starting with another FROM.
To quote the relevant section of the doc:
An ARG declared before a FROM is outside of a build stage, so it can’t
be used in any instruction after a FROM.

Can I pass Docker run arguments to optional Golang flags? [duplicate]

This question already has answers here:
Pass optional arguments when running a Docker image
(1 answer)
How to pass arguments to Shell Script through docker run
(8 answers)
Can you pass flags to the command that docker runs?
(2 answers)
Closed 3 years ago.
I want to run a simple go script in a docker container. The script has some flags like the two examples bellow.
Flags:
dataSource := flag.String("input", "", "Path")
...
concurrency := flag.Int("concurrency", 10, "Concurrency")
flag.Parse()
Some flags have defaults set and are optional. Others are mandatory to be set by the user. How would I pass arguments in the docker run command to the go script without having the user to enter all arguments?
Dockerfile:
FROM golang:alpine AS builder
RUN apk update && apk add --no-cache git
WORKDIR $GOPATH/go/src/app
ENV GOBIN=/usr/local/bin
COPY . .
RUN go get github.com/lib/pq
RUN go build -o /go/bin/Import
FROM scratch
COPY --from=builder /go/bin/Import /go/bin/Import
ENTRYPOINT ["/go/bin/Import""]
I've read the docs about ENTRYPOINT but could not find anything suitable for me. Is it even possible or doesn't it make sense?
I've read through posts like this one: Pass optional arguments when running a Docker image . They simply pass single arguments, how would I define the default value for those?
Thanks for any help

How to avoid the Docker build cache for a single command/RUN? [duplicate]

This question already has an answer here:
Docker RUN ls shows cached files
(1 answer)
Closed 4 years ago.
I'm using RUN ls /some/directory for "printf-debugging" of a Dockerfile. After the command has been run once and no command has changed before, the result is cached and no output is provided.
I can change the command with a part which is never executed, e.g. append || echo some changing number] which is annoying for every run or turn off the build cache which affects more RUNs than necessary and thus slows down the development of the Dockerfile.
Is there a way to disable the cache for just one RUN without any of the described downsides?
Would using a build arg be an acceptable solution?
# Dockerfile
FROM alpine
RUN echo "executed 1"
# Above this will be cached, below will be retriggered with new builds
ARG BUILD
RUN echo "executed 2"
Then, running with different build arg number to re-run everything below the ARG
$ docker build --build-arg BUILD=2 -t temp .
Or, with using date as the build number:
$ docker build --build-arg BUILD="$(date)" -t temp .

How to change a docker ARG value inside an if statement?

In my Dockerfile on Ubuntu 16.04 with docker 17.12.1-ce I use
ARG ver=latest
ARG pkg=master
For building a docker container, I would like to call docker build --build-arg ver=v1 . in order to set a special package.
The code-handling part in my Dockerfile is
RUN if[ "x$ver" = "xv1" ] ; then pkg=v1.2.3 ; fi
RUN echo $pkg
Unfortunately, the ARG pkg variable is not updated and the echo statement always shows its initial value.
What can I do, to update my build variable pkg inside an if statement??
You will not be able to pass variables from one RUN to another because each RUN command is executed in a different shell.
A solution to your problem would be to extract the logic into a script and execute docker with the build arguments something like this:
if [ $ver="v1" ]; then pkg=1.2.3; fi; docker build --build-arg ver=$ver --build-arg pkg=$pkg .

Create dynamic environment variables at build time in Docker

My specific use case is that I want to organize some data about the EC2 instance a container is running on and make i available as an environment variable. I'd like to do this when the container is built.
I was hoping to be able to do something like ENV VAR_NAME $(./script/that/gets/var) in my Dockerfile, but unsurprisingly that does not work (you just get the string $(./script...).
I should mention that I know the docker run --env... will do this, but I specifically want it to be built into the container.
Am I missing something obvious? Is this even possible?
Docker v1.9 or newer
If you are using Docker v1.9 or newer, this is possible via support for build time arguments. Arguments are declared in the Dockerfile by using the ARG statement.
ARG REQUIRED_ARGUMENT
ARG OPTIONAL_ARGUMENT=default_value
When you later actually build your image using docker build you can pass arguments via the flag --build-arg as described in the docker docs.
$ docker build --build-arg REQUIRED_ARGUMENT=this-is-required .
Please note that it is not recommended to use build-time variables for passwords or secrets such as keys or credentials.
Furthermore, build-time variables may have great impact on caching. Therefore the Dockerfile should be constructed with great care to be able to utilize caching as much as possible and therein speed up the building process.
Edit: the "docker newer than v1.9"-part was added after input from leedm777:s answer.
Docker before v1.9
If you are using a Docker-version before 1.9, the ARG/--build-arg approach was not possible. You couldn't resolve this kind of info during the build so you had to pass them as parameters to the docker run command.
Docker images are to be consistent over time whereas containers can be tweaked and considered as "throw away processes".
More info about ENV
A docker discussion about dynamic builds
The old solution to this problem was to use templating. This is not a neat solution but was one of very few viable options at the time. (Inspiration from this discussion).
save all your dynamic data in a json or yaml file
create a docker file "template" where the dynamic can later be expanded
write a script that creates a Dockerfile from the config data using some templating library that you are familiar with
Docker 1.9 has added support for build time arguments.
In your Dockerfile, you add an ARG statement, which has a similar syntax to ENV.
ARG FOO_REQUIRED
ARG BAR_OPTIONAL=something
At build time, you can pass pass a --build-arg argument to set the argument for that build. Any ARG that was not given a default value in the Dockerfile must be specified.
$ docker build --build-arg FOO_REQUIRED=best-foo-ever .
To build ENV VAR_NAME $(./script/that/gets/var) into the container, create a dynamic Dockerfile at build time:
$ docker build -t awesome -f Dockerfile .
$ # get VAR_NAME value:
$ VAR_VALUE=`docker run --rm awesome \
bash -c 'echo $(./script/that/gets/var)'`
$ # use dynamic Dockerfile:
$ {
echo "FROM awesome"
echo "ENV VAR_NAME $VAR_VALUE"
} | docker build -t awesome -
https://github.com/42ua/docker-autobuild/blob/master/emscripten-sdk/README.md#build-docker-image

Resources