How to initialize a Docker container without building an image
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:
- Start a container from the base image.
- Mount the initialization script as a file in the container.
Be sure that it starts with a shebang and ends with
exec $SHELL
. - 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[@]}"
}