docker build with --build-arg with multiple arguments - docker

According to the documentation, it's possible to define multiple args for the flag --build-arg, but I can't find out how. I tried the following:
docker build -t essearch/ess-elasticsearch:1.7.6 --build-arg number_of_shards=5 number_of_replicas=2 --no-cache .
=> This returns an error.
I also tried:
docker build -t essearch/ess-elasticsearch:1.7.6 --build-arg number_of_shards=5,number_of_replicas=2 --no-cache .
=> This sets one variable, number_of_shards, to the value "5,number_of_replicas=2"
Any idea how I can define multiple arguments?

Use --build-arg with each argument.
If you are passing two argument then add --build-arg with each argument like:
docker build \
-t essearch/ess-elasticsearch:1.7.6 \
--build-arg number_of_shards=5 \
--build-arg number_of_replicas=2 \
--no-cache .

The above answer by pl_rock is correct, the only thing I would add is to expect the ARG inside the Dockerfile if not you won't have access to it. So if you are doing
docker build -t essearch/ess-elasticsearch:1.7.6 --build-arg number_of_shards=5 --build-arg number_of_replicas=2 --no-cache .
Then inside the Dockerfile you should add
ARG number_of_replicas
ARG number_of_shards
I was running into this problem, so I hope I help someone (myself) in the future.

If you want to use environment variable during build. Lets say setting username and password.
username= Ubuntu
password= swed24sw
Dockerfile
FROM ubuntu:16.04
ARG SMB_PASS
ARG SMB_USER
# Creates a new User
RUN useradd -ms /bin/bash $SMB_USER
# Enters the password twice.
RUN echo "$SMB_PASS\n$SMB_PASS" | smbpasswd -a $SMB_USER
Terminal Command
docker build --build-arg SMB_PASS=swed24sw --build-arg SMB_USER=Ubuntu . -t IMAGE_TAG

It's a shame that we need multiple ARG too, it results in multiple layers and slows down the build because of that, and for anyone also wondering that, currently there is no way to set multiple ARGs per one line.

In case you want to pass automatically build arguments from a specific file, you can do it this way :
docker build $(cat .my-env-file-name | while read line; do out+="--build-arg $line"; done; echo $out; out="") .

A way to pass in build arguments from a file using xargs is as follows:
cat .MY_ENV_FILE | xargs printf -- '--build-arg %s\n' | xargs docker build -t MY_TAG .

Related

docker build --build-arg SSH_PRIVATE_KEY="$(cat ~/.ssh/id_rsa)" returning empty

I want to be able to read the contents of the file ~/.ssh/id_rsa and pass the same to my build stage of the image. When I use the command docker build --build-arg SSH_PRIVATE_KEY="$(cat ~/.ssh/id_rsa)" and then I try to echo that inside the container during a build, I get empty.
RUN echo "$SSH_PRIVATE_KEY" > /priv_key \
&& cat /priv_key
the result is
Step 6/14 : RUN echo "$SSH_PRIVATE_KEY" > /priv_key && cat /priv_key
---> Running in c8d6e3c88cd8
Removing intermediate container c8d6e3c88cd8
In the dockerfile I have ARG SSH_PRIVATE_KEY.
But when I use a dummy text like docker build --build-arg SSH_PRIVATE_KEY="dummy text" I can see it in the logs.
This causes my private key to be in invalid format since it is empty.
RUN echo "${SSH_PRIVATE_KEY}" >> /root/.ssh/id_rsa
What am I doing wrong or what is it that am not doing? Thank you
I went ahead and used ONVAULT toool to handle the ssh keys. https://github.com/dockito/vault.
Also, I had misconfigured my .ssh/config file. The new file looks like this
Host *
IgnoreUnknown AddKeysToAgent,UseKeychain
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_rsa
I hope it helps someone in future.
I could solve this by placing the ARG after defining the base image:
FROM ubuntu:18.04 as builder
ARG SSH_PRV_KEY
instead of
ARG SSH_PRV_KEY
FROM ubuntu:18.04 as builder

Default Docker Argument to UUID

Is it possible to default an ARG to a new unique ID if one has not been provided as a Build Argument?
Failing that is it possible to fail on build if a build argument is not provided?
Failing that is it possible to fail on build if a build argument is
not provided?
Yes, but then you should set any default value to ARGS in Dockerfile, or if set default value then you can ignore the default value in condition.
FROM alpine
ARG NODE_ENV
RUN if [ -z ${NODE_ENV} ];then \
echo "No value provided for build ARGS, please provide NODE_ENV, like --build-arg NODE_ENV=dev" \
exit 1; \
else \
echo "NODE_ENV is passed, value is ${NODE_ENV}"; \
fi
So if you tried like
docker build --build-arg NODE_ENV=test -t test_arg .
It will build the image, but if you tired like
docker build -t test_arg .
In this, the build will fail and will print a message to pass NODE_ENV

Do I need separate Dockerfiles for py2 and py3?

Currently I have 2 Dockerfiles, Dockerfile-py2:
FROM python:2.7
# stuff
and Dockerfile-py3:
FROM python:3.4
# stuff
where both instances of # stuff are identical.
I build two docker images using an invoke task:
#task
def docker(ctx):
"""Build docker images.
"""
tag = ctx.run('git log -1 --pretty=%h').stdout.strip()
for pyversion in '23':
name = 'myrepo/myimage{pyversion}'.format(pyversion=pyversion)
image = '{name}:{tag}'.format(name=name, tag=tag)
latest = '{name}:latest'.format(name=name)
ctx.run('docker build -t {image} -f Dockerfile-py{pyversion} .'.format(image=image, pyversion=pyversion))
ctx.run('docker tag {image} {latest}'.format(image=image, latest=latest))
ctx.run('docker push {name}'.format(name=name))
is there any way to prevent the duplication of # stuff so I can't get in a situation where someone edits one file but not the other?
Here is one way using Dockerfile ARGS along with docker build --build-arg:
ARG version
FROM python:${version}
RUN echo "$(python --version)"
# stuff
Now you build for python2.7 like so:
docker build -t myimg/tmp --build-arg version=2.7 .
In the output you will see:
Step 3/3 : RUN echo "$(python --version)"
---> Running in 06e28a29a3d2
Python 2.7.16
And in the same way, for python3.4:
docker build -t myimg/tmp --build-arg version=3.4 .
In the output you will see:
Step 3/3 : RUN echo "$(python --version)"
---> Running in 2283edc1b65d
Python 3.4.10
As you can imagine you can also set default values for ${version} in your dockerfile:
ARG version=3.4
FROM python:${version}
RUN echo "$(python --version)"
# stuff
Now if you just do docker build -t myimg/tmp . you will build for python3.4. But you can still override with the previous two commands.
So to answer your question, No, you don't need two different docker files.

DockerHub autobuild for a GitHub pull request - using the $DOCKER_TAG variable?

I have a project with DockerHub autobuilds running for each branch of the project. These builds are running nicely.
I would like to extend this autobuild configuration to build images for selected pull requests for these branches.
The following documentation indicates that a variable named DOCKER_TAG should be available in a DockerHub autobuild.
https://docs.docker.com/docker-hub/builds/advanced/#environment-variables-for-building-and-testing
I want to configure my auto build in the following manner.
If I attempt to build a tag named "pr1234" then my build will overlay the code from PR #1234 before running the build.
# Assign the env variable DOCKER_TAG to an arg of the same name
ARG DOCKER_TAG=${DOCKER_TAG}
...
# if DOCKER_TAG is in the format prNNNN then merge code for that PR on top of the current branch
RUN PRNUM=`echo ${DOCKER_TAG}| egrep "^pr([0-9]+)$" | sed -e s/pr//` && \
if [ -n "$PRNUM" ]; \
then echo "Merging $PRNUM"; \
curl -o /tmp/pr.patch -L https://github.com/DSpace/DSpace/pull/$PRNUM.diff; \
git apply /tmp/pr.patch; \
fi
If I run my build locally, I am able to set this variable and my docker build runs as I would like.
docker build -t dspace/dspace:pr1234 -f Dockerfile.jdk8-test --build-arg DOCKER_TAG=pr1234 .
When I attempt to run this from Dockerhub, the DOCKER_TAG variable appears to be blank, so I presume that DOCKER_TAG is not being set as I expected.
Can you suggest a way to access this variable or to accomplish an automated build for selected PR's?
I found a solution that seems to work. I created a build hook named hooks/build and pass the variable explicitly.
#!/bin/bash
docker build --build-arg DOCKER_TAG=$DOCKER_TAG -f $DOCKERFILE_PATH -t $IMAGE_NAME .
See https://docs.docker.com/docker-hub/builds/advanced/#custom-build-phase-hooks

Equivalent of --env-file for build-arg?

I'm building a Docker image using multiple build args, and was wondering if it was possible to pass them to docker build as a file, in the same way --env-file can be pased to docker run. The env file will be parsed by docker run automatically and the variables made available in the container.
Is it possible to specify a file of build arguments in the same way?
There's no such an option, at least for now. But if you have too many build args and want to save it in a file, you can archive it as follows:
Save the following shell to buildargs.sh, make it executable and put it in your PATH:
#!/bin/bash
awk '{ sub ("\\\\$", " "); printf " --build-arg %s", $0 } END { print "" }' $#
Build your image with argfile like:
docker build $(buildargs.sh argfile) -t your_image .
This code is safe for build-arg's that contain spaces and special characters:
for arg in buildarg1 buildarg2 ; do opts+=(--build-arg "$arg") ; done
...
docker run ... "${opts[#]}"
Just substitute buildarg1 and so on with your build-arg's escaped.
Using linux you can create a file (example: arg_file) with the variables declared:
ARG_VAL_1=Hello
ARG_VAL_2=World
Execute the source command on that file:
source arg_file
Then build a docker image using that variables run this command:
docker build \
--build-arg "ARG_VAL_1=$ARG_VAL_1" \
--build-arg "ARG_VAL_2=$ARG_VAL_2" .

Resources