/ docker

Containerizing a Web App

Devout rollBak followers may remember a previous web app tutorial I created here. Well in this tutorial, I'll be containerizing that same "hello world" application so you can "ship" it to your friends, colleagues, and mom!

Prerequisite:

To create the container, I'll be using Docker. Please install and configure Docker on your machine.

Alright time to quickly recap how the previous web app works. The web app is built using node.js and simply returns "hello world" when you access it from a browser. It also spits out a console message indicating that it is running.

The two files you need from my previous project are app.js and package.json.

app.js:

var express = require("express");
var app = express();

app.get("/", function(req,res){
    res.send("Phil says: hello world, im in a container!");
});

app.listen(80, process.env.IP, function(req,res){
    console.log("####################");
    console.log("## SERVER STARTED ##");
    console.log("####################");
});

** NOTE: I edited the output message so that it says "Phil says: hello world, im in a container! **

package.json:

{
  "name": "app",
  "version": "1.0.0",
  "description": "container test project",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Phil Afable",
  "license": "ISC",
  "dependencies": {
    "express": "^4.16.4"
  }
}

Creating a Dockerfile

Onwards to new content! Time to create a dockerfile, this dockerfile will function as the recipe that will guide Docker on how to create an image for my container.

Essentially I want Docker to create the image with the following instructions below:

  1. Use a base container
  2. Create an app directory in the container
  3. Copy the app.js and package.json to the container's app directory
  4. Install dependencies on the container
  5. Use the command specified once the container is up and running

To find a docker image running node, I visited docker hub and found a node docker image. I will be using this as the base image for my container. For the app directory I'll create a directory called app. Also I'll need to run npm install to download and install the dependencies, the only dependency my app needs is express.

So my dockerfile will look like this:

# Use node docker container as a base (preferrably node:alpine)
FROM node:alpine

# Create a working dir in the container for the app
WORKDIR /app

# Add package.json file into container
COPY ./app.js ./
COPY ./package.json ./

# Download and install a dependency
RUN npm install

# Tell the image what to do when it starts as a container
CMD ["node", "app.js"]

FROM will tell docker to use the node alpine image as a base image. Docker will create a directory called /app with the WORKDIR line. Then it will copy the files, app.js and package.json into the /app directory inside of the container image with the COPY line. The RUN line will execute the npm install command during the creation process of the container, it will pull down the dependency (express) for this web app to function. CMD ["node", "app.js"] will tell the container to run the command node app.js as soon as the container is created.

Creating the Docker Image

On my local machine I put all of the files (app.js, package.json and Dockerfile) in a directory called myapp.

[scleft@ubuntu myapp]# ls
app.js  Dockerfile  package.json

To build the docker image, I will execute the docker build command inside of the myapp directory.

docker build -t myapp_image:1.0 .

The -t flag will build the image and give it a name of "myapp_image" with a tag "1.0". The . is the build context, docker will takes all files located in the directory as inputs.

Once you run the docker build command, you will see the following:

Sending build context to Docker daemon  104.4kB
Step 1/6 : FROM node:alpine
 ---> ebbf98230a82
Step 2/6 : WORKDIR /app
 ---> Running in 0dc6b76835cd
Removing intermediate container 0dc6b76835cd
 ---> d8f2273cb37f
Step 3/6 : COPY ./app.js ./
 ---> fa8803074bd6
Step 4/6 : COPY ./package.json ./
 ---> ff78e501b938
Step 5/6 : RUN npm install
 ---> Running in 910ded91a350
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN app@1.0.0 No repository field.

added 48 packages from 36 contributors and audited 121 packages in 1.534s
found 0 vulnerabilities

Removing intermediate container 910ded91a350
 ---> 9037b7c774a2
Step 6/6 : CMD ["node", "app.js"]
 ---> Running in 5ed912f3fe65
Removing intermediate container 5ed912f3fe65
 ---> 76c3d009b097
Successfully built 76c3d009b097
Successfully tagged myapp_image:1.0

If you see Successfully built then your image build completed! To check the docker images on your machine use the docker images command. You should see something like below:

REPOSITORY                  TAG                 IMAGE ID            CREATED             SIZE
myapp_image		    1.0                 76c3d009b097        About an hour ago   76.7MB
node                        latest              dd913630b38a        15 hours ago        916MB

Creating Docker Container

Now that we have the image, let's create the container. To create the container use the docker run command. I'll add the --name option to give the container a name instead of using a default docker container name. Secondly, I'll use the -p option to specify a port to map the container to the outside world. Below I mapped the port 9001 to the internal container port of 80 since the app is listening on port 80. Also port 9001 was an arbitrary port, you can specify whatever port number you prefer. Lastly 76c3d009b097 is the image ID assigned to my newly created image.

docker run --name myapp_container -p 9001:80 76c3d009b097

Once you execute the docker run command, you should see the console log message appear in your terminal.

[scleft@ubuntu myapp]# docker run --name myapp_container -p 9001:80 76c3d009b097
####################
## SERVER STARTED ##
####################

Now comes the real test, let's check out our work on a browser...

Open up your favorite browser and go to the IP address of your machine or use localhost. I went with the IP address because my docker environment is running on a virtual machine. Which ever you use, don't forget to specify port 9001!

Yay it worked! The little node.js web app is now running inside of a container!

View the github project here:

https://github.com/pafable/containerapp.git

Containerizing a Web App
Share this