https://hub.docker.com/_/busybox
For busybox, the default execution is sh
. So, after using run
, we find ourselves in a shell environment:
docker run -it busybox
But we can specify an alternate command to run in the busybox container by appending it to the Docker run command:
docker run -it busybox echo Hello World!
docker run -it busybox whoami
docker run -it busybox pwd
docker run -it busybox ls
docker run -it busybox ls /bin/
The above commands run a busybox
container, but with our own command instead of sh
. Our command controls the "main process", and the container stops when this main process ends.
But each run
operation creates a brand new container from the image! If we modify one container, we can't see the changes in the next:
docker run -it busybox echo "Hello World!" > hello.txt
docker run -it busybox cat hello.txt
Image builds are defined using the Dockerfile
. This is a text file that, by default, is named Dockerfile
. Make sure your text editor doesn't add an extension to the name!
Each image we make is built on top of another image. The FROM
instruction usually appears at the top of the Dockerfile and tells us what image we're building on.
The CMD
instruction sets the command to be run when the container starts. Multiples are redundant; only the last one is used.
FROM busybox
CMD ["echo", "Hello World!"]
To build a Docker image, you must specify a tag for the image. The tag is what Docker will call the image. You must also specify the location of the Dockerfile used to build it:
docker build -t <image_tag> <path_to_dockerfile>
We're usually working in the directory of the Dockerfile, so the path is just .
:
docker build -t hellodojo .
Once built, our image is as genuine as the ones we've downloaded. We can use it in all the same ways:
docker run -it hellodojo
Including overriding the command entirely, if we wish:
docker run -it hellodojo echo Hello Graham!
As we've seen, the CMD
instruction sets a default command to run with the container, but it can be overridden in full. If we think of containers as applications, it usually doesn't make sense to override the whole command, but it might make sense to specify arguments.
The ENTRYPOINT
instruction tells Docker the base command that we'll always want to run in this container. Users can then add their own arguments at run time.
Let's create a Dockerfile to test this:
FROM busybox
ENTRYPOINT ["echo"]
CMD ["Hello World!"]
We'll need to build this again using the docker build
steps from above. If we use the same name, our previous image will be overwritten.
When we specify no command, we get the same behaviour as before:
docker run -it hellodojo
But our echo
command is implicit now. We can simply pass the text and our container will echo it:
docker run -it hellodojo Hello Graham!
If we want to override the entrypoint to, e.g., explore the container, we can still do that with the --entrypoint
argument:
docker run -it --entrypoint=sh hellodojo
While ENTRYPOINT
and CMD
tell us what to run at the runtime of the container, RUN
instructions run, in order, during the building of the image. We can use them to install software, download and extract zip files, and do anything else that we might do on the command line when setting up an application.
FROM busybox
RUN echo "Hello World!" > hello.txt
CMD ["cat", "hello.txt"]
During the build process, Docker will create file hello.txt
in the image. When we run a container from this image, it will concatenate the output of the hello.txt
file, giving the now typical greeting.
We can also see the new file in the container's directory structure if we list the directory contents:
docker run -it hellodojo ls
I need to add some mention of the COPY instruction here, and give an example.