How to get from code to production in minutes

Fran Rios
Netbeast
Published in
6 min readJan 21, 2017

At Netbeast we maintain an open source project called Dashboard. For a while, it used to be our main product until we launched Yeti. At the time, we wanted to have a live and always up to date demo of Dashboard that our users could access easily.

How did we achieve this? We created a DevOps pipeline that wraps the Dashboard in a Docker container to serve it in production. Here’s a step by step tutorial to implement it with a simplified but fully working example.

We’ll cover the whole DevOps workflow which starts at the source code editing on the developer’s side and ends on production deployment on your favourite Cloud Provider. The walkthrough looks like the following:
GitHub -> Travis-CI -> Docker Hub -> Docker Cloud -> Production (Digital Ocean in my case).

You can always change the CI platform and replace it with the one of your choosing. For example you may use Circle-CI instead of Travis.

Source Code

https://github.com/franrios/testingNdeploying

This part’s goal is to test over Travis-CI so that’s why we have to set up a very (very) simple Node.js app.

You need to create your own repo on GitHub with the same files (changing some things as for example .travis.yml‘s last line)

This is the index.js file for our Node app:

var express = require(‘express’)
var app = express()
app.get(‘/’, function (req, res) {
res.status(200).send(‘root path of the project! (Testing redeploy)\n’)
})
app.listen(8080, function () {
console.log(‘App listening at localhost:8080’)
})

If we run node index.js we'll get a basic server that displays the message root path of the project! (Testing redeploy)
in your browser (at http://localhost:8080).

We then add a test file that uses Mocha and Chai to check that our server is ok. Our test.js file would look like this:

var request = require(‘request’)
var expect = require(‘chai’).expect
describe(‘Server response’, function () {
it(‘should return 200’, function (done) {
request.get(‘http://localhost:8080/', function (err, res, body){
if (err) throw err
expect(res.statusCode).to.equal(200)
done()
})
})
})

Let’s add some gulp tasks for running tests. To use gulp, you need to previously install it’s command line interface by typing: npm install -g gulp-cli. Then you can add a gulpfile.js like this one:

var gulp = require(‘gulp’)
var mocha = require(‘gulp-mocha’)
var bg = require(‘gulp-bg’)
var bgstart gulp.task(‘start’, bgstart = bg(‘node’, ‘./index.js’))
gulp.task(‘test’, [‘start’], function () { return gulp.src(‘./test/test.js’, {read: false})
.pipe(mocha({reporter: ‘nyan’}))
.once(‘end’, function () {
bgstart.setCallback(function () { process.exit(0) })
bgstart.stop(0) })
.once(‘error’, function () {
bgstart.setCallback(function () { process.exit(0) }) bgstart.stop(0) }) })

gulp.task(‘default’, [‘start’, ‘test’])

This gulpfile basically runs the server and tests in the correct order when we use the gulp command. We add this command to the package.json file:

“scripts”: { 
“test”: “gulp test”
}

The reason of that is to let Travis execute gulpfile just by doing a npm test.

Other important file that we need is the .travis.ymlfile of course. It looks like this:

sudo: falsenode_js:
— “4.2.1”
after_success:
— |
curl -H “Content-Type: application/json” — data ‘{“build”: true}’ -X POST https://registry.hub.docker.com/u/fcojriosbello/testingndeploying/trigger/4fcbd380-e094-4c28-9bab-95f7fe62001a/

Keep an eye on the last line, we’ll explain it later… It triggers the Docker Hub Automated Build 🙃 AWESOME!!

The last important file is the Dockerfile:

FROM ubuntu:14.04MAINTAINER Fran Rios fcojriosbello@gmail.com# to avoid some problems:
# debconf: unable to initialize frontend: Dialog
ENV DEBIAN_FRONTEND noninteractive
# Install Nodejs…
RUN apt-get update && apt-get install -y nodejs npm
# Copy app to /src
COPY . /src
# Install app and dependencies into /src
RUN cd /src; npm install
#Show in our container
EXPOSE 8080
#Run the app
CMD cd /src && nodejs ./index.js

It basically creates an Ubuntu based container, installs Node.js and Npm and copy our app into the container (and executes it exposing port 8080).

Travis

Having said that we can run our CI tests on Travis. Remember to create your own account in Travis and add the repo that you have just created for this tutorial by linking your Github account.

To run the test locally you can type gulp and check that it pass. If you want to run them on Travis you need to run a git push and update your code in the remote repo. Automatically Travis recognises that your source code has changed and check that tests are ok. If you see green color everything it's been doing well.

You’ll see something like this:

Docker Hub

Now we can Login in Docker Hub and create a new Automated Build. To do this you need to link your github account and click on the following option (on the right corner):

After that you choose your recent repo and configure it as follow (clicking on Build Settings):

In the same settings page you need to Activate Build Triggers and then copy the first curl ...command from the hidden examples (click over Show examples to expand them) This what you need to copy in the after_success section of .travis.yml file.

At this point you can check that success builds in Travis will trigger an Automated Build in Docker Hub. Fantastic!!! 🚀

Docker Cloud

We only need to complete the two last steps of Deployment: Docker Cloud and chosen cloud provider. You need to configure your Docker Cloud account in order to add your cloud provider (AWS, Digital Ocean, etc…)

The steps are:

  • Set Cloud Provider (it depends on what you’ll use)
  • Launch a Node Cluster
  • Setup a new service on that cluster

Well known Tutum is water under the bridge. Now we have Docker Cloud which is the evolution of Tutum and it’s still in beta version. It lets you build, deploy and manage your docker based services. When you have linked your cloud provider you need to launch a Node Cluster. You can configure it as follow:

Having done that you’ll have a node cluster without any services on top. It’s time to add a new service. You’ll add it directly from your Docker Hub account:

And this would be a valid configuration:

When it’s done you can check that everything is ok by accessing to the endpoint created for your service:

We have now our app correctly deployed but it’s not totally automated. It’s necessary to link Docker Hub and Docker Cloud in order to trigger a redeploy when a success build occurs.

To do this you need to add a Webhook in Docker Hub repo. You can do it here:

and get the Webhook from Docker Cloud, here:

Now we have completed the workflow. Each new push in Github repo will trigger a new build in Travis-CI and if tests passed a Docker Hub automated build will be triggered too.

If everything is correct our app will be deployed in our chosen provider. 🏻👏

Long story short… You can trigger actions between CI services and deployment platforms which allows you to save time and money. Also each step acts as firewall that protects your production services of been incorrectly updated as well as give you the information of where to act if something went wrong.

--

--

Fran Rios
Netbeast

Engineer at Skyscanner ✈️ Beer n cheese lover 🍺🧀