Most of us agree that C_ontinuous Integration (CI)_ , C_ontinuous Delivery (CD)_, cloud infrastructure, test automation, and configuration management make up the basics of devops. Depending on the scale of your project, CI/CD may be a hassle to set up and difficult to implement. Nevertheless, it is definitely necessary and here’s why:
In an Agile environment, requirements evolve quickly over time and to ship out features which are bug-free, having a suite of automated tests and integrating code continuously is of utmost important. Having a proper CI/CD environment provides you the confidence to experiment, implement new features, and push out updates quickly.
In fact, with proper CI, bugs can be caught earlier and developers can review code faster as changes to code in a repository are usually merged a few times a day so it can be continuously validated.
You sure you want to do without CI/CD?
By following this article, you will be equipped with the basic knowledge to be able to set up a CI/CD environment on Gitlab and deploy your NodeJS project to Heroku in less than an hour. Of course, we will not be going in-depth on how to write unit tests and that can be further explored in another article.
Sign up for an account and create a new project. Name your project and choose whether it is private/public.
When you first create your project, you will need to add your ssh keys to it.
To create a pair of SSH keys, follow the steps below:
ssh-keygen -t rsa
Then enter the file to save your SSH keys in.
Enter file in which to save the key (/home/demo/.ssh/id_rsa):
Lastly, you can choose to have a passphrase or not. Once done, copy the public key and paste it in gitlab.
cat ~/.ssh/id_rsa_gitlab.pub | pbcopy
After clicking “Add key”, store the key in your keychain with the command:
ssh-add ~/.ssh/id_rsa_gitlab
Configure SSH to always use the keychain. If you do not already have a config
file in .ssh
, create an ~/.ssh/config
file. In other words, in the .ssh
directory in your home dir, make a file called config
.
In that .ssh/config
file, add the following lines:
Host
In Heroku, create a pipeline which will hold both staging and production apps.
Inside the pipeline, create both the staging and productions apps. Note, it will be good if the name of the staging app can be appended with the word ‘staging’ at the back to clearly differentiate the two apps.
After setting up the apps, it will look something like this.
In the root directory of the app, create a folder called tests
, and add a test file in the folder. For me, I use both chai (assertion library) and mocha (JS framework). You can use other assertion libraries such as Jasmine etc if you prefer.
npm install mocha chai --save-dev
Add a script to package.json so you can simply run npm test
next time.
"test": ./node_modules/.bin/_mocha --recursive ./tests/*.test.js
Add a file in tests
called me.test.js
describe(‘me’, () => {it(‘is awesome’, () => {expect(...).to.be....
})});
As I mentioned earlier, we will not be going in-depth into how to write the tests.
To setup a CI environment on Gitlab, add a .gitlab-ci.yml
in the root of your repository.
This file contains definitions of how your project should be built and your Gitlab Runner (which you will be setting up later) will search for this file in your repository and execute it within the environment of the Runner.
This is how I setup my .gitlab-ci.yml
. You may wish to tweak it depending on your project. But of course, before you push up your project to Gitlab, it is good practice to run it by the YAML validator first to make sure it’s valid, if not, it will result in errors. I will explain the various components in my YAML file.
image: node:6.10.3
stages:
ver
init
tests
deploy
ver:
stage: ver
script:
- node --version
- whoami
init:
stage: init
script:
- npm cache clean
- rm -rf node-modules
- npm install
run_tests:
stage: tests
script:
- npm test
deploy_staging:
stage: deploy
script:
- git remote add heroku https://heroku:$HEROKU\_API\[email protected]/text-giving-staging.git
- git push heroku master
- echo "Deployed to staging server"
environment:
name: staging
url: https://text-giving-staging.herokuapp.com/
only:
- master
deploy_production:
stage: deploy
script:
- git remote add heroku https://heroku:$HEROKU\_API\[email protected]/text-giving.git
- git push heroku master
- echo "Deployed to production server"
environment:
name: production
url: https://text-giving.herokuapp.com/
when: manual
only:
- master
image: allows you to specify a certain version of NodeJS you want to use during build time
stages: define build stages. In this case, we have ver
, init
, tests
, and deploy
, but you can change the names of the stages to what you deem fit for your project.
stage ver: node —-version
allows us to check the version of NodeJS we are using and whoami
reveals whether the user has permissions, which makes it easier to debug when things go wrong.
stage init: we clean the npm cache, remove the node modules, install it and then we run the tests which we have written previously.
stage tests: we want to run the tests to make sure all the tests pass.
stage deploy: we will add a remote to the repository using Heroku API key. We can retrieve the Heroku API key from Accounts setting page in Heroku.
Then, go to Gitlab settings > CI/CD pipelines > Secret variables and add HEROKU_API_KEY as a Secret Variable.
We can then refer to the Heroku API key as $HEROKU_API_KEY
in our YAML file.
Notice we have two deploy stages — one for staging, one for production. We have also set it to manually push to production by adding when: manual
in the YAML file. Hence, if all is successful, it will push the master
branch automatically to staging
, and we will need to push manually to production
if everything passes.
As mentioned, in GitLab, Runners run the jobs that you define in .gitlab-ci.yml
. Since I’m using a MacOS, I will be following the instructions here: https://docs.gitlab.com/runner/install/osx.html. It should be fairly straightforward to follow.
Next, register the Gitlab Runner by following instructions here: https://docs.gitlab.com/runner/register/index.html. Again, it should be fairly straightforward to follow. For the runner executor, I chose to run it on shell which is the easiest to configure (you may choose other options if you prefer). After registering, install and start the service with the following commands:
gitlab-runner installgitlab-runner start
You may check if the runner is running with the following command:
gitlab-runner statusgitlab-runner: Service is running!
Now that wasn’t so bad was it?
In Part 2 of this article (please stay tuned), I will be showing you how to setup a notifier for your CI/CD pipeline on Telegram and then pushing the repository up to Gitlab and watch the CI/CD pipeline run through the different stages you have configured and eventually manually pushing it to production.
If you have any feedback for me, please feel free to contact me at [email protected] or just leave a comment on this article.
Or if this article has helped you in anyway, please show some love and hit the little 💚 and follow me on https://github.com/stacygohyunsi for updates on what I’m up to next!