Stackahoy

Deploying a Node.js & Docker Application

This article demonstrates one of many ways you could go about configuring your Docker application.

The following assumes you have successfully installed Docker on the server to which you will be deploying. You can download the source code for the application we will be deploying here.

The Application

Our application is pretty simple. It connects to MongoDB, Redis, and then finally sets up an express route which will add a record into MongoDB, then display the record (in this case, the name of a cat) to the DOM.

app.get('/', function (req, res) {
  var cats = ['Larry', 'Cinza', 'Steve', 'Jack', 'Foo', 'Poo', 'Krammer'];
  var kitty = new Cat({ name: cats[Math.floor(Math.random() * cats.length)] });
  kitty.save(function (err) {
    if (err) {
      throw err;
    }
    Cat.count(function(err, c) {
      if (err) {
        throw err;
      }
      res.send('Hello world, '+kitty.name+' was saved. Number of cats now in the system: '+c+'\n');
    });
  });
});


var server = app.listen(app.get('port'), function() {
  console.log(
    'App running on port %d in %s.',
    app.get('port'),
    app.get('env')
  );
});

Docker

Our application will be 100% managed by Docker. Docker is incredibly handy because it guarantees to the developer that the application will have the exact same environment in development, staging, and production. It also makes deployment quite easy as we never need to install anything on the remote server except for Docker itself.

Docker's CLI interface is fairly straight forward, but we recommend to create a build script specific for your application to run common tasks. We chose to use a Makefile.

~ :: make


Application management. Please make sure you have the env_make file setup.


Usage:
make build        This builds the lev-interactive/myapp image.
make run-dev      This will start the application mapping port 80 to 3030. All src
                  files will be volumed as well for automatic restarts.
                  be working in for instant changes. Runs on port 3000.
make run-release  This will run a container without the volumes on port 80. Good
                  for production.
make save         This will save the database in the backups directory.
make restore      This will restore from the last time you saved.
make destroy      Stops and removes all running containers.

Now to get the application started we simply need to run: make build run-dev. This is especially convenient to use as post commands when configuring the Stackahoy deployment so Stackahoy can build and start the application every time it's deployed.

This application does not maintain persistence by leaving a storage container running at all times. Persistence is kept manually by dumping our data, then re-importing it anytime we want. One of the benefits to this is easily creating a "clean slate" while developing. You can read more about this here.

Whether you are using stateless controlled persistence or "storage container"persistence, it doesn't matter. The only thing that will change is the post deployment command.

The last thing to note is the env_make.dist file. This file should be copied to env_make (cp env_make.dist env_make). This is used to set environment variables which can be used by our Makefile. In our case, we're only setting one: NODE_ENV=development. This file is ignored by the .gitignore file so you don't need to worry about checking it in.

Stackahoy Post Command

So to bring it all together, let's create the post deployment command for Stackahoy to run.

# Create the environment configuration file. You could optionally just go on to the server and write this file manually one time but this way is easier because it's all maintained in one place - Stackahoy.


echo "NODE_ENV=production" > env_make


# Build the docker image from our Dockerfile. This can also handle compiling
# or preprocessing any css or javascript assets as they are stored directly in
this image. Note, when this is happening the application will still be running
so the downtime is very minimal (just a few seconds).


make build


# Save the state of our application.


make save


# Tear down the application.


make destroy


# Start all containers - redis, mongo, nginx, our application. run-release is
set to # run our application on port 80 so it will be "live".


make run-release


# Restore the state (in our case, mongodb).


make restore

This could also be written in just 2 lines:

echo "NODE_ENV=production" > env_make
make build save destroy run-release restore

Conclusion

It doesn't matter how many moving parts there are in your application. The key to sanity is a nice interface for building, starting, and anything else that it needs to do. The beauty of Docker is that you can deploy a complex server stack while being able to sleep at night knowing all of the environments that it's running in are exactly the same.