Detecting username in Dockerfile - docker

I need to run a cmd that will create my home folder within a docker container. So, if my username in my linux box is josecz then I could use it from within a Dockerfile to run a cmd like:
RUN mkdir /home/${GetMyUsername}
and get the folder /home/josecz after the Dockerfile is processed.

The only way just as commented by folks: use ARG, next gives you a workable minimal example:
Dockerfile:
FROM alpine:3.14.0
ARG GetMyUsername
RUN echo ${GetMyUsername}
RUN mkdir -p /home/${GetMyUsername}
Execution:
cake#cake:~/3$ docker build --build-arg GetMyUsername=`whoami` -t abc:1 . --no-cache
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM alpine:3.14.0
---> d4ff818577bc
Step 2/4 : ARG GetMyUsername
---> Running in 4d87a0970dbd
Removing intermediate container 4d87a0970dbd
---> 8b67912b3788
Step 3/4 : RUN echo ${GetMyUsername}
---> Running in 2d68a7e93715
cake
Removing intermediate container 2d68a7e93715
---> 100428a1c526
Step 4/4 : RUN mkdir -p /home/${GetMyUsername}
---> Running in 938d10336daa
Removing intermediate container 938d10336daa
---> 939729b76f09
Successfully built 939729b76f09
Successfully tagged abc:1
Explaination:
When docker build, you could use whoami to get the username who run the docker build, then pass to args GetMyUsername. Then, in Dockerfile, you could use ${GetMyUsername} to get the value.

Related

DOCKER ASSIGN a shell value to ENV in DOCKERFILE

I'm drastically looking for the solution of passing the value to the ENV variable in DOCKERFILE.
EX:
FROM alphine
COPY domainname.txt .
ENV NAME=$(cat /domainname.txt)
If you insist to get NAME value when docker build, you could use next:
Dockerfile:
FROM alpine
ARG NAME
ENV NAME=${NAME}
domainname.txt:
hello
Execution:
$ docker build --build-arg NAME=$(cat ./domainname.txt) -t abc:1 . --no-cache
Sending build context to Docker daemon 3.072kB
Step 1/3 : FROM alpine
---> d4ff818577bc
Step 2/3 : ARG NAME
---> Running in f1c58e816499
Removing intermediate container f1c58e816499
---> dc4d5894440b
Step 3/3 : ENV NAME=${NAME}
---> Running in 9b8f98a3857c
Removing intermediate container 9b8f98a3857c
---> 2b0c68ddc994
Successfully built 2b0c68ddc994
Successfully tagged abc:1
$ docker run --rm -it abc:1 env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=2155d7368c3e
TERM=xterm
NAME=hello
HOME=/root
You could see above NAME be assigned as hello.
Simple explanation:
NAME=$(cat ./domainname.txt) assign the hello to NAME
--build-arg pass the hello to docker build's ARG NAME
ENV NAME=${NAME} get the hello from ARG NAME

RUN Instruction in building Docker Image

Below is my Docker file
ARG tag_info=latest
FROM alpine:${tag_info} AS my_apline
ARG message='Hello World'
RUN echo ${message}
RUN echo ${message} > myfile.txt
RUN echo "Hi Harry"
When i run docker image build -t myimage:v1_0 - < Dockerfile
the output is :
Sending build context to Docker daemon 2.048kB
Step 1/6 : ARG tag_info=latest
Step 2/6 : FROM alpine:${tag_info} AS my_apline
latest: Pulling from library/alpine
cbdbe7a5bc2a: Already exists
Digest: sha256:9a839e63dad54c3a6d1834e29692c8492d93f90c59c978c1ed79109ea4fb9a54
Status: Downloaded newer image for alpine:latest
---> f70734b6a266
Step 3/6 : ARG message='Hello World'
---> Running in 74bcc8897e8e
Removing intermediate container 74bcc8897e8e
---> d8d50432d375
Step 4/6 : RUN echo ${message}
---> Running in 730ed8e1c1d3
Hello World
Removing intermediate container 730ed8e1c1d3
---> 8417e3167e80
Step 5/6 : RUN echo ${message} > myfile.txt
---> Running in c66018331383
Removing intermediate container c66018331383
---> 07dc27d8ad3d
Step 6/6 : RUN echo "Hi Harry"
---> Running in fb92fb234e42
Hi Harry
Removing intermediate container fb92fb234e42
---> a3bec122a77f
It displays "Hi Harry" and "Hello World" in the middle (which I do not understand why)
Why "Hi Harry and "Hello World" is not displayed when i spin the container from image file?
Because the RUN command executes the commands when you are building the image not when you are spinning up the container using the image. It is used to alter the image like adding new packages using apt-get or changing file permissions etc
If you need something to run when the container is starting you need to use command to entrypoint instructions
From the docker official documentation:
The RUN instruction will execute any commands in a new layer on top of the current image and commit the results. The resulting committed image will be used for the next step in the Dockerfile.
You should use CMD if you want to obtain the described behavior.
The main purpose of a CMD is to provide defaults for an executing container. These defaults can include an executable, or they can omit the executable, in which case you must specify an ENTRYPOINT instruction as well.
This has three forms:
- CMD ["executable","param1","param2"] (exec form, this is the preferred form)
- CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
- CMD command param1 param2 (shell form)

Is there a better way than repeating --build-arg on the command line when building a Dockerfile?

My single docker build command line is getting quite long. I wonder if there's a better way than settings all the ARG's in the Dockerfile and then --build-arg through each of them on the docker build command.
Unfortunately, there are no built-in possibility to specify file with build args to use docker build yet.
But anyway we can use simple bash wrapper for that:
1. We create file with build args. Something like args_list:
month=March
day=26
year=2018
2. An example of the Dockerfile is:
FROM alpine:3.7
ARG month
ARG day
ARG year
RUN echo "Today is the $day/$month/$year."
3. And build our above docker image with the following one line script:
command="docker build ."; for i in $(cat args_list); do command+=" --build-arg $i"; done; $command
The output shows that everything is successfully injected:
Sending build context to Docker daemon 3.072kB
Step 1/5 : FROM alpine:3.7
---> 3fd9065eaf02
Step 2/5 : ARG month
---> Running in 5c6e695c3fab
Removing intermediate container 5c6e695c3fab
---> 6193d0d5665f
Step 3/5 : ARG day
---> Running in da0bc3e65890
Removing intermediate container da0bc3e65890
---> 41a90a4dd893
Step 4/5 : ARG year
---> Running in 83f6ae68390d
Removing intermediate container 83f6ae68390d
---> 1fd4beef3c53
Step 5/5 : RUN echo "Today is the $day/$month/$year."
---> Running in b5eaa6a5a80c
Today is the 26/March/2018.
Removing intermediate container b5eaa6a5a80c
---> de7581671706
Successfully built de7581671706
This way we can simply add new build args into the "build args" file and our CI system will build proper images without changes on its side.

docker multistage build fails with multiple --build-arg

I am using this Dockerfile
ARG IMAGE_ONE
FROM ${IMAGE_ONE}
RUN cat /etc/debian_version
ARG IMAGE_TWO
FROM ${IMAGE_TWO}
RUN cat /etc/debian_version
But it fails because it does not use the second var IMAGE_TWO:
$ docker build --no-cache --build-arg IMAGE_ONE=debian:7 --build-arg IMAGE_TWO=debian:8 .
Sending build context to Docker daemon 2.048kB
Step 1/6 : ARG IMAGE_ONE
Step 2/6 : FROM ${IMAGE_ONE}
---> 90c038768099
Step 3/6 : RUN cat /etc/debian_version
---> Running in f842d9cf4f17
7.11
Removing intermediate container f842d9cf4f17
---> 0f7f7afdd8a6
Step 4/6 : ARG IMAGE_TWO
---> Running in ed3d36f2f9cb
Removing intermediate container ed3d36f2f9cb
---> ae4ae3cabc02
Step 5/6 : FROM ${IMAGE_TWO}
--->
Step 6/6 : RUN cat /etc/debian_version
---> Running in 6f1c165e2765
OCI runtime create failed: container_linux.go:296:
starting container process caused "exec: \"/bin/sh\":
stat /bin/sh: no such file or directory": unknown
Docker version:
$ docker --version
Docker version 17.12.0-ce, build c97c6d6
Is there something wrong in my Dockerfile or is the docker build command wrong?
The reason is because IMAGE_TWO is not in the same scope check this
https://docs.docker.com/engine/reference/builder/#scope
Basically the ARG IMAGE_TWO is still part of the first stage and goes out of scope when that stage ends and will not be part of the second stage.
Declaring the arguments at the beginning allow the IMAGE_TWO to be in the second stage.
ARG IMAGE_ONE
ARG IMAGE_TWO
FROM ${IMAGE_ONE}
RUN cat /etc/debian_version
FROM ${IMAGE_TWO}
RUN cat /etc/debian_version
docker build --build-arg=IMAGE_ONE=debian:7 --build-arg=IMAGE_TWO=debian:8 .

How to pass ARG value to ENTRYPOINT?

Docker 1.9 allows to pass arguments to a dockerfile. See link: https://docs.docker.com/engine/reference/builder/#arg
How can i pass the same arugments within ENTRYPOINT Instruction??
My dockerfile has
ARG $Version=3.1
ENTRYPOINT /tmp/folder-$Version/sample.sh start
I am getting an error while creating container with above dockerfile.
Please suggest what is the correct way to specify the argument within ENTRYPOINT instruction??
Like Blake Mitchell sais, you cannot use ARG in ENTRYPOINT. However you can use your ARG as a value for ENV, that way you can use it with ENTRYPOINT:
Dockerfile
ARG my_arg
ENV my_env_var=$my_arg
ENTRYPOINT echo $my_env_var
and run:
docker build --build-arg "my_arg=foo" ...
Short answer: you need to use ENV
Both ARG and ENV are not expanded in ENTRYPOINT or CMD. (https://docs.docker.com/engine/reference/builder/#environment-replacement) However, because ENVs are passed in as part of the environment, they are available at run time, so the shell can expand them. (This means you can't use the array form of ENTRYPOINT or CMD.)
Here is an example:
$ cat arg/Dockerfile
FROM debian:jessie
ARG FOO=bar
ENTRYPOINT echo ${FOO:-foo}
$ sudo docker build arg
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM debian:jessie
---> f50f9524513f
Step 2 : ARG FOO=bar
---> Using cache
---> 2cfdcb514b62
Step 3 : ENTRYPOINT echo ${FOO:-foo}
---> Running in 21fb9b42c10d
---> 75e5018bad83
Removing intermediate container 21fb9b42c10d
Successfully built 75e5018bad83
$ sudo docker run 75e5018bad83
foo
$ sudo docker run -e FOO=bas 75e5018bad83
bas
$ sudo docker build --build-arg FOO=bas arg
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM debian:jessie
---> f50f9524513f
Step 2 : ARG FOO=bar
---> Using cache
---> 2cfdcb514b62
Step 3 : ENTRYPOINT echo ${FOO:-foo}
---> Using cache
---> 75e5018bad83
Successfully built 75e5018bad83
$ sudo docker run 75e5018bad83
foo
$ cat env/Dockerfile
FROM debian:jessie
ARG FOO=bar
ENV FOO=${FOO}
ENTRYPOINT echo ${FOO:-foo}
$ sudo docker build env
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM debian:jessie
---> f50f9524513f
Step 2 : ARG FOO=bar
---> Using cache
---> 2cfdcb514b62
Step 3 : ENV FOO ${FOO}
---> Running in f157a07c1b3e
---> a5e8c5b65a17
Removing intermediate container f157a07c1b3e
Step 4 : ENTRYPOINT echo ${FOO:-foo}
---> Running in 66e9800ef403
---> 249fe326e9ce
Removing intermediate container 66e9800ef403
Successfully built 249fe326e9ce
$ sudo docker run 249fe326e9ce
bar
$ sudo docker run -e FOO=bas 249fe326e9ce
bas
$ sudo docker build --build-arg FOO=bas env
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM debian:jessie
---> f50f9524513f
Step 2 : ARG FOO=bar
---> Using cache
---> 2cfdcb514b62
Step 3 : ENV FOO ${FOO}
---> Running in 6baf31684b9f
---> 8f77ad154798
Removing intermediate container 6baf31684b9f
Step 4 : ENTRYPOINT echo ${FOO:-foo}
---> Running in 892ac47cabed
---> fa97da85bf8a
Removing intermediate container 892ac47cabed
Successfully built fa97da85bf8a
$ sudo docker run fa97da85bf8a
bas
$
Just in case you have more than one parameter to pass to ENTRYPOINT or CMD, you can do like that:
FROM openjdk:8-jdk-alpine
ARG PROFILE
ENV PROFILE=${PROFILE}
...
CMD java -jar -Dspring.profiles.active=$(echo ${PROFILE}) /app/server.jar
I'm struggling with this for a day, thanks for #Rotareti for mentioning. It needs to be in ENV before it can be used to the ENTRYPOINT.
ENV variable=$from_ARG_variable
ENTRYPOINT exec your_exec_sh_file $variable
Hope this helps.
The syntax for ARG should omit the $.
Instead of ARG $Version=3.1, try ARG Version=3.1.

Resources