Default Docker Argument to UUID - docker

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

Related

Docker build requires exactly 1 argument

When I run this command on my gitlab pipeline
docker build --build-arg NPM_TOKEN=${NPM_TOKEN} --tag $REGISTRY_IMAGE/web-public:$CI_COMMIT_SHA --tag $REGISTRY_IMAGE/web-public:$CI_COMMIT_REF_NAME packages/web-public
it fails with
build requires exactly 1 argument
It looks to me like I am actually passing one argument, the path; packages/web-public. Flags are not arguments as far as I know.
What am I missing here?
This is the structure of my project
Quote your variables. Something in those variables is expanding to be more than the single arg to the flag.
docker build --build-arg "NPM_TOKEN=${NPM_TOKEN}" --tag "$REGISTRY_IMAGE/web-public:$CI_COMMIT_SHA" --tag "$REGISTRY_IMAGE/web-public:$CI_COMMIT_REF_NAME" packages/web-public
You can also echo that command to see how the variables are expanding, e.g.
echo docker build ...
from https://docs.docker.com/engine/reference/commandline/build/
docker build [OPTIONS] PATH | URL | -
It looks like there's something wrong with your PATH. Try using the absolute path or change to the directory containing the Dockerfile and use .
see also: "docker build" requires exactly 1 argument(s)
My issue was that I had a multi line script entry, eg
script:
- >
docker build \
--network host \
-t ${CI_REGISTRY}/kylehqcom/project/image:latest \
....
As soon as I added to a single line, we were all ok. So I guess the line breaks got "entered" after the first line which meant that the subsequent lines were ignored and the error was returned. Also note, that I CI linted via the GitLab ui and all was syntactically correct.

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

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

docker build with --build-arg with multiple arguments

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 .

How to make a build arg mandatory during Docker build?

Is there any way to make a build argument mandatory during docker build? The expected behaviour would be for the build to fail if the argument is missing.
For example, for the following Dockerfile:
FROM ubuntu
ARG MY_VARIABLE
ENV MY_VARIABLE $MY_VARIABLE
RUN ...
I would like the build to fail at ARG MY_VARIABLE when built with docker build -t my-tag . and pass when built with docker build -t my-tag --build-arg MY_VARIABLE=my_value ..
Is there any way to achieve that behaviour? Setting a default value doesn't really do the trick in my case.
(I'm running Docker 1.11.1 on darwin/amd64.)
EDIT:
One way of doing that I can think of is to run a command that fails when MY_VARIABLE is empty, e.g.:
FROM ubuntu
ARG MY_VARIABLE
RUN test -n "$MY_VARIABLE"
ENV MY_VARIABLE $MY_VARIABLE
RUN ...
but it doesn't seem to be a very idiomatic solution to the problem at hand.
I tested with RUN test -n <ARGvariablename> what #konradstrack mentioned in the original (edit) post... that seems do the job of mandating the variable to be passed as the build time argument for the docker build command:
FROM ubuntu
ARG MY_VARIABLE
RUN test -n "$MY_VARIABLE"
ENV MY_VARIABLE $MY_VARIABLE
You can also use shell parameter expansion to achieve this.
Let's say your mandatory build argument is called MANDATORY_BUILD_ARGUMENT, and you want it to be set and non-empty, your Dockerfile could look like this:
FROM debian:stretch-slim
MAINTAINER Evel Knievel <evel#kniev.el>
ARG MANDATORY_BUILD_ARGUMENT
RUN \
# Check for mandatory build arguments
: "${MANDATORY_BUILD_ARGUMENT:?Build argument needs to be set and non-empty.}" \
# Install libraries
&& apt-get update \
&& apt-get install -y \
cowsay \
fortune \
# Cleanup
&& apt-get clean \
&& rm -rf \
/var/lib/apt/lists/* \
/var/tmp/* \
/tmp/* \
CMD ["/bin/bash", "-c", "/usr/games/fortune | /usr/games/cowsay"]
Of course, you would also want to use the build-argument for something, unlike I did, but still, I recommend building this Dockerfile and taking it for a test-run :)
EDIT
As mentioned in #Jeffrey Wen's answer, to make sure that this errors out on a centos:7 image (and possibly others, I admittedly haven't tested this on other images than stretch-slim):
Ensure that you're executing the RUN command with the bash shell.
RUN ["/bin/bash", "-c", ": ${MYUID:?Build argument needs to be set and not null.}"]
Another simple way:
RUN test -n "$MY_VARIABLE" || (echo "MY_VARIABLE not set" && false)
Long time ago I had a need to introduce a required (mandatory) ARG, and for better UX include the check at the beginning:
FROM ubuntu:bionic
ARG MY_ARG
RUN [ -z "$MY_ARG" ] && echo "MY_ARG is required" && exit 1 || true
...
RUN ./use-my-arg.sh
But this busts the build cache for every single layer after the initial MY_ARG, because MY_ARG=VALUE is prepended to every RUN command afterwards.
Whenever I changed MY_ARG it would end up rebuilding the whole image, instead of rerunning the last RUN command only.
To bring caching back, I have changed my build to a multi-staged one:
The first stage uses MY_ARG and checks it's presence.
The second stage proceeds as usual and declares ARG MY_ARG right at the end.
FROM alpine:3.11.5
ARG MY_ARG
RUN [ -z "$MY_ARG" ] && echo "MY_ARG is required" && exit 1 || true
FROM ubuntu:bionic
...
ARG MY_ARG
RUN ./use-my-arg.sh
Since ARG MY_ARG in the second stage is declared right before it's used, all the previous steps in that stage are unaffected, thus cache properly.
You could do something like this...
FROM ubuntu:14.04
ONBUILD ARG MY_VARIABLE
ONBUILD RUN if [ -z "$MY_VARIABLE" ]; then echo "NOT SET - ERROR"; exit 1; else : ; fi
Then docker build -t my_variable_base .
Then build your images based on this...
FROM my_variable_base
...
It's not super clean, but at least it abstracts the 'bleh' stuff away to the base image.
I cannot comment yet because I do not have 50 reputation, but I would like to add onto #Jan Nash's solution because I had a little difficulty getting it to work with my image.
If you copy/paste #Jan Nash's solution, it will work and spit out the error message that the build argument is not specified.
What I want to add
When I tried getting it to work on a CentOS 7 image (centos:7), Docker ran the RUN command without erroring out.
Solution
Ensure that you're executing the RUN command with the bash shell.
RUN ["/bin/bash", "-c", ": ${MYUID:?Build argument needs to be set and not null.}"]
I hope that helps for future incoming people. Otherwise, I believe #Jan Nash's solution is just brilliant.
In case anybody is looking for a the solution but with docker compose build, I used mandatory variables.
version: "3.9"
services:
my-service:
build:
context: .
args:
- ENVVAR=${ENVVAR:?See build instructions}
After running docker compose build:
Before exporting ENVVAR: Invalid template: "required variable ENVVAR is missing a value: See build instructions"
After exporting ENVVAR: build proceeds
Support for Required Environment variables
Compose Environment Variables
None of these answers worked for me. I wanted ${MY_VARIABLE:?} but did not want to print anything, so I did like this:
ARG MY_VARIABLE
RUN test -n ${MY_VARIABLE:?}
Nothing is printed on success. On error you see this, which is a good enough error:
ERROR RUN test -n ${MY_VARIABLE:?}
/bin/sh: MY_VARIABLE: parameter not set or null
executor failed running [/bin/sh -c test -n ${MY_VARIABLE:?}]: >exit code: 2

Resources