(This Blog post is part of a collaborative work between Me and Mustapha El Idrissi, Consult his devTo page for more information: https://dev.to/appsbymuss)
What is CI/CD
CI/CD, or Continuous Integration and Continuous Delivery/Deployment, is a set of practices and tools that automates the process of software development, testing, and release. It helps developers deliver code changes more frequently, safely, and reliably.
Continuous Integration: This is a development practice where developers frequently integrate their code changes into a shared repository.
Continuous Delivery: This goes one step further by automating the entire release process. Once code passes all testing stages, it is automatically deployed to the production environment.
There are lot of tools that are used to perform CI and CD such as and not limited to:
- Jenkins
- GitHub Actions
- GitLab CI/CD
- Travis CI
However these tools are usually followed by resource use restrictions or require monetary contributions to be used efficiently and at the same time beginners struggle to use such tools at the start of their Software Development career.
- There is however an easier-to-bootstrap and harder-to-efficiently-setup way to achieve CI/CD which is "GitHub Webhooks"
How to setup GitHub Webhook ?
Step 0: Create a repo
- Ofcourse when we have a new project we have to create a new repository for it to store our code changes (aka commits), but in this case it will also be useful to achieve our CI/CD goal.
Step 1: Create a route for the POST-webhook
- Assuming that you already have a server with your desired runtime environment/Framework up and running on a specific port.
- You're gonna have to also make a webhook in order to let Github have a way to reach your server in the case of new change to the main/production branch on your github repo like so:
require('dotenv').config();
const express = require('express');
const crypto = require('crypto');
const bodyParser = require('body-parser');
const { exec } = require('child_process');
const app = express();
const updatedAt = new Date();
function verifySignature(req, res, buf, encoding) {
const signature = req.headers['x-hub-signature-256']; // GitHub sends the signature here
if (!signature) {
console.log('No signature found on request');
return false;
}
const hmac = crypto.createHmac('sha256', process.env.REPO_WEBHOOK_SECRET);
const digest = 'sha256=' + hmac.update(buf).digest('hex');
if (signature !== digest) {
console.log('Signature does not match');
return false;
}
console.log('Signature is valid');
return true;
}
app.use(bodyParser.json());
app.post('/cicd/github-cicd', (req, res) => {
const buf = JSON.stringify(req.body); // The raw body of the request
// const isValid = verifySignature(req, res, buf);
/* if (!isValid) {
return res.status(401).send('Invalid signature');
}*/
const { ref } = req.body;
if (ref === 'refs/heads/main') {
// PM2 is my instance manager
exec('git pull origin main && pm2 restart cicd_app');
}
res.sendStatus(200);
});
app.get('/cicd/time', (req, res) => {
res.send(`<h1>${updatedAt}</h1>`);
});
app.listen(80, () => {
console.log("Listening on Port 80...");
});
Step 2: Configure the repo's settings
Then we get to the webhook creation panel
[warn] Depending on the SSL state of your website (if it's activated or not), choose the "SSL Verification" option accordingly.
[warn] Incase you want Github to include a "secret" token to authenticate itself to your server to ensure it's Github and not a threat actor, then put a secret word, otherwise leave empty.
Step 3: Ready !
- After Setting up your webhook on your webserver and github webhook of your repo, then you're basically good to go.
Macro
- First a developer will push their commit (code changes) to GitHub.
- Secondly GitHub will send a POST Request to our server, and specifically to our webhook route with the body in JSON with information related to that github push that we've done just a moment ago.
- Thirdly The server will then ofcourse treat said request as a way to know that there are changes on the production branch that must be applied as soon as possible, therefor a git pull will be attempted and then tests and new builds and whatnot are going to be executed.
- Finally The server will consequently restart with the updated source code.
Top comments (14)
Why this is better (or not) that configure Vercel (or any other) to keep an eye on a repo and if a push did happens Vercel (or any other) take the new code and restart the application with the new version ?
Funny thing is that this method is already inspired by How Vercel, Heroku and Cyclic handle this sort of stuff, so it's neither better nor worse, it's actually the same exact method.
I personally still to this day prefer to work with IaaS instead of PaaS in order to learn more stuff especially things that are DevOps or System design focused, and as you know, IaaS does not offer this sort of stuff by default unless you implement it yourself (like the code/guide shown above).
Furthermore this blog just demonstrates how you could achieve the same exact thing Vercel offers but on your own machines/servers.
And as a bonus there could be some other custom logic that you could add to this (or these) webhook handler (unlike PaaS like Vercel where you don't really get much control about what happens when the "new commit" repo webhook gets triggered)
I hope I didn't complicate the explications too much and if you have any more questions let me know :)
Agreed.
My personal issue is that I dislike Micro$oft very much since Windows 3.11...
Have been using GNU/Linux since 1992.
It's quite an honor to be speaking to someone that had at the very least ten times the amount of experience I have, and yes I do agree that Linux is much much better if you're in the IT field, it could only pose some limitations if you're mostly a consumer, like the case in video games etc.
I almost always get a head migraine before I setup a server/service on Windows, whereas in Linux things are a lot more straightforward
Not to mention the fact that Open Source projects are far more admired than Closed source ones.
Nowadays Windows is just a collection of bloatware.
You are welcomed :-)
I'm now far away from the gaming context. Even though have a simple desktop with Win 10 just to run Unreal Tournament III, kind of old school first person shooting.
Nowadays, one can see lots of YouTube videos with some savvy person teaching some IT subject and, most often than not, they use a Apple Mac hardware. As with Micro$oft, IOs is a cesspool of spyware and all sorts of 'big data' gathering.... Second only to my family, I love liberty and privacy. So, Free Software is the best way - not ideal though as there are tales of "infiltration" - like the systemd one.
Recently I migrate to the MX Linux distro that uses sysV init instead systemd...
This is a very good post.
Thank you :)
Amazing! I spent Sunday doing a very similar thing wondering what would be the advantages and drawbacks of the various ways to tackle this. Great to see there's others who are interested in this.
Thank you, to be frank I took inspiration from Heroku and Cyclic, they're PaaS services that offer hosting. What made me take interest in this specific method is its simplicity and also the fact that it eats very little resources, so no additional strain is put on the server.
I will take a look!
Thank you, Youssef.
You're welcome :)
nice, we use gitlab and similar way , we use gitlab webhooks and audit events.
Do you have any other scenarios where this will be useful ?
we monitor all user actions with these events.
great presentation!! SO what is the main raison to do this steps