Containerising a simple JavaScript application using Docker - Part 1
Tags: azure, docker, kubernetes
Published: 2022-08-31 21:51:40

## Introduction

In this tutorial we are going to be taking a simple Javascript application (source code taken from Docker) and running it in a container using Docker.

This is the first of a series of posts on containers. Here is a breakdown of what's to come.

1. Part 1 will look at putting a simple app into a Docker container

2: Part 2 will look at building some persistent storage for our application using Dockeer.

3: Part 3 will look at taking our application we containerised using Docker and putting it into a local Kubernetes deployment using minikube. 

4: Part 4 will look at taking our application and deploying it to an Azure Kubernetes Cluster and exposing it publicly.
 
5: Part 5 will look at adding an ingress controller and WAF in front of our application using Azure Application Gateway.

Docker has grown in adoption since it was first introduced in 2013. Docker engine is by no means the only containerisation technology out in the market. You can use open source tools such as Buildah or Podman to achieve the same results. Docker actually consists of a number of products however it is most commonly known for Docker engine.

The images we are going to be building are of file type .Dockerfile however these are actually OCI images. [OCI](https://opencontainers.org/) or open container initiative is an open source governance structure for creating open industry standards for container formats and runtimes. What this means is that you can any OCI formatted image is generally transportable to any container runtime supporting OCI and not just Docker so you could actually run your image using the [containerd](https://containerd.io/) runtime or a runtime that supports OCI.  

## Containers vs Virtualisation

Before we dive into the tutorial here is a comparison of containers vs virtualisation. In simple terms, containers allow you to run multiple applications on a single operating system on a single server whereas virtualisation allows you to run multiple operating systems on a single physical server. This means containers are portable and lightweight as they do not carry the burden of the operating system. You can run containers either on bare metal servers or more commonly on virtual machines so typically containers run on top of OS virtualisation. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w83zjct2lu2419ttcatc.png)

## Prerequisites

There are some tools required in order to put our sample application into Docker as listed below.

- Docker [Desktop](https://www.docker.com/products/docker-desktop/)

- [WSL2](https://docs.microsoft.com/en-us/windows/wsl/install) if you are using windows. This allows you to run a Linux subsystem if your are using a windows machine. If you are using Mac OS x then this is not required.

- [Git](https://git-scm.com/)

## Putting our app in a container

The application we are going to containerise is a simple to do list built using Javascript. I took the sample code from the Docker docs any take no credit for building it.  

1: Start of by creating a fork of my repository located on [Github](https://github.com/lakovmartin/kubernetes-tutorial). 

2: Clone the repository to your local machine by running `Git clone `

3: Navigate to the `docker/app` directory where you will see the Dockerfile for the application and the source code which we will compile when building the image.

Before we build the image let's breakdown the instructions in the Dockerfile. A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. These are what's used to build our image.

```docker
FROM node:12-alpine
RUN apk add --no-cache python2 g++ make
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
EXPOSE 3000
```
**From** - Here we are specifying an existing image from the public Docker repository to use as a base. 
**Run** - RUN instruction is used to executes any commands on top of the current image and this will create a new layer.
**WORKDIR** - 
**COPY** - COPY instruction is used to copy files, directories and remote URL files to the destination within the filesystem of the Docker Images.
**CMD** - CMD instruction is used to set a command to be executed when running a container. There must be only one CMD in a Dockerfile.
**EXPOSE** - EXPOSE instruction is used to inform about the network ports that the container listens on runtime

**Let's build the image**

4: Run `Docker Build -t todo-list` 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4l12ysoffo0711axyvtd.png)

The image will take a couple minutes to build. Once it's complete we can check the image exists by listing our docker images:

```docker
Docker image ls
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ewk44gdddadeqpz970eq.png)

We can see our image was built successfully and is tagged "latest". We can optionally use semantic versioning. 

5: Let's run the application locally: 

```docker
docker run -dp 3000:3000 todo-list
```
You should now be able to access the to-do list app on `http://localhost:3000/` in your browser.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t1kvokhpn0t2174ckbj9.png)

The `-dp` flag is telling Docker to detach the container and map the application port of 3000 to a local port on our machine and in this it's 3000. You can map the port the application is listening to on any port available on your machine. 

**Next steps**

Currently any items added to the to-list will be removed once the container is stopped. In the next post we will attach some persistent storage to our application that will allow us to persist the items added to the list in local storage when the container is stopped so we don't loose the data.