Docker is the world’s leading software container platform.
Containers are a way to package software in a format that can run isolated on a shared operating system. Unlike VMs, containers do not bundle a full operating system - only libraries and settings required to make the software work are needed. This makes for efficient, lightweight, self-contained systems and guarantees that software will always run the same, regardless of where it’s deployed
Docker is a wonderful tool for many things. A few of them are;
Table of Contents
- As a version control system for your entire app's operating system by storing each configuration as a central build.
- To distribute/collaborate our app's operating system with our team.
- To run your code on your laptop in the same environment as you have on your server.
We are going to explore Docker images. Why we should use them, and how to go about it.
To illustrate this, we will create a Docker image for AdonisJs applications.
To follow this tutorial you will need Docker installed on your machine. You can find detailed installation instructions here.
When to build a Docker image
Docker images are used to configure and distribute application states. Think of it as a template with which to create the container.
With a Docker image, we can quickly spin up containers with the same configuration. We can then share these images with our team, so we will all be running containers which all have the same configuration.
There are several ways to create Docker images, but the best way is to create a
Dockerfile and use the
docker build command.
Dockerfile is a file that tells Docker how to build an image. There are various instructions we give to let Docker know what to do to configure our image.
The full documentation on the
Dockerfile can be found here.
Following the AdonisJs installation instructions, we will ask Docker to do the following.
- Build from the node:8 image since AdonisJs requires at least Node 8.0
- Install the cli tool.
- When a container starts, we need to create a new application in the current directory if none exists.
- Serve the AdonisJs application.
Let us create a folder called adonisjs for our code.
With that in mind, we can have our
Dockerfile like this.
FROM node:8 LABEL maintainer="Stephen Afam-Osemene <firstname.lastname@example.org>" # ------------------------------------------ # install the adonis CLI # ------------------------------------------ RUN npm i -g @adonisjs/cli # ------------------------------------------ # change the working directory # ------------------------------------------ WORKDIR /var/www # ------------------------------------------ # copy our initialization file and set permissions # ------------------------------------------ COPY init.sh /init.sh RUN chmod 755 /init.sh CMD ["/init.sh"]
FROMinstruction tells Docker to build from the
- We copy the
init.shfile into our image and it will run when the container is first created. We will use it to install and serve AdonisJs
init.sh will be like this.
#!/bin/bash # check if workinig directory is empty # Install adonisjs in the working directory if empty if [[ -z "$(ls -A $PWD 2>/dev/null)" ]]; then adonis new . $adonisFlags # change host and port to work properly inside a Docker container sed -i -e "s/HOST=.*/HOST=0.0.0.0/g" .env sed -i -e "s/PORT=.*/PORT=80/g" .env fi # check for the .env file if [[ -z "$(ls -A $PWD | grep .env)" ]]; then echo "no .env file found." exit 1 fi # source the .env file so we can use the variables source .env # serve production build if the NODE_ENV is set to production # serve with --dev flag if not in production if [[ "$NODE_ENV" == "production" ]]; then adonis serve else adonis serve --dev fi
After creating a Dockerfile, we can then build our image.
Building our image from a
docker build command creates a new Docker image from a
Dockerfile in the specified directory.
docker build /path/to/directory
Dockerfile is present in the current directory, we can simply do
docker build .
To specify the name of the file, we use the
docker build -f CustomDockerfile .
Naming our Image
When a new image is built, it is given an
ID but no name.
If you run
docker images you will see the
To change that we pass a string to the
docker build -t my-adonis-js .
If we run
docker images we will see our image with the
REPOSITORY set as
my-adonis-js and the
TAG set to
However, this means that each time we build our image, it will overwrite the old one. It does this because by default
docker build uses the
To prevent this, we should explicitly define the
NOTE:There are other reasons to avoid using the default
latest tag. Some of them are highlighted in this article.
To specify the
TAG of our image, in the string passed to the
docker build command, we pass a colon
: and then the
docker build -t my-adonis-js:1.0.0 .
NOTE:The parameter passed to the
--tag flag is actually the repository and the tag.
Distributing our Image
There are several ways to distribute our images.
- With a tar archive
- Using Docker Hub
- Other methods
With a tar archive
Creating the tar archive
To create a tar archive of our repository, we use the
docker save command. We specify the file to write to using the
docker save -o my-adonis-js.tar my-adonis-js
When run like this, it will save all tags of the my-adonis-js image. To save only one tag we should specify it.
docker save -o my-adonis-js.tar my-adonis-js:1.0.0
If we want to save more than one image in the same file, we can pass more images to the command
docker save -o my-adonis-js.tar my-adonis-js:1.0.0 my-adonis-js:2.0.0
NOTE: The images passed do not have to be tags of the same image. For example, we can do;
docker save -o backup-images.tar my-adonis-js:1.0.0 ubuntu:16.04 node:8
Loading a tar archive
After creating and sharing our tar archive, we have to then load them into Docker.
To do this, we use the
docker load command. To specify the input file, we use the
--input flag .
docker load -i my-adonis-js.tar
This will load all the images we have saved into the tar archive. The images will now show up when we run
Using Docker Hub
Docker Hub is a public repository for Docker images. There are thousands of Docker images available and anyone can signup and use it to host their own Docker image.
First of all, if you don't have an account yet, you will need to sign up at hub.docker.com.
Next, we log in on our terminal using the command
docker login. We will be prompted to input our username and password.
To push to Docker Hub, we have to change the tag of our image to include our Docker Hub username. For that, we use the
docker tag command.
docker tag my-adonis-js:1.0.0 username/my-adonis-js:1.0.0
NOTE: This will NOT delete the previous image. If we need to do that we run
docker rmi my-adonis-js:1.0.0
Then we push the image to Docker Hub.
docker push username/my-adonis-js:1.0.0
By default, all repositories on Docker Hub are public. But you can also have private repositories.
Anyone with access to the image on Docker Hub can get it by running
docker pull username/my-adonis-js:1.0.0
There are several other ways of sharing your Docker image.
- If our Dockerfile is hosted on Github or Bitbucket, we can configure an automated build on Docker Hub.
- We can deploy our own docker registry and push/pull images to it instead of Docker Hub.
Running a Docker image
Once we have our image on the machine, we can then run it using
docker run --name=adonis username/my-adonis-js:1.0.0
The above command will spin up a new container based on our image and run it. If we do not pass the
--name parameter, Docker will pick a random name for our container.
Many images require some extra parameters to be passed to the run command, so take some time to read through the documentation of an image before you use it.
Also, take some time to read the full documentation of the
docker run command.
We can see our running containers using the
docker ps command. To see ALL containers, we add the
-a flag -
docker ps -a.
Now, we should be able to see our AdonisJs container up and running! Our team members can also pull the image and run the same application, and if we ever change it, we can just create a new tag for it.
One more thing though. If we actually want to see our AdonisJs website we need to make some changes to our
docker run command.
First, the Adonis server is started inside the container on port 80. We have to map a port on our host machine to port 80 on the container to be able to visit the server. Let's use port 12345.
docker run --name=adonis -p 12345:80 username/my-adonis-js:1.0.0
Now we can visit out AdonisJs site on
Second, we don't just want the base AdonisJs site, we want to be able to edit the files and develop the site. To do this we have to mount a directory onto the working directory of the container. That's the way we configured it :-).
docker run --name=adonis -p 12345:80 -v $PWD/src:/var/www username/my-adonis-js:1.0.0
Now once the container is up, we can view the files in the src folder and edit them. Note that this will not change the image itself. To do that, we can use
docker commit. However, it is more maintainable to use a Dockerfile.
Docker is a very powerful tool, and images are at its very heart. Understanding how to use images are key to making effective use of Docker.
We have been able to build, distribute and run a Docker image. If you have any questions, suggestions, comments, kindly leave them below.
There is so much more to do with Docker. I hope to write more about it. Let me know if there is anything you'd like me to write about.