Treating Dockerfiles as shell scripts (2020)

hard_times2 pts0 comments

Treating Dockerfiles as shell scripts - Jake Wharton

Treating Dockerfiles as shell scripts

03 December 2020

I use Docker to run a lot of tools. With the tools all wrapped up in containers, my computers are<br>free of Python and Go and the various other dependencies needed for their use. While this is a nice<br>win for isolation and reproducibility, the user experience is sub-par.

To run a tool, I just use docker run:

$ docker run --rm tool arguments...

But the editing workflow is something like:

$ nano tool.dockerfile<br># hack hack hack...<br>$ docker build -t tool -

I also use a lot of bash scripts with easy-to-remember names. To run a script I just type its name:<br>./update_containers.sh. To edit, I open it in an editor, save, and then run. The user experience<br>of this is top-notch!

Can we combine the two?

Executable Dockerfiles

If the first line of an executable starts with #!, unix-y systems will treat what follows on that<br>line as an executable for interpreting the rest of the file. This is called the<br>shebang, and the bash scripts I use start with one:<br>#!/usr/bin/env bash.

In order to do this with a Dockerfile, though, we need a program which will conditionally run<br>docker build and then docker run the resulting image. Thankfully docker build is already<br>conditional and won't rebuild anything unless necessary, so we can always run it.

#!/usr/bin/env bash<br>NAME=$(basename "$1")<br>docker build -t "$NAME" - "$1" > /dev/null<br>shift # Remove script name from arguments<br>docker run --rm --name "$NAME" "$NAME" "$@"

With this saved as dockerfile-shebang.sh, we can add it as the shebang in a Dockerfile.

#!/path/to/dockerfile-shebang.sh

FROM alpine:latest<br>ENTRYPOINT ["echo"]

Saving this as echo.dockerfile and running chmod +x echo.dockerfile provides the user experience<br>we're after:

$ ./echo.dockerfile Hello, world!<br>Hello, world!

It's Dockerfile-Shebang!

I have wrapped up this utility into an executable, dockerfile-shabang.<br>You can find it at<br>github.com/JakeWharton/dockerfile-shebang.

The implementation is a bit more complicated than above for a few usability and correctness<br>concerns:

Builds can be slow, so a message will be displayed if the container is currently being built.

If the build step fails, its entire output will be displayed to aid in debugging.

Most importantly, there's a mechanism for passing arguments to the docker run command for<br>mounting volumes, setting environment variables, and any other container-level flags.

A real-world invocation looks something like:

$ ./tool.dockerfile -v /tanker/backups:/backups -e UID=1000 -- /backups/path/to/file.txt

While I've been using Docker to wrap tools for a while, I've only been using this shebang for a<br>week. If you're feeling similar usability pain around Dockerfiles, try it out, let me know if it<br>works, and let me know of any use cases you have which aren't covered.

— Jake Wharton

dockerfile docker name shebang dockerfiles scripts

Related Articles