Dockerizing Node
- Part 1: Running Node Application in Docker Container on Raspberry Pi
- Part 2: Dockerfile
- Part 3: Dockerizing Mongo and Express
- Part 4: docker-compose
- Part 5: Rancher–First Application
Now that we are familiar with the Docker and how it helps us in high isolation and compartmentalization; lets expand and try out deploying some real world application. I will be using the application that we built for MongoDB and Mongoose; its an Express JS / MongoDB application and we will try deploying it across two Docker containers; one for MongoDB and the other for Express in spirit of Microservice Architecture. As per wikipedia; Microservices are a more concrete and modern interpretation of service-oriented architectures (SOA) used to build distributed software systems. Like in SOA, services in a microservice architecture are processes that communicate with each other over the network in order to fulfill a goal. Also, like in SOA, these services use technology agnostic protocols. Using separate Container for each microservice; we get fine control and can monitor and distribute components of our application at each microservice level.
For MongoDB; lets start an Ubuntu instance; install Mongo and try to run it; we will learn that it needs /data/db directory
We can create that in the container but as we know that when container is stopped it loses the data. Its recommended to use Data Volume for such requirement and we will mount one as /data/db. Lets create a Dockerfile for our MongoDB container
FROM ubuntu
MAINTAINER Khurram <khuziz@hotmail.com>RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv EA312927
RUN echo "deb http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.2 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-3.2.list
RUN apt-get update && apt-get install -y mongodb-orgEXPOSE 27017
ENTRYPOINT ["/usr/bin/mongod"]
Lets create a Dockerfile for the Node JS as well; we will not be including the application code in the Node JS container instead we will use Data Volume for the application files. Note that Node is not being run as ENTRYPOINT or CMD; we will be starting it as a parameter to the container in docker run command and pass the start up JS file as the parameter; this way we can reuse our Node JS container image for different applications; scenarios like running web service in its own container and front end application in separate container
FROM ubuntu
MAINTAINER Khurram <khuziz@hotmail.com>RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y nodejs
RUN apt-get install -y build-essential
RUN apt-get install -y npm
To build the container images; give commands
docker build -t khurram/node -f Dockerfile.node .
docker build -t khurram/mongo -f Dockerfile.mongodb .
- I have kept different name for the Dockerfile for our containers; as these names are not standard I am passing the file name using –f argument; its done so that I can have both files in one directory
- Its better to make a BAT / SH script for above commands
Before running the two docker containers; we need two data volumes, one for Mongo and the other for Node application. For the Node application we will use host directory; in our case the directory in Boot2Docker VM; we will use cifs-utils to mount the folder from Windows HyperV Host sharing it on network as discussed in Docker on Windows- Customized Boot2Docker ISO with CIFS; from there on it can act as a host directory in Docker VM and we can use it for data volume. Unfortunately we cant use this arrangement for Mongo as it expects certain features from the file system (for its data locking etc) and mounted directory using cifs-utils doesnt have these features, therefore we will create a volume using docker and use it instead
docker volume create --name mongo-data
mongo-datadocker volume inspect mongo-data
[
{
"Name": "mongo-data",
"Driver": "local",
"Mountpoint": "/mnt/sda1/var/lib/docker/volumes/mongo-data/_data",
"Labels": {}
}
]
To start the Mongo container issue this command
docker run -d -p 27017:27017 -v mongo-data:/data/db --name mongodb khurram/mongo
- The above created mongo-data volume is passed using –v argument
- Its mounted as /data/db in the container as required by the Mongo we learned by installing it in a test container
- The Mongo port is exposed; we can test by connecting to Docker VM from the development machine!
Docker has a Linking feature; using which we can link one or more containers to particular container while starting it; doing so it adds /etc/hosts entry as well as set Environment Variables. Its important that the linking container is given proper name; you will see that /etc/hosts entry and environment variables all depends on it. Lets start the khurram/node instance linking mongodb container that we already have started!
docker run -it -v /mnt/srcshare/HelloExpress:/app --link mongodb:mongodb --name helloexpress khurram/node
root@7be354a7e084:/# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 mongodb 75e912d09a6c
172.17.0.3 7be354a7e084
root@7be354a7e084:/# set
BASH=/bin/bash
….
MONGODB_NAME=/helloexpress/mongodb
MONGODB_PORT=tcp://172.17.0.2:27017
MONGODB_PORT_27017_TCP=tcp://172.17.0.2:27017
MONGODB_PORT_27017_TCP_ADDR=172.17.0.2
MONGODB_PORT_27017_TCP_PORT=27017
MONGODB_PORT_27017_TCP_PROTO=tcp
…
UID=0
_=/etc/hosts
root@7be354a7e084:/# cd /app/
root@7be354a7e084:/app# ls
DockerBuild.bat DockerRun.bat Dockerfile.node HelloExpress.sln bin node_modules package.json routes
Dockerfile.mongodb HelloExpress.njsproj app.js models obj public views
- Given it has added /etc/hosts entry; we can simply access the mongodb server with the name in connection string for mongoose.connect() call
- Note that the information about the mongodb’s exposed port is also available in the environment variables
- Note that the cifs mounted “local” directory is mounted as volume in the container and we can access its content accordingly
Once the data volumes are in place; and container linking is understood and app.js is updated accordingly for mongoose.connect(); lets clean up and start the fresh instances of our containers
docker stop mongodb
docker stop helloexpressdocker rm mongodb
docker rm helloexpressdocker run -d -v mongo-data:/data/db --name mongodb khurram/mongo
docker run -d -p 3000:3000 -v /mnt/srcshare/HelloExpress:/app --link mongodb:mongodb --name helloexpress khurram/node nodejs /app/bin/www
- Its better to make a BAT / SH script for the above commands
Code @ https://github.com/khurram-aziz/HelloExpress is updated accordingly having the DockerBuild.bat, DockerRun.bat and Dockerfiles for Mongo and Node
Resources
- https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/
- https://docs.docker.com/engine/examples/mongodb/
- https://docs.docker.com/engine/tutorials/dockervolumes/
- https://docs.docker.com/engine/reference/commandline/volume_create/
- https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/