94

Is it possible to create Dockerfile that executes a command on host when image is being build?

Now I'm doing:

./script_that_creates_magic_file.sh
docker build .

with Dockerfile:

FROM alpine
COPY magic_file

I want to be able to do:

docker build .

with Dockerfile:

FROM alpine
# invoke script_that_creates_magic_file.sh on the host
COPY magic_file

Of course, this script is in the same directory as Dockerfile.

1
  • Possible duplicate of stackoverflow.com/questions/32163955/…. Anyway, there are a few other possible methods to doing this i.e. ssh, mounting volumes, etc. Use more search-fu. Good luck! Commented Mar 11, 2017 at 14:59

2 Answers 2

77

(Just a suggestion)

We usually have the following structure for building our docker images:

my-image/
├── assets
│   ├── entrypoint.sh
│   └── install.sh
├── build.sh
├── Dockerfile
├── README.md
└── VERSION
  • build.sh: This is where you should invoke script_that_creates_magic_file.sh. Other common tasks involve downloading required files or temporarily copying ssh keys from the host. Finally, this script will call docker build .
  • Dockerfile: As usual, but depending on the number of commands we need to run we might have an install.sh
  • install.sh: This is copied and run inside the container, installs packages, removes unnecessary files, etc. Without being 100% sure - I think such an approach reduces the number of layers avoiding multiple commands in a single RUN
  • entrypoint.sh: Container's entrypoint. Allows us to perform tasks when the container starts (like parse environment variables) and print debugging info

I find the above structure convenient and self-documented since everyone in the team can build any image (no special instructions/steps). The README is there to explain what the image is doing... but I won't lie to you... it is usually empty... (or has an h1 for the gitlab to display) :)

Sign up to request clarification or add additional context in comments.

3 Comments

Doesn't this mean your container image has to contain everything necessary to build your app, when all you want it to do is run your app ?
@AlexMcMillan The above structure lives in your source repo. The container images will only have whatever is copied/added from the Dockerfile (host->container) and whatever is later installed by install.sh (container->container). The build.sh remains on the host and does not modify the image (prepares the env and invokes build). Since the OP did not ask for running, I didn't mention anything but I usually have a docker-compose.yml for this. The only unnecessary file left in the image is install.sh which could delete itself once finished. Makes sense now?
A common variation is to have a Makefile instead of build.sh and then simply run make instead of docker build. There are advantages (familiar to many developers; the dependency graph handling of make lets you avoid redoing things which are already done) but also disadvantages (passing arguments to make on the command line gets clunky if you have many variables you want to control, and if you have some sort of matrix of targets it gets hairy).
24

To answer the question; no there is no built-in functionality to run a command on the host before docker build (i.e., no "hooks" to trigger scripts on the host).

If you provide more information about your use case, possibly there are alternatives (e.g. using a combination of --build-arg, and docker compose)

4 Comments

well sometimes its easier and much faster to just build everything on the host system, and THEN copy all build files into the docker container. Rather than copying everysingle source file into the container, building it inside there, then deleting all the source files. The first way is faster
For sure, there may be situations where it's faster (although the build-cache, especially with BuildKit enabled may help). There may be reasons to not do so; using a Dockerfile helps with getting a consistent, sandboxed build environment, which allows setting up all tooling needed, including dependencies, which helps getting a more secured supply chain. Copying a binary from <unknown origin and environment> may not provide this. As to "deleting all the source files"; multi-stage Dockerfiles resolve that for most cases.
Could you explain the docker compose --build-args way?
@TamusJRoyce It's not hard to find from the documentation, but it's very basic. If you define ARG foo in your Dockerfile you can refer to $foo further down in the file, and pass in a value for it with docker build --build-arg foo="bar" but it's just a simple string.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.