Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use console output in Dockerfile

I want to use some console output as the name of my base docker image.

Specifically, I have a chain of dependent docker build files so I am trying to automate this process. So for instance, the Dockerfile of one image derived1 depends on the base image base_image_namein the following scenario:

base_image_name/ 
    Dockerfile
    derived1/
        Dockerfile
    derived2/
        Dockerfile

When the base image builds, it grabs its name from its current folder by using ${PWD##*/}. In this case, the base image's folder is called base_image_name, and so the base image is called company:base_image_name.

Then when the derived images build, they should just be able to figure out the base image's name by moving up a directory and looking at that directories name. So for instance, when build the company:derived1 image builds, it should look up one directory, see that it is called base_image_name, and from that infer that it should use the base image company:base_image_name.

I would like to have this structure several layers deep, so I want to automate it. To do that, I have tried several permutations of the syntax

FROM company:$(cd $PWD/../;  echo ${PWD##*/})

but I can't seem to get it right. To understand what the command $(cd $PWD/../; echo ${PWD##*/}) is doing, just type it into your terminal..

echo $(cd $PWD/../;  echo ${PWD##*/})

simply returns the name of the directory one level up. However, when I try to use this in a Dockerfile, I get the error

Error response from daemon: Dockerfile parse error line 1: FROM requires either one or three arguments

Could somebody please provide me with the correct syntax?

EDIT:

I also tried building the derived images with a build-arg, but that doesn't seem to work either:

build.sh:

BASE=$(cd $PWD/../../; echo ${PWD##*/})
echo "BASE="$BASE
docker build --build-arg BASE=${BASE} -t company:"${PWD##*/}" . 

where the Dockerfile looks like

FROM company:$BASE

Specifically, this yields the build error:

BASE=base_image_name
Sending build context to Docker daemon   5.12kB
Step 1/3 : FROM company:$BASE
invalid reference format

So it seems that docker is not interpretting that build arg correctly.

like image 978
bremen_matt Avatar asked Feb 28 '19 11:02

bremen_matt


3 Answers

Dockerfiles don't support shell syntax in general, except for some very limited environment variable expansion.

They do support ARGs that can be passed in from the command line, and an ARG can be used to define the image FROM. So you could start your Dockerfile with

ARG tag
FROM company:${tag:-latest}

and then build the image with

docker build --build-arg tag=$(cd $PWD/../;  echo ${PWD##*/}) .

(which is involved enough that you might want to write it into a shell script).

At a very low level, it's also worth remembering that docker build works by making a tar file of the current directory, sending it across an HTTP connection to the Docker daemon, and running the build there. Once that process has happened, any notion of the host directory name is lost. In other words, even if the syntax worked, docker build also doesn't have the capability to know which host directory the Dockerfile is in.

like image 74
David Maze Avatar answered Oct 02 '22 23:10

David Maze


Aha. Found it.

As Jonathon points out, it seems as though you can't easily pull stuff in from your environment into the build system. It seems that you must use Docker build-args.

The solution was to evaluate the variable in the terminal and pass that as a build-arg:

build.sh:

BASE=$(cd $PWD/../; echo ${PWD##*/})
echo "BASE="$BASE
docker build --build-arg BASE=${BASE} -t company:"${PWD##*/}" . 

Then inside the Dockerfile of the derived image:

ARG BASE
FROM company:$BASE
like image 31
bremen_matt Avatar answered Oct 02 '22 23:10

bremen_matt


You're trying to use bash command substitution in something that isn't consumed by bash.

The [Dockerfile reference[(https://docs.docker.com/engine/reference/builder/) indicates that environment variable substitution is supported by the FROM instruction.

You'll need to instead simply use an environment variable in FROM that you compute outside of the Dockerfile and pass to docker build.

like image 28
Jonathon Reinhart Avatar answered Oct 02 '22 23:10

Jonathon Reinhart