Docker The Containerization World -Part 2
In the previous blog, we learned basic concepts about docker. This is the link to PART 1 https://medium.com/globant/docker-containerisation-world-basics-part-1-f5abc0b7390b
So far we have been using docker images (busybox, hello-world) that have been built and developed by third parties. Now in this blog, we will learn how to create custom Docker images on our own. To achieve this we make use of docker files.
We are going to create a simple node js web application using docker and access this with the browser. Refer to the below image.
We follow the below steps to create the node js web application using docker.
- First, we create the Node JS server-side application. For that, we make the directory and then create the package.json file inside that directory and add the contents below.
{
"name": "simple-web",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"express": "^4.18.1"
}
}
- Then create an index.js file in the same directory. This file is the entry point that listens to the incoming requests. Add the below contents to it.
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(5000, ()=> {
console.log("listening on port 5000");
});
- In the above image, we have imported the express library which has been added to the package.json file as a dependency. Using this library we create the server.
app.get
is going to handle get request, like this we can also use other HTTP methods as well.app.listen
listens to the port 5000. - We have done creating the Node js application. Now it’s time to create Dockerfile which is responsible for running this nodejs application as a separate container. So let’s add the below contents to the Dockerfile.
# Specify a base image
FROM node:alpine#Create a dicrectory inside the container
WORKDIR usr/app#Copy package.json file to container
COPY ./package.json ./# Install some dependencies
RUN npm install# COPY rest of the files to container
COPY ./ ./# Default command to the container startup
CMD ["npm", "start"]
Let’s understand each line of Dockerfile
Specify a base image
- We use From keyword at the beginning of the Dockerfile to mention the image name, So here the image name is a node. After that, we put semicolons(:) to define the version. Here we use an alpine version of node. The alpine version is compact in nature and it is 5MB in size. We use the alpine version image because we want our container to have a smaller size. You can use other node versions as well at the docker hub. But those versions might be bigger in size compared to alpine.
Create a directory inside the container
- WORKDIR keyword we use to create the working directory inside the container. Here the usr directory is a part of the file system. Under this, we create the app directory.
Copy the package.json file to the container
- Here we copy the package.json file from the current working directory to the container’s directory which is an app that we created in step 2.
Install some dependency
- Here we install the dependency using
npm install
the command under the container. So that it will generate the node_modules in the same directory.
Copy the rest of the files to the container
- Now we copy the rest of the files to the container. In our case, we have only the index.js file which is our server. Here the first ./ means the source directory and the second ./ means the destination directory.
Default command to the container startup
- As we already learned about the startup commands in the previous blog. So here we are adding the
["npm", "start"]
command with CMD keyword.
In the end, our project architecture should look like this
Build docker image
- To build a docker image using Dockerfile we use the command
docker build .
, please notice the dot period after the build keyword. The dot basically tells docker that the Dockerfile that has to be used is in the current directory. We need to tag our image with some name using the flag called -t. - The final command to run on the root level will be
docker build -t simple-web .
- We have successfully created the image. And now it's time to run the image. Use
docker run <image-name>
. In our case we usedocker run simple-web
. When we do this, the file system of the image simple-web will get copied to a separate container. We have learned in the previous blog how it works internally. The below image shows how this container looks after we run the commanddocker run simple-web
.
- In the above diagram, we can see our custom simple-web image and its file system. Also, the container that is created when we run the image
docker run simple-web
. This will display the below output on the terminal.
- Now the server is running on port 5000. Open the browser and enter the URL localhost:5000.
- It is unable to reach port 5000. Because our node js application is running under the container. So it is unable to load the application on the browser. Now we will understand why the application is not reachable with the below diagram.
- The browser makes the request to the localhost on port 5000. So wherever a request comes to localhost 5000, it will get routed to the container. The container has its own isolated set of ports that can receive traffic from the outer world. So now by default no request coming from your machines localhost to the container’s network.
- Here comes the way using which we expose our application from the container to the outside world. To achieve this we have to do the port mapping with the -p flag explicitly.
- Run the command again
docker run -p 5000:5000 simple-web
. Once you hit the command on the terminal, you can see again same output on the screen. Then go to the browser and type localhost:5000 again. Now you could able to make the request to the container.
- Here is the diagram which shows the port mapping to the container.
Conclusion
We have successfully completed the basic node js application with Dockerfile. This is called a single container application. In the upcoming blog, we will be learning how we can achieve multi-container with docker.
If you have any queries then feel free to add them in the comments section.