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

Lets run a Node application in Docker on Raspberry Pi; for the proof of concept; I will be using a simple hello world app and a GIT/SSH setup we made in Staging Node Application on Raspberry Pi. The Docker way of running the application is that we have our “data” and “application” files outside of the container; so that container remains completely disposable. When running the container; we can mount the directory from the Host OS; using this feature we can have our data and application files on the Host OS and they are being used from the Container; something like this:

We can continue to have the GIT / NGINX arrangements that we did in Staging Node Application on Raspberry Pi; but now we can run Node and MongoDB (and others) from Containers. We already have made the Node Docker image in the Docker on Raspberry Pi; all we need is to run is so that we mount /home/pi/hello directory into the Node Container and run Node in the Container, doing so we will have the Node server at container’s 3000 port, expose this port to the Host OS’s 3000 port so that NGINX forwards the request to Host OS’s 3000 port when it receive any request at Host OS’ http://ip/node endpoint
pi@raspberrypi:~ $ docker images      
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE       
khurram/pi           node                6af338545368        5 hours ago         159 MB       
khurram/pi           nano                99f0053b387e        6 hours ago         105.6 MB       
resin/rpi-raspbian   jessie              80a737f1a654        7 days ago          80.01 MB       
pi@raspberrypi:~ $ cd hello       
pi@raspberrypi:~/hello $ ls       
hello.js       
pi@raspberrypi:~/hello $ docker run -p 3000:3000 -v /home/pi/hello:/hello -it khurram/pi:node       
root@381ece8ec01a:/# cd /hello       
root@381ece8ec01a:/hello# ls       
hello.js       
root@381ece8ec01a:/hello# nodejs hello.js       
Server running at port 3000
- -p 3000:3000 is to expose container’s 3000 port and map it to Host OS’s 3000; the port of container where node application will run in the container and host os port where nginx is expected to forward the requests
- -v localpath:remotepath is to mount the Host OS’s localpath directory as a remotepath in the container
- -it is for interactive terminal
- khurram/pi:node is the Node image we created
Once the container is running and we are on its terminal; we can start our node app; we have to leave the terminal running so Node server continue to run; and from another terminal we can issue docker ps to get the list of all the running container
pi@raspberrypi:~ $ docker ps      
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES       
381ece8ec01a        khurram/pi:node     "/bin/bash"         2 minutes ago       Up 2 minutes        0.0.0.0:3000->3000/tcp   goofy_khorana
- Note; how the ports are mapped
- Note the NAMES column; Docker has named our container “dynamically”
We can try http://ip:3000 and http://ip/node URL and our node application should be running there; using the Container Name or Container ID we can stop it. We can issue docker ps –a to list all the containers including those that are stopped
pi@raspberrypi:~ $ docker stop goofy_khorana      
goofy_khorana       
pi@raspberrypi:~ $ docker ps       
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES       
pi@raspberrypi:~ $ docker ps -a       
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS                       PORTS               NAMES       
381ece8ec01a        khurram/pi:node             "/bin/bash"              9 minutes ago       Exited (130) 9 seconds ago                       goofy_khorana       
aece7089082d        khurram/pi:node             "-p 3000:3000 -v /hom"   10 minutes ago      Created                                          determined_colden       
e5e7005489a2        khurram/pi:nano             "/bin/bash"              6 hours ago         Exited (0) 5 hours ago                           grave_pasteur       
5b62a2d14818        resin/rpi-raspbian:jessie   "/bin/bash"              6 hours ago         Exited (0) 6 hours ago                           tiny_feynman       
As you can see; our Containers are also getting stored on the Host OS; think of it as the Working Directory in the source control; the server will have code images that we commit and working directory has currently working copy of source code; similarly docker images are the images of container that we committed and containers are the running (or stopped) copies, they also eats up the disk and we should remove the unwanted one; keeping an eye on STATUS we can learn which one we are not using anymore and can remove them using docker rm
pi@raspberrypi:~ $ docker rm goofy_khorana      
goofy_khorana       
pi@raspberrypi:~ $ docker rm aece7089082d       
aece7089082d
We dont always have to get the interactive shell on starting container; if we know what command to run when container is running; we can start our container in the background giving the command to run as parameter; lets create a new container for our Node application (as we have deleted the previously created one) from the Docker Image; something like this
pi@raspberrypi:~ $ docker run -d -p 3000:3000 -v /home/pi/hello:/hello khurram/pi:node nodejs /hello/hello.js      
49b347531127cc1d6c07f9b266e9e146afa0c4214c3c13514b7a851a444c525e       
pi@raspberrypi:~ $ docker ps -a       
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES       
49b347531127        khurram/pi:node     "nodejs /hello/hello."   9 seconds ago       Up 3 seconds        0.0.0.0:3000->3000/tcp   stupefied_wing       
pi@raspberrypi:~ $ curl http://localhost/node     
Hello World from NODE in Container      
Restarting Container
Now if we reboot the Raspberry; and give docker ps –a when it comes back; you will notice that our Container is not running anymore
pi@raspberrypi:~ $ docker ps -a      
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                            PORTS               NAMES       
49b347531127        khurram/pi:node     "nodejs /hello/hello."   2 minutes ago       Exited (143) About a minute ago                       stupefied_wing
This can be taken care using –restart=always as the paramter to docker run; with this; even if our container exits unexpectedly; Docker will restart it; and also start it when machine boots (Docker Daemon gets started)
pi@raspberrypi:~ $ docker run --restart=always -d -p 3000:3000 -v /home/pi/hello:/hello -it khurram/pi:node nodejs /hello/hello.js      
575b6cf68407fb08bf0fae895ea1170f5cbc02fba596f903c1901e17aa859747       
pi@raspberrypi:~ $ curl http://localhost/node     
Hello World from NODE in Container      
pi@raspberrypi:~ $ sudo shutdown -r now
Using docker ps we can see that the second container that we started with restart=always is running on the boot!
pi@raspberrypi:~ $ docker ps -a      
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS                       PORTS                    NAMES       
575b6cf68407        khurram/pi:node     "nodejs /hello/hello."   About a minute ago   Up 4 seconds                 0.0.0.0:3000->3000/tcp   serene_mirz       
49b347531127        khurram/pi:node     "nodejs /hello/hello."   6 minutes ago        Exited (143) 5 minutes ago                            stupefied_w       
pi@raspberrypi:~ $ curl http://localhost/node     
Hello World from NODE in Container
We can delete the previous container using docker rm, and if we want to protect the Container ports being exposed on Host; we can use iptables!
Restarting Container on changing application files
We know that we need to restart the node process when application files are changed. In this case; we simply can restart the Docker Container, it takes almost the same time. This can be done using docker restart command; but we need to "know" the container name at runtime so that we can use it in our post-receive GIT script; i-e when new code is “pushed” the GIT hook can restart the container. We can have a static known name for our container if we run the container with –name parameter
pi@raspberrypi:~ $ docker ps -a     
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES      
575b6cf68407        khurram/pi:node     "nodejs /hello/hello."   3 hours ago         Up 3 hours          0.0.0.0:3000->3000/tcp   serene_mirzakhani      
pi@raspberrypi:~ $ docker stop 575b6cf68407      
575b6cf68407      
pi@raspberrypi:~ $ docker rm 575b6cf68407      
575b6cf68407      
pi@raspberrypi:~ $ docker run --restart=always --name hello -d -p 3000:3000 -v /home/pi/hello:/hello -it khurram/pi:node nodejs /hello/hello.js      
6774bc75b25e584b9f132bf78894a90789180d868c3176593b96e3f426db4118      
pi@raspberrypi:~ $ curl http://localhost/node    
Hello World from NODE in Container     
pi@raspberrypi:~ $ docker restart hello     
hello      
pi@raspberrypi:~ $ curl http://localhost/node    
Hello World from NODE in Container
We just need to add docker restart hello in hello.git/hooks/post-receive; similar to Staging Node Application where we added pm2 restart hello to restart the pm2 application
Resources
- https://docs.docker.com/engine/reference/run/
- https://docs.docker.com/engine/userguide/containers/dockervolumes/
- https://docs.docker.com/engine/userguide/networking/default_network/binding/
- https://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/
- https://wiki.debian.org/iptables
Happy Containering!