Continuous integration tools have made the process of integrating code a lot easier and definitely have sped things up.
This way, you can have more contributors to the codebase, while CI ensures that code is integrated into one place. You also have version control for managing branches - they can be as many as you want.
Continuous Delivery makes sure that the changes you made locally are published to the server automatically when you push new changes to the repository.
For this article, we exemplify CI and CD with Gitlab.
GitLab is great because it offers continuous integration (like GitHub), but also continuous delivery using runners, pipelines, issue tracking and a whole lot of other cool tools.
It is open-source and a very good starting point for any beginner in the field of DevOps to learn CI/CD, understand the flow and basically get a hang of the whole process.
The main benefits of using CI/CD are:
- Sped-up development process: you only have to push the code to the repository and it will be deployed to the server.
- Testing the product is much faster when small changes are reflected within the server. They can be tested and if there is a fault in some functionality, we can pinpoint the commit after which the fault started, as well as the person who did the commit making the whole process of development and testing kind of transparent.
- Time and cost-efficiency: When we deploy the code after the application is completed, there are potential faults that may occur, and resolving them takes extra time and extra effort. If, however, we use CI/CD, all the feednack and changes that the client adds can be resolved and implemented parallel to development.
We are going to deploy a React application which is basically a very simple weather app that uses OpenWeatherApi to fetch weather data.
We will use a Gitlab service called Gitlab pages to deploy our website. This service lets you deploy static applications directly from gitlab repository to the interweb.
I will assume you already have a React codebase set up on Gitlab at this point, so that we can focus on the topic here.
After you have pushed the React codebase to the Gitlab repository, navigate towards settings of the repository, go to the general section and expand Visibility, project features, permissions section. Scroll down and make sure the pages switch is in ON state.
Next step will be to create a
.gitlab-ci.yml file in your project root. This file will have instructions on how Gitlab will build your project and which folder it needs to serve on the internet. Nothing Complex i will explain all. A point to note as this file is yml so monitor your spaces because if there is single space more or less it could mess up things and cause errors.
Let’s start off by defining the stages in which we want our pipeline to run. You can think of stages as steps to deploying the application.
image: node:12.22.0 stages: - build - deploy
Here, we are doing two things: first, we are telling GitLab to use Node version 12 because my application is using this version of node. If you are using a different version, just replace it. Next, we are defining that there will be two stages - build and deploy - and yes you can use any stage name you want.
cache: paths: - node_modules/
In this section, we are telling GitLab to cache the
node_modules directory so that it does not download new node modules on every build. This will save time and resources because basically we are reusing code.
before_script: - rm -rf build - CI=false npm install
What we just did is we specified a tag
before_script which will run before the stage script. Then, we remove the build folder (if there is any or it it was pushed by mistake to the codebase) and we install all dependencies using
npm install command.
In the previous step we have specified to cache
npm install will use those caches; if there is a new dependency, it will install that and also add it to caches.
Here we have the script for stage build, so let's unwrap it:
pages: stage: build script: - CI=false npm run build - rm -rf public - cp build/index.html build/404.html - mv build public artifacts: paths: - public only: - master
Instead of 'pages', you can name it whatever you want, just remember to specify the stage in the next step. Script tag defines the start of the script and below it we can write the commands which Gitlab will execute in order to run the application.
CI=false npm run build is basically building the project and it is the same for all react projects, just like we built the project using this command. What's different is we used environment variable CI, which ensures that the build is not failed due to any warnings. If there are warnings, sometimes the build fails.
Now, after building the project and establishing a build directory which has everything for our application to run, we can remove the existing public directory so that we can use it for serving our application with GitLab.
Rm-rf public removes the existing public directory.
Next we are copying
index.html to a file named '404.html'. In React, a route which is not defined in our router, is redirected to 404.html page. If you don't have a 404.html page defined within the project, you will get an error from the web server. So we are defining a 404.html page with content the same as index.html.
Remember I said GitLab needs a public named directory to serve the internet? We have our application build into the build folder, so the line
mv build public is just copying build folder into public folder.
Next on, the
artifacts tag is telling GitLab that the build job has an output of this directory. As we need a public directory to serve, we need to specify in the
artifacts tag what to save for the next step.
only tag is defining the rule that this pipeline should run only if the push is to master branch. This comes in handy if we have different development environments like dev, prod and testing.
deploy_app: stage: deploy script: - echo "deploying the app" artifacts: paths: - public
On the next stage which is 'deploy' we are not doing anything significant, we are just printing, 'deploying the app' and giving the path name of the folder to serve in the
artifact tag. This stage can be skipped but I did it to explain in detail. Here we are using the same public folder that we specified in the previous stage. So the whole yml file will be this:
image: node:12.22.0 stages: - build - deploy cache: paths: - node_modules/ before_script: - rm -rf build - CI=false npm install pages: stage: build script: - CI=false npm run build - rm -rf public - cp build/index.html build/404.html - mv build public artifacts: paths: - public # only: # - master deploy_app: stage: deploy script: - echo "deploying the app" artifacts: paths: - public
Now push the changes to the repository and open up CI/CD tab:
As soon as there is a new push, you should see a new pipeline job.
After successful deploy you should see something like this:
Navigate to settings and than pages tab and you should see this:
One more thing we need to do is create an
.env file in the project root and specify the public URL for our application. The app will use it to access static files like css, js etc.
PUBLIC_URL=/<URL FROM PAGES TAB>
In my case it will be 'weatherapp'.
Push the changes with the
.env file and click on the link and voilà!
Now if I change the city to London and push the changes, the app should auto-deploy the changes. Let’s test it out:
Commit message is “Changing city to london”.
The pipeline is running, so let's wait for it to complete and see the changes.
There you have it: we have successfully created a CI/CD pipeline using GitLab pages and GitLab pipelines.
This process is fairly easy and it will definitely speed up your development and testing phase of an application.