Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using variable interpolation in string in Docker

Tags:

bash

docker

I am having trouble creating and using variables in a Dockerfile - I build a Docker image via a Dockerfile with this command:

$ docker build --build-arg s=scripts/a.sh -t a . 

(So because I use --build-arg, $s will be an available argument in the Dockerfile, and this part works)

The Dockerfile is like so:

ARG s  RUN echo $s   RUN useradd -ms /bin/bash newuser  USER newuser WORKDIR /home/newuser  ENV fn=$(filename $s)  # fails on this line  COPY $s .  ENTRYPOINT ["/bin/bash", "/home/newuser/$fn"] 

The problem I have is that the Docker build is failing on the line indicated above.

Error response from daemon: Syntax error - can't find = in "$s)". Must be of the form: name=value 

If I change that line to this:

RUN fn=$(filename $s) 

I get this error:

Error: Command failed: docker build --build-arg s=scripts/a.sh -t a . The command '/bin/sh -c fn=$(filename $s)' returned a non-zero code: 127 

Anyone know the correct way to

  1. Create a variable inside the docker file
  2. Use string interpolation with that variable so that I can reference the variable in the ENTRYPOINT arguments like so:

    ENTRYPOINT ["/bin/bash", "/home/newuser/$var"]

Even if I do this:

ARG s  ARG sname  RUN echo $s          # works as expected RUN echo $sname      # works as expected  RUN useradd -ms /bin/bash newuser  USER newuser WORKDIR /home/newuser   COPY $s .  # works as expected (I believe)  ENTRYPOINT /bin/bash /home/newuser/$sname  # does not work as expected 

even though I am using the "non-JSON" version of ENTRYPOINT, it still doesn't seem to pick up the value for the $sname variable.

like image 573
Alexander Mills Avatar asked Dec 01 '16 04:12

Alexander Mills


People also ask

Can I use variables in Dockerfile?

You can use ARG variable defaultValue and during the run command you can even update this value using --build-arg variable=value . To use these variables in the docker file you can refer them as $variable in run command.

How do I pass an environment variable in Dockerfile?

Use -e or --env value to set environment variables (default []). If you want to use multiple environments from the command line then before every environment variable use the -e flag. Note: Make sure put the container name after the environment variable, not before that.

Does docker use .ENV file?

env in your project, it's only used to put values into the docker-compose. yml file which is in the same folder. Those are used with Docker Compose and Docker Stack.

What is the difference between ENV and Arg in Dockerfile?

ENV is for future running containers. ARG for building your Docker image. ¶ ENV is mainly meant to provide default values for your future environment variables.


1 Answers

I would avoid using variable in ENTRYPOINT at all. It's tricky and requires a deep understanding of what is going on. And is easy to break it by accident. Just consider one of the following.

Create link with the known name to your start script.

RUN ln -s /home/newuser/$sname /home/newuser/docker_entrypoint.sh ENTRYPOINT ["/home/newuser/docker_entrypoint.sh"] 

or write standalone entrypoint script that runs what you need.

But if you want to know how and why solutions in your questions work just keep reading.

First some definitions.

  • ENV - is environment variable available during buildtime (docker build) and runtime (docker run)
  • ARG - is environment variable available only during buildtime

If you look at https://docs.docker.com/engine/reference/builder/#environment-replacement you see the list of dockerfile instructions that support those environment variables directly. This is why COPY "picks up the variable" as you said.

Please note that there is no RUN nor ENTRYPOINT. How does it work?

You need to dig into the documentation. First RUN (https://docs.docker.com/engine/reference/builder/#run). There are 2 forms. The first one executes command through the shell and this shell has access to buildtime environment variables.

# this works because it is called as /bin/sh -c 'echo $sname' # the /bin/sh replace $sname for you       RUN echo $sname   # this does NOT work. There is no shell process to do $sname replacement  # for you RUN ["echo", "$sname"] 

Same thing applies to the ENTRYPOINT and CMD except only runtime variables are available during container start.

# first you need to make some runtime variable from builtime one ENV sname $sname  # Then you can use it during container runtime # docker runs `/bin/sh -c '/bin/bash /home/newuser/$sname'` for you # and this `/bin/sh` proces interprets `$sname` ENTRYPOINT /bin/bash /home/newuser/$sname  # but this does NOT work. There is no process to interpolate `$sname` # docker runs what you describe. ENTRYPOINT ["/bin/bash", "/home/newuser/$sname"] 

edit 2017-04-03: updated links to the docker documentations and slight rewording to avoid confusion that I sense from other answers and comments.

like image 158
Villlem Avatar answered Sep 22 '22 04:09

Villlem