How to initialize a Docker container without building an image

2020 February 10

Recently, I was debugging a Travis build issue, and I wanted to shorten the iteration time. The best way I could imagine was to create a container with a copy of the Travis environment and run a shell in it.

I started with a base image and wrote an initialization script. My conventional pattern is to create a Dockerfile that copies the script into the container and executes it:

FROM image:tag
WORKDIR /root
COPY install.sh .
RUN ./install.sh && rm install.sh

Since I would need to iterate on the initialization script until I got it right, I thought for a second if there was a way I could run a script at the start of a container, without writing a Dockerfile or running more than one command (i.e. no build step before the run step). Here's what I came up with:

  1. Start a container from the base image.
  2. Mount the initialization script as a file in the container. Be sure that it starts with a shebang and ends with exec $SHELL.
  3. Execute the initialization script as the ENTRYPOINT of the container.

In one short command, it looks like this:

sudo docker run --rm -it -v "$PWD/install.sh:/x" --entrypoint /x image:tag

We can abstract this pattern into a shell function. I merged it into an existing shell function I wrote that already mounts my working directory and chooses a default image.

# dock
# dock image:tag
# dock image:tag install.sh
dock() {
args=()
if [ -n "$2" ]; then
args+=(--volume "$(realpath ${2}):/tmp/entrypoint.sh" --entrypoint /tmp/entrypoint.sh)
fi
args+=("${1:-ubuntu:23.10}")
sudo docker run --rm --interactive --tty --volume "${PWD}:${PWD}" --workdir "${PWD}" "${args[@]}"
}