Docker basics: building a simple docker image

Introduction

Docker is all about image, at least for me. You can't use docker properly until you can build your own docker image.

So let's say that docker image is like a package. No matter where you open it, the content will always be the same. As long as you don't change the content and re-pack it, the content will always the same. If you give the package to someone else, they will also get the same content. This may be over-simplify it, but this analogy helps me to understand docker image clearly.

Preparing the app

I'm going to create a javascript web app using express-generator, so at least you have NPM installed on your computer machine.

If you already have express-generator installed globally, just go to your whichever directory on your computer (empty directory is more preferred), and run this command on your terminal:

express

This command will at least generate a basic file and design pattern in order to run your web app. After that, you also need to run this command to install all needed package and run the app on your localhost:

npm install && npm start

The command npm install will going to install all the package in your package.json file, and npm start will going to run the web app in your localhost.

The express-generator will by default run your web app on the port 3000. So go and open your browser and access localhost:3000 in your browser.

Dockerfile

I gonna assumed that you already have docker installed on your computer.

So in order to build the image from the code that express-generator generate for us, we have to make Dockerfile.

Dockerfile (without any extension), is a text document that contains the list of all commands needed in order for docker to make their image. This is the reason why we have to make sure that our web app is running first in our localhost before building the docker image. Because we first have to know all the command we need in order to run our app.

We already know that all you have to do is just install all the library using the command npm install and start the app using the command npm start. But how do we write that as an instruction in our Dockerfile ?

Well, first let assume that we have a brand new PC/Laptop/Computer for our developer work. We just bought it, and it still doesn't have any program installed in order to run our program. In this case, it is node. So, in order to run our program, we first have to install it right ? and that's what we're going to do.

Our docker image is the same as a brand new PC without any program, you just can't do anything with it, let alone running our app. So, first of all, we have to install it. In Dockerfile we have to search for base image to run our app. As our web app is using node, so we're going to use base node image in order to do that. You can see all official base image available here.

What is a base image ? well, basically base image is an image that we'll going to use in order to create our app image. Ironically, we already using an image in order to create another image.

For this, we'll going to use the node image from docker hub. It's an official image supported by node themselves, so you don't have to worry about the support. So, from this base image, we're going to write our Dockerfile.

FROM node:lts-alpine

WORKDIR /APP

COPY . /APP

RUN npm install

CMD ["npm", "start"]

This is all the instruction that docker will need in order to create our image.

Firstly, we're going to install our base image using FROM command. the node:lts-alpine is our base image. It's going to install the latest node version. By the way, you can also specify the node version. For example, please use the node:alpine3.10 in order to use node version 15.7.0. Please refer to the official base image in order to specify other version. It is considered bad practice to just use the latest version in every build.

Secondly, we're telling docker to use /APP directory as our main program directory. using WORKDIR command. It will create an APP directory in our program.

After that, we're just going to run the command npm install using the RUN command and running our program using the command npm start using CMD command.

This will mark as the end of our Dockerfile. After that we'll going to learn how to build the docker image using the Dockerfile that we just created.

Building the docker image

In order to build the docker image, firstly we have to had docker engine installed on our machine. You can install it from the docker official site.

Using docker engine, we're going to use the docker-cli in order to access the API that docker have and interact with the machine. In order to see all the command that docker engine have, you just have to type docker -h in your terminal and all the available command will be shown to you. If you focus for a bit, in commands section you'll see that docker have a build command, and we're going to use that command.

The docker build command also have some options that you can use. You can check them out using command docker build -h. And now we're going to build the image using the command

docker build -t express-app .

That command will build the docker image for us using the Dockerfile that we just created.

The -t option there means tag, it means that we're giving tag to our build image. In here, the name of our image will be express-g and the tag will be latest. Why our tag is latest ? we don't specify our tag there since our image name doesn't have a tag in it, docker will build the image tag as latest. If you want to specify the tag, you can give something line express-app:1.0 to our -t option and the tag will be 1.0.

The . in the end of our command is to specify the path to our Dockerfile. Since we're gonna run this command inside the directory that have our Dockerfile in it, you just have to write . at the end of our command like that. If you want to specify the path, you can just use /path/directory.

After running that command, our docker image will be built using the Dockerfile. You can check our image list using the command

docker image ls

That command will list all of your docker image that you've built or download. After this we just have to run the image that we've just built.

Running docker image

This is the last part and the simplest part of this tutorial.

So, in order to run our image, you just have to run this command:

docker run -d -p 8000:3000 express-g

First of all, if you want to run the specific tag of an image, please specify it like express-g:1.0.

-d in the command means detach, it means to run the image in the background.

-p in the command means publish, it means to publish the port 3000 in our image (or program) to the port 8000 of our computer.

If the command is success, it will return the container ID. But first you have to realize that when you go to your browser and open localhost:3000, it will fail. Why ? because we already mapped it to port 8000. So in order to access our app, we use port 8000. So open localhost:8000 to see our app running.

And if you want to see all the running image that you have (we call it containers). You can just type this command in your terminal:

docker container ls

It will list all the container that is running, the port, and the container status.

Conclusion

This is only a simple tutorial on how to write Dockerfile, create docker image using it, and run it. On real-life app, it should not be like this. We have databases, networking, etc, that we have to consider. But i'd say that this is a good introduction to create and run docker image.