Starting with Docker
A Docker post has been on my todo list forever: Now is the time!
Why Docker, though?
- If you’ve ever had to use a virtual machine, you’ll know how slow and heavy they are — they take up so much space! Docker is faster and lighter!
- If you’ve ever had issues between your local machine virtual environment, where your code works, and deploying it elsewhere — even with the same environment– where it suddenly no longer works, Docker can provide a working space that will be exactly the same running on your local machine as running on the remote one, because it will, in effect, be the same “machine”! Makes trouble shooting simpler as there are fewer variables.
Using instructions laid out in the Dockerfile
file, Docker packages up your environment — libraries, any dependencies, environment variables and config files etc — and the code together into an image
which you can share with whoever. They can then run
the image on their machine, and whatever you sent them will work! 💥
So, how do we start?
- Create a docker hub account: https://hub.docker.com
- Download docker from docker hub.
- Once downloaded (and dragged into Applications if you’re on a Mac), click on it and wait for docker to start (it takes a few moments). Once it has started, the docker symbol should be visible in your status bar at the top near your battery and wifi symbols.
- Open a terminal, and from whatever directory, type
docker run hello-world
which will grab the Hello World image from Docker Hub, build it, and print a message. Or, more simply, you can also just typedocker info
and you’ll get a print out of all the Docker info on your machine 😁 - Hopefully that worked out!
Some things to try:
Exploring what docker things you’ve got going on —
docker images
to see what images you have. Probably none at this point.docker ps
ordocker ps -a
to see what containers are or have been active. If you have nothing, dodocker run busybox
and then trydocker ps -a
again. You should see a new line. Take note of the<IMAGE>
image name, and the<CONTAINER ID>
,<STATUS>
and<NAMES>
as these can be referenced in command line to do things like remove, stop or run specific things.
Running —
docker run <IMAGE>
to launch a docker container and run your program within it.- If you have no images to run, try
docker run busybox
and it will look on your machine, then search Docker Hub for it, download it, and run it in a container. You can also grab an image from Docker Hub usingdocker pull <IMAGE>
. You can check out more images available on the Hub here. docker run -it <IMAGE> sh
to run the image, and open a shell so you can interact directly with the container. If the container is already running, dodocker exec -it <CONTAINER ID> sh
to get a shell prompt in the container.
Stopping and removing docker things —
docker stop <CONTAINER ID>
to stop a container running in a graceful manner. The container will still exist, though, so at some point you’ll need to remove it.docker system prune -a
to remove every image and every container on your machine! 😱 It will ask for confirmation before executing this request, however, which is nice 🎉- more sensible
rm
commands include:docker rm <CONTAINER ID>
to remove a specific container,docker container prune
to only remove stopped containers,docker rmi
to remove images. - Tip: When typing in the <CONTAINER ID> you only need to type the first few values and it will figure out which one you mean. ✨
- For more on removing images, containers and volumes, check out this post by DigitalOcean.
docker -h
to see what other commands are available.
Make your own <IMAGE>
In order to create your own images, you’ll need to type up a Dockerfile. It can be helpful for readability to install a syntax highlighter if your current text editor doesn’t already do it. I use Atom, and there are several Docker syntax highlighters available to install 👍 To find them in Atom, open Atom, select Packages
-> Settings View
-> Install Packages/Themes
and them type something like Docker highlighter
in the search bar.
The Dockerfile
This is the instruction file. Normally, we base our Dockerfile on an image that already exists so that we don’t have to build our image from scratch. For example, if you wanted to run python code in your container, you can base your Dockerfile on an existing python image. To do this, the first line will be FROM <IMAGE>
where <IMAGE>
is the pre-existing image. The screenshot below shows an Dockerfile based on the official Python3 image.
Line 1: The tag :3
specifies which version of the image to use. This could also read FROM python:2
for a python 2 version. For all different versions — or tags — check out the supported tags on the python Docker Hub page.
Line 3: The working directory WORKDIR
for the container is specified
Line 5 & 6: The reqiuirements.txt
is copied from the current directory on the local machine to the WORDKDIR
in the container, which then RUN
to install all the libraries listed in the file.
Line 8: Everything is copied from the current directory on the local machine to the WORKDIR
in the container
Line 10: The CMD
command launches the python script in the new container 💥
Tip! Write fewer lines with FROM python:3-onbuild
which will include the copying files part and the installation of requirements from requirements.txt
. The above Dockerfile becomes:
Finally, build the image, share, and run:
docker build -t <TAG NAME> .
will build the image from this Dockerfile, giving it a-t
tag name that makes sense to you. The.
is saying the Dockerfile is the current location.docker run -it <TAG NAME>
will run the new image in-i
interactive mode.
What if you wanted to use an image from Docker Hub or elsewhere as is, with no additional libraries or environment variables etc, and run a single script with it? Do you have to write a Dockerfile and build a new image?
Instead, we can run the command below to initiate a container based directly an image <TAG NAME>
such as the official python image, and run the script my-new-python-script.py
in it:
docker run -it
is as before, and run in the directory where the script is.-v "$PWD":/usr/src/myapp
mounts the local directory — or-v
olume — to the container directly, which means the desired script must be in the current local directory.-w /usr/src/myapp
defines the working directory. This is necessary even ifWORKDIR
was specified in the Dockerfile the image was built from.<TAG NAME> python my-new-python-script.py
is specifying the image to use and then calling the python script.
If you want to run several containers from the same image, and don’t want to use the randomly generated container names, a container name can be specified with the flag --name
.
In the terminal code above, the container has been named “new-script” so I know which script is running in that container. Container names have to be unique, however, so bare that in mind.
That is all for now. There is so much to Docker that it is easy to get overwhelmed. Some handy resources include:
- Command line reference https://docs.docker.com/engine/reference/commandline/docker/
- Docker’s own curriculum https://docker-curriculum.com
Now, don’t forget to clean up your exited containers!!! 👋