Skip to content
jbellver99 edited this page May 13, 2021 · 13 revisions

In this section we will see everything related to Docker, from the installation of Docker in our local machine to the creation of images from a Dockerfile and the creation of docker-compose files for the deployment of our containers.

What is Docker?

The idea behind Docker is to create light and portable containers for the software applications that can be executed in any machine with Docker installed, independently of the operating system that the machine is working with, facilitating also the deployments.

Docker allows me to put into a container everything that my application needs in order to be executed. So, I can take this container to any machine with Docker installed and execute my application with no need of doing anything else. I will execute mi application from the Docker container, and inside of it I will find all the libraries and things that my application needs in order to work correctly.

Installing Docker in our machine

The first thing that we need in order to create and launch our Docker images is installing Docker's application from its web page, available in the following link. Once we have the file downloaded, we will make double click on it to execute the installer. Just follow the steps in the wizard installer until the installation is finished.

Now we have Docker installed in our machine, but if we try to execute it the Docker server would not be able to connect as we need to install a Linux subsystem in our computer. For this we will follow this steps:

1. Enabling the Windows subsystem for Linux

Open PowerShell as administrator and execute the following order:

dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart

2. Enabling the virtual machine feature

Open PowerShell as administrator and execute:

dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

Restart the machine to complete the WSL installation and the WSL2 update.

3. Linux kernel update package download

  1. Download the latest version: https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi

  2. Execute the update package downloaded in the previous step. (Double click on it to execute the package. Elevated permits will be asked. Select "Yes" to approve the installation).

4. Defining WSL 2 as the default version

Open PowerShell as administrator and execute the following order to establish the WSL 2 version as the predefined when installing a new Linux distribution:

wsl --set-default-version 2

5. Install of the Linux distribution that you want

  1. Open Microsoft Store and select your favorite Linux distribution.

  2. In the distribution page, select "Get".

  3. Start the distribution, you will have to create a username and a password for the new Linux distribution.

Once the Linux distribution is installed, simply restart the Docker application and you will be able to see that the server is now "Running".

Creating images using a Dockerfile

Now that we have Docker installed in our machine and it works correctly, we are going to start creating the images of our application.

In order to create this images we are going to use some files called "Dockerfiles" which we will need to create. We will need to create a Dockerfile for the Angular side of our application and another Dockerfile for the Java side. We will be starting with the fron-end part.

Dockerfile Angular

First, what we need to do is place ourselves in the angular directory of our project.

C:\...\workspaces\main\jumpthequeue\angular

Here, we are going to create a new file called Dockerfile, without any extension. Inside C:\...\worspaces\main\jumpthequeue\angular\Dockerfile we will add the following code:

FROM node:10-alpine as build-step
RUN mkdir -p /app
WORKDIR /app
COPY package.json /app
RUN npm install
COPY . /app
RUN npm run build

#NGINX
FROM nginx:latest
COPY --from=build-step /app/dist/angular /usr/share/nginx/html

Now we are going to explain what each of these orders do:

  1. FROM Specifies the Docker image that we are going to use (node:10-alpine).
  2. RUN Executes the specified. In this case: mkdir -p /app (create a new directory).
  3. WORKDIR Specifies the directory where we are going to work. In this case the directory that we have just created.
  4. COPY Executes the copy order. In our case we are copying the file package.json from the application into the new work directory.
  5. RUN Executes the order npm install in order to install the application dependencies.
  6. COPY Executes the order of copying everything that is the actual directory into the new directory.
  7. RUN Executes the order npm run build. Which creates a folder called dist with all the compiled classes of our application.
  8. FROM Specifies that we are now going to use the image nginx:latest (as it is the server that we will use to launch our application).
  9. COPY Copies all the code in the folder /app/dist/angular into the folder where the nginx web application are stored.

Now that we have our Dockerfile done, the following step is to build our Docker image. For doing this we will need to be inside the directory where the Dockerfile is located and execute the following order in our terminal:

docker build -t jump-the-queue/angular .

ℹ️ The -t option in the order specifies how you do you want to name the image.

Once the order finishes its execution, we can check that the image has been created successfully in the "Images" tab inside our Docker application:

ℹ️ We can also check the Docker images by executing the order: docker images.

Dockerfile Java

Now it is time to create the Dockerfile for our back-end side. First of all we will go into the directory where our Java application is located C:\...\worspaces\main\jumpthequeue\java and create, as we did before, the Dockerfile. This time the Dockerfile will look a bit different, inside the Dockerfile we will write:

FROM maven:3.6-jdk-11 AS build
WORKDIR /app
COPY jtqj/ /app
RUN mvn clean install

FROM adoptopenjdk/openjdk11:jre-11.0.4_11-alpine
WORKDIR /app
COPY --from=build /app/server/target/jtqj-server-bootified.war /app/jumpthequeue.war
ENTRYPOINT ["java","-jar","/app/jumpthequeue.war"]
EXPOSE 8081

What this Dockerfile does is:

  1. FROM Specifies the image that we are going to use (maven:3.6-jdk-11).
  2. WORKDIR We specify the working directory (app).
  3. COPY We copy everything inside jtqj/ into the working directory.
  4. RUN We execute the order mvn clean install to build our application.
  5. FROM We specify that we are now going to use the image adoptopenjdk/openjdk11:jre-11.0.4_11-alpine.
  6. WORKDIR We specify the working directory.
  7. COPY We copy the war file created when executing he order mvn clean install into the working directory.
  8. ENTRYPOINT We execute the Java application that we have just copied.
  9. EXPOSE We indicate in which port of our computer the application will be executed.

Now, as we did before with the Angular side, we will execute the Docker order to build our image:

docker build -t jump-the-queue/java .

Once it is finished, we can check that the image was correctly created:

Creating the containers

After creating the images for both parts of our application we are going to create the corresponding Docker containers in order to launch our application. Inside our machines terminal we will execute the following orders:

docker run --name jump-the-queue-angular -p 80:80 -d jump-the-queue/angular

docker run --name jump-the-queue-java -p 8081:8080 -d jump-the-queue/java

What this does is creating a container based on the image that we specify at the end of the order. The --name option is for setting the name of our container, the -p option is for exposing the ports where our application will be launched and the -d option is for running our containers in the background.

Once the execution is finished we can see that our containers are correctly built in our Docker application or executing the order: docker container ls.

Now to check that everything is working correctly we can access our application in our web browser in the following urls:

http://localhost:80 for the Angular side.

http://localhost:8081/jumpthequeue for the Java side.

Creating a reverse proxy

What we are going to create now is a reverse proxy using a "docker-compose.yml" file. This will allow us to build and launch both containers at the same time and make them accessible in the same port.

For making this, we will place ourselves in the main directory of our application (C:\...\workspaces\main\jumpthequeue) and we will create a file called "docker-compose.yml". Inside this file we will add the following code:

version: '3'

services:
    reverse-proxy:
        build: 'reverse-proxy/'
        container_name: 'jtq_reverse_proxy'
        image: jump-the-queue/reverse-proxy:latest
        ports:
            - '80:80'
            - '443:80'
        networks:
            - jump-the-queue
        depends_on:
            - java
            - angular

    angular:
        build: 'angular/'
        container_name: 'jtq_angular'
        image: jump-the-queue/angular:latest
        networks:
            - jump-the-queue

    java:
        build: 'java/'
        container_name: 'jtq_java'
        image: jump-the-queue/java:latest
        networks:
            - jump-the-queue

networks:
    jump-the-queue:
        driver: bridge

What we are doing here is telling Docker that we want to create three services (containers), one for our angular part, one for our java part and one named "reverse-proxy" which is going to depend on the other two services and is going to specify the ports where we want to launch our application. All of these services will be connected to the same network that we have create called "jump-the-queue".

Before executing this file, we need to create first a Dockerfile for our reverse-proxy service. Inside the main directory of our application we will create a new folder called "reverse-proxy" where we are going to add the following files:

  1. Dockerfile:
FROM nginx:latest

COPY nginx.conf /etc/nginx/conf.d/default.conf

A Dockerfile which uses the image nginx:latest (as it is going to be our server) and a COPY instruction which is going to copy a file named nginx.conf into the configuration folder of our nginx.

  1. nginx.conf:
server {
    server_name _;
    root /usr/share/nginx/html;

        location / {
            proxy_pass http://angular:80;
            proxy_http_version  1.1;
            proxy_cache_bypass  $http_upgrade;

            proxy_set_header Upgrade            $http_upgrade;
            proxy_set_header Connection         "upgrade";
            proxy_set_header Host               $host;
            proxy_set_header X-Real-Ip          $remote_addr;
            proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto  $scheme;
            proxy_set_header X-Forwarded-Host   $host;
            proxy_set_header X-Forwarded-Port   $server_port;
        }

        location /api {
            proxy_pass http://java:8081/jumpthequeue;
            proxy_http_version  1.1;
            proxy_cache_bypass  $http_upgrade;

            proxy_set_header Upgrade            $http_upgrade;
            proxy_set_header Connection         "upgrade";
            proxy_set_header Host               $host;
            proxy_set_header X-Real-Ip          $remote_addr;
            proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto  $scheme;
            proxy_set_header X-Forwarded-Host   $host;
            proxy_set_header X-Forwarded_Port   $server_port;
        }
}

In this file what we specify is that when the user searches for the url http://localhost the Angular part of our app should show up and if the user searches for http://localhost/api the Java part of our app should show up.

Now that we have all the files prepared lets get into launching our reverse proxy. Inside the directory where we created the docker-compose file (C:\...\workspaces\main\jumpthequeue) we will execute the following order:

docker-compose up -d

ℹ️ Just as mentioned before the -d option is for running the container in the background.

Once the order finishes its execution we can check that a new container with the three services is made:

Now we are able to access our application just by entering http://localhost for the Angular part and http://localhost/api for the Java part, without the need of specifying any port.

Saving Docker images into files and uploading these files into Docker

The last thing that we will see about Docker is how to save our images into files and how we can upload again this files into Docker.

Docker save instruction

For saving our images in .tar files what we will do is, first of all place ourselves in the directory where we want to save them and then we will execute the following order:

docker save -o angular-image.tar jump-the-queue/angular (For the Angular image).

docker save -o java-image.tar jump-the-queue/java (For the Java image).

docker save -o reverse-proxy-image.tar jump-the-queue/reverse-proxy (For the reverse proxy image).

We can check in the directory where we executed this instruction that our .tar files with our images have been created.

Docker load instruction

Now, for loading our files again into our Docker we will execute the following order in the directory where our .tar files are located, but first we will delete from our Docker the images that we have created in order to assure that the loading is done correctly.

docker load -i angular-image.tar (For the Angular image).

docker load -i java-image.tar (For the Java image).

docker load -i reverse-proxy-image.tar (For the reverse-proxy image).

Once the execution of the instructions is finished, we can check inside our Docker application that the images have been successfully loaded.


Next Chapter: SonarQube