Deployment

This chapter describes how to put in place a mechanism to deploy the app into a remote server.

We will use ShipIt to have a really easy and fast way to have deployments.

Project Configuration

We need to configure shipit in the projects

Backend

Make sure that package.json file has a repository url property. If https then it will ask your passwd on each release, twice :(, otherwise use ssh access.

Example

  ...
  "repository": {
    "type": "git",
    "url": "[email protected]:MiOrg/myproject.git"
  },
  ...

Shipit config

Lets create a script to run deploys easily, in the same file, under

"deploy": "shipit staging deploy"

Now install shipit packages

npm install --save-dev shipit-cli shipit-deploy shipit-npm shipit-pm2

Create a file named shipitfile.js with the following content

var pkg = require('./package.json');

module.exports = function (shipit) {
  require('shipit-deploy')(shipit);
  require('shipit-npm')(shipit);
  require('shipit-pm2')(shipit);
  var config = require('./shipitfile.config.json')

  shipit.initConfig({
    default: {
      workspace: '/tmp/myproject/backend',
      deployTo: '/var/www/myproject/backend',
      repositoryUrl: pkg.repository.url,
      branch: 'master',
      ignores: ['.git'],
      keepReleases: 2,
      deleteOnRollback: false,
      shallowClone: true
    },
    staging: {
      servers: {
        host: config.staging.host,
        user: config.staging.user,
      },
      key: config.staging.sshKey
    }
  });
};

Of course this can be customized, if you would like different folders, or steps. You will need to change

  • default.workspace | deployTo to replace "myproject" with the name of your project (if you want better names for the folders on the server where the app is going to be deployed.

Now this file requires a configuration file shipitconfig.config.json

{
    "staging": {
        "host": "myserver.com",
        "user": "ubuntu",
        "sshKey": "/blah/bleh/mykey"
    }
}

Of course you should update this content. And you probably want to ignore this file from git.

echo "shipitfile.config.json" >> .gitignore

A good practice is to save a template file for this file with the name shipitconfig.config.json.example but without real values. Then your team can copy the file and change it for running the deploy.

PM2 config

We will use PM2 to monitor start/stop/restart our app in the server (we will install it later in the server). But it also makes things simpler later if our app already has a file to describe itself as a pm2 application.

So lets create

vi app.json

With this content

{
  "name"             : "myproject-backend",
  "script"           : "index.js",
  "cwd"              : "/var/www/myproject/backend/current",
  "exec_interpreter" : "/var/www/myproject/backend/current/node_modules/.bin/babel-node",
  "env": {
    "NODE_ENV": "production",
    "PORT": 3001
  }
}

That's it, commit and push all changes.

We now need to setup the server before we can run the deploy

Frontend

// TODO:

Server Setup

We will need to setup a server instance with all the required software and configuration.

Install Mongodb

Follow instructions for example for Ubuntu 16.04 https://docs.mongodb.com/v3.2/tutorial/install-mongodb-on-ubuntu/

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv EA312927

echo "deb http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.2 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.2.list

sudo apt-get update

sudo apt-get install -y mongodb-org

sudo service mongod start

Install nginx

Follow https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-16-04

sudo apt-get install nginx

Then check with a browser

http://miserver.com

(or whatever IP / hostname you have)

Node

We will use node 6.x following this instructions https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-ubuntu-16-04

curl -sL https://deb.nodesource.com/setup_6.x -o nodesource_setup.sh

sudo bash nodesource_setup.sh

sudo apt-get install nodejs

PM 2

Follow the pm2 section from here https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-ubuntu-16-04

sudo npm install -g pm2

Now in order to have the logs rotated every day at 00:00:00 we must install a plugin

pm2 install pm2-logrotate

That's it. More info on how to customize the logs and rotation here

Install Python 2.7

We need python 2.7 for node-gyp (notice that it seems to require 2.7 and not 3.x !!) We will use a prebuilt package as it is the easiest solution.

sudo add-apt-repository ppa:fkrull/deadsnakes
sudo apt-get update
sudo apt-get install python2.7

Configure python in npm (probably it will also work if you create an alias "python" and make sure it is in $PATH)

npm config set python /usr/bin/python2.7

Create Remote folder

We need to create a remote folder for the releases that will be served by nginx

Log to the server

sudo mkdir /var/www/myproject
sudo chown -R ubuntu: /var/www/myproject

(or whatever user you want to use)

Configure Nginx Proxy

We will put nginx on front of the backend module and also serving the frontend.

Our deployment with shipit, if well configured would end up creating a structure like this in the server


/var/www
├── html
│   └── index.nginx-debian.html
└── myproject
    ├── backend
    │   ├── current -> releases/20161110194400
    │   └── releases
    └── frontend
        ├── current -> releases/20161110205627
        └── releases

Serve Backend

Now we will configure nginx to act as proxy for the backend

sudo vi /etc/nginx/sites-available/default

And add the following location

location /api/ {
                proxy_pass http://127.0.0.1:3001/;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection 'upgrade';
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
        }

(Notice the ending slash in api/ ! otherwise you will lose time :P )

This expects the backend to be in the same host as nginx, and using port 3001 (default).

Now restart nginx

sudo systemctl restart nginx

Now go to a browser http://myserver.com/api/

Serve Frontend

The front end once deployed is just regular static files (js, css, etc). So we only need to configure nginx to serve files from that folder

Again

sudo vi /etc/nginx/sites-available/default

Comment the root directive and add a new one pointing to our front end release folder. Also change the / location to look as here below

#root /var/www/html;
root /var/www/myproject/frontend/current;

location / {
   root /var/www/nes/frontend/current/;
   try_files $uri $uri/ /index.html;
}

Restart

sudo systemctl restart nginx

And now access http://myserver.com/

(notice the slash at the end !)

Note

Of course nginx can be configured in different ways. For example you could prefer to create specific config file for this virtual server, etc. We just picked one here, the one that seemed the easiest but probably not the better for real production. (anyway, for production it would be better to have a docker based deployment :))

Deploying

That's it, we are ready. Now to deploy lets say the backend we just need to run

npm run deploy

results matching ""

    No results matching ""