Full Web App + CI/CD pipeline in a Hammer Way! ๐จ๐ฅ๐
Nick Shulhin
Posted on April 19, 2019
VueJS app with NodeJS backend + CI/CD pipeline: Hammer way ๐จ๐
In this tutorial I will explain how to build a simple, full-scale Web App project with NodeJS backend + complete CI/CD pipeline.
I call it "Hammer way" , because it doesn't use Docker or any architecture... It is not very fancy, however it works ยฏ_(ใ)_/ยฏ
In the end of this tutorial we will be able to have our application running on server, with fully automated pipeline which will build, test and deploy on every push to git repository!
Both projects are already available here:
Backend => Here
Frontend => And here
(Feel free to submit PRs for improvements)
Are you ready?
Letโs go! ๐ฅ
Part One: Our NodeJS backend ๐ป
For the sake of simplicity, we will have a super minimalistic NodeJS backend which will do the only thing: serve a front end.
Project structure will look like this:
./backend
โโโ package-lock.json
โโโ package.json
โโโ circle.yml
โโโ scripts
โ โโโ deploy.sh
โโโ server.js
Letโs have a look at server.js:
const express = require('express');
const path = require('path');
const http = require('http');
const app = express();
app.use(express.static('/home/deploy/frontend/'));
app.get('/', (req, res) => res.sendFile(path.join('/home/deploy/frontend/index.html')));
http.createServer(app).listen(8080);
Described above code uses express library which loads an index.html file referenced in static folder and serves on port 8080. Not a rocket science, but we need to start somewhere...
What about deploy.sh?
#!/usr/bin/env bash
ssh-keyscan -H "$1" >> ~/.ssh/known_hosts
ssh "deploy@$1" rm -rf ~/backend/*
scp -r ./server "deploy@$1:~/backend/"
scp -r ./package.json "deploy@$1:~/backend/"
scp -r ./package-lock.json "deploy@$1:~/backend/"
ssh $1 "cd /home/deploy/backend
npm i
forever stopall
forever start server.js
โ
This shell script plays a role of automation deployment system.
Before we walk through the shell code, some server setup clarification:
On our server we will create deploy user specifically for this purpose and generate a pair of SSH keys for our CI/CD pipeline (will go through it soon).
We will also install forever js
which will run NodeJS process in the background.
There will be two folders in home directory: frontend and backend. These will be locations where CI server will copy files to.
For those who are not familiar with shell variables: that
$1
means we are going to pass server host name as a parameter. (It will be executed like:bash deploy.sh my.awesome.website
, wheremy.awesome.website
will be placed instead of$1
).
In brief, this script removes old version of server files, copies new files from Git repository and restarts background run process of server.js.
But how do we integrate with CircleCI? Here is our magic circle.yml configuration file:
version: 2
jobs:
build:
working_directory: ~/backend
docker:
- image: circleci/node:4.8.2
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ checksum "package.json" }}
- run:
name: Install npm dependencies
command: npm install
- save_cache:
key: dependency-cache-{{ checksum "package.json" }}
paths:
- node_modules
test:
docker:
- image: circleci/node:4.8.2
steps:
- checkout
- run:
name: Test
command: npm run test
deploy:
docker:
- image: circleci/node:4.8.2
steps:
- checkout
- run:
name: Deploy
command: bash ./scripts/deploy.sh my.awesome.website
workflows:
version: 2
build_and_test:
jobs:
- build
- test:
requires:
- build
filters:
branches:
only: master
- deploy:
requires:
- build
- test
filters:
branches:
only: master
Configuration file above declares working directory where our pulled from Git repository will be located, test and deploy steps which will run test and execute shell script we discussed before to copy new files.
And it also contains environment description such as node version installed on docker container.
Awesome! We finished with backend! Yahoo! ๐
Now go and push your project to your Git repository!
Part Two: Quick server configuration ๐
As I promised, here is more on Linux server configuration:
We need to install NodeJS:
After that we should install forever.js
for background processing (there could be better alternatives, feel free to experiment):
And lastly, a pair of SSH keys:
ssh-keygen -t rsa -C โamazing@dev.to"
You will need a private key soon to allow CircleCi perform SSH actions on the instance.
Part Three: Front end! ๐
It is a time for a VueJS front-end!
The best way to start with VueJS is by using VueCLI. Once installed you can create a new application by running:
vue create frontend
(You can follow official doc: here)
It may take some time to generate a project, and in the end we will have similar structure:
./frontend
โโโ README.md
โโโ babel.config.js
โโโ node_modules
โโโ package-lock.json
โโโ package.json
โโโ public
โโโ src
Donโt forget to run
npm install
to install all dependencies.
To test your awesome template website, run: npm run serve
.
Can you see it? Amazing, it works! Good job!
Now, letโs add some magicโฆ ๐ฎ
Letโs create a scripts
directory in src
folder, and put deploy.sh
file there which will look like this:
#!/usr/bin/env bash
ls -l
ssh-keyscan -H "$1" >> ~/.ssh/known_hosts
ssh "deploy@$1" "rm -rf ~/frontend/*"
scp -r ./dist/static "deploy@$1:~/frontend/"
scp ./dist/index.html "deploy@$1:~/frontend/"
scp ./dist/service-worker.js "deploy@$1:~/frontend/"
Looks similar, isnโt it?
This script will remove old front-end, and copy new files built by our CircleCi!
And here our circle.yml
file we will create in root of the project:
version: 2
jobs:
deploy:
docker:
- image: circleci/node:latest
steps:
- checkout
- run:
name: Install dependencies
command: npm i
- run:
name: Package
command: npm run build
- run:
name: Deploy
command: bash ./scripts/deploy.sh my.awesome.website
workflows:
version: 2
build_and_deploy:
jobs:
- deploy:
filters:
branches:
only: master
As you can spot, it looks almost the same as a previous one for the server.
However this version builds our frontend project first, and after - performs deployment.
Final project structure will look like this (with our new files):
./frontend
โโโ README.md
โโโ babel.config.js
โโโ node_modules
โโโ circle.yml
โโโ scripts
โ โโโ deploy.sh
โโโ package-lock.json
โโโ package.json
โโโ public
โโโ src
We did it! Yahoo!
Now the last piece: CI configuration (CircleCi in this case)
Part Four: CircleCi ๐
Once you login with BitBucket to CircleCi, add your projects by following them:
Do you still remember SSH key we generated on our server? Now we need to use it!
Go to settings of each of two projects, navigate to SSH Permissions
tab and copy/paste generated private key there:
And now try to push any change to either frontend or backend project => it will trigger a build and your Web Application will be automatically updated:
We made it! ๐๐๐
Conclusion ๐
This kind of pipeline would be suitable for a small personal project, or just to get familiar with deployment idea. Sure thing: almost every part of this tutorial can be upgraded and enhanced :) If you have any ideas or spotted a bug (I'm sure there are few of them - don't hesitate to rase PRs!)
Posted on April 19, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.