minutes read

Getting Started with GitLab CI/CD

Ty Huynh

September 19, 2022

feature image

A better way to debug your PHP code

A better way to debug your PHP code

Khoa Pham

November 16, 2022

Discover iOS Dark Mode Programming

Discover iOS Dark Mode Programming


November 1, 2022

CI/CD stands for continuous integration and continuous delivery/continuous deployment. In the software world, the CI/CD pipeline refers to the automation that enables incremental code changes from developers’ desktops to be delivered quickly and reliably to production. This article will guide you on how to create and run a CI/CD pipeline using GitLab.

About GitLab CI/CD

GitLab CI/CD is a tool for software development using the continuous methodologies:

  • Continuous Integration (CI)
  • Continuous Delivery (CD)
  • Continuous Deployment (CD)

To put it simply, GitLab CI/CD can automatically build, test, deploy, and monitor your applications. It can help you catch bugs and errors early in the development cycle, while also ensuring that all the code deployed to production complies with the code standards established for the application.

Continuous Integration vs Continuous Delivery vs Continuous Deployment

Continuous Integration (CI)

  • In continuous integration, developers merge their changes back to the main branch as often as possible.
  • The changes are validated by creating a building and running automated unit tests.
  • This helps to avoid integration challenges and check that the application is not broken whenever new commits are done.
the process of Continuous Integration

Continuous Delivery (CD)

  • Extension of continuous integration by which it automatically deploys all code changes to testing and/or staging environment.
  • The final production deployment will be manual or using continuous deployment (CD).
  • The goal of continuous delivery is to have a codebase that is always ready for development in a production environment.

Continuous Deployment (CD)

  • Every change that passes all stages of your production pipeline is released to your customers/ production environment.
  • No human intervention, completely automated.
the process of continuous deployment

Getting started with Gitlab CI/CD

Creating a project and uploading the code

First, create a repository for our project and push some sample files.

a screenshot when you create a project and upload it on gitlab

Create the CI/CD configuration file .gitlab-ci.yml and add a first test job. We can also view the .gitlab-ci.yml syntax reference here.

Once we pushed the .gitlab-ci.yml file, the Gitlab pipeline will be triggered and run the job. Now, we can see the pipeline is running and this job should be done.

pipeline status screen in gitlab

All our jobs will be run by an application called Gitlab runner. So, to find out what the Gitlab runner is, let’s read on.

GitLab Runner

GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. Written in Go, it’s open-source and can be run as a single binary; no language-specific requirements are needed.

GitLab Runner can be installed on several different supported operating systems. Other operating systems may also work, as long as a Go binary is compiled on them.

Here is the scope of runners:

  • Shared runners are available to all groups and projects in a GitLab instance.
  • Group runners are available to all projects and subgroups in a group.
  • Specific runners are associated with specific projects. Typically, specific runners are used for one project at a time.

If you use GitLab.com, you can run your CI jobs on Runner Cloud. These are runners managed by GitLab and fully integrated with GitLab.com. These runners are enabled for all projects, though you can disable them. If you don’t want to use runners managed by GitLab, you can install GitLab Runner and register your own runners on GitLab.com.

Shared runners

Shared runners are available to every project in a GitLab instance.

Use shared runners when you have multiple jobs with similar requirements. Rather than having multiple runners idling for many projects, you can have a few runners that handle multiple projects. As the example above, the jobs are run by shared runners because on GitLab.com, shared runners are enabled in all projects by default.

Group runners

Use Group runners when you want all projects in a group to have access to a set of runners. Group runners process jobs by using a first in, first out (FIFO) queue.

Specific runners

Use Specific runners when you want to use runners for specific projects. For example, when you have:

  • Jobs with specific requirements, like a deploying job that requires credentials.
  • Projects with a lot of CI activity that can benefit from being separate from other runners.

You can set up a specific runner to be used by multiple projects. Specific runners must be enabled for each project explicitly. Specific runners also process jobs by using a first-in, first-out (FIFO) queue.

In the next part, we will learn how to deploy from GitLab to the server automatically.

Build and deploy an application using Gitlab CI/CD

We will set up the Gitlab CI/CD pipeline to create a react app build, test, and deploy to our server whenever code is merged to the main branch using shared runners.

a screenshot of an up and running project on Gitlab

Step 1: Grant GitLab access to our server by adding Gitlab CI/CD Variables

We are going to use Gitlab CI/CD Variables to save a private SSH key, user, and host which Gitlab will use to authenticate with the server. These SSH keys are used to authenticate rather than using usernames and passwords, as it is more secure. This can be configured at a repository level or at a group level.

To view all the CI/CD variables of our repository:

  1. Go to our project’s Settings > CI/CD.
  2. Expand the Variables section.

To create a new variable, Select the Add Variable button and fill in the details:

  • Value: <ssh_private_key_details>. (To generate new SSH public and private key pair, follow the steps from this guide. Make sure to not accidentally overwrite any existing key pairs.)
  • Type: Variable
  • Choose other settings based on our needs

Finally, Click Add Variable to add the variable:

a screenshot when you add variable in GitLab

Repeat the same as above steps to create SSH_USER and SSH_HOST variables:

creating SSH_USER and SSH_HOST variables complete

Step 2: Configuring GitLab CI/CD configuration file

Gitlab looks for .gitlab-ci.yml in the root folder of our repository for CI/CD pipeline configurations. Once we added the .gitlab-ci.yml file and push it to our GitLab repository, GitLab will detect this file and a GitLab runner will go through the file and run all the jobs that we specify there.

In this file we can define the scripts that we want to run, we can run commands in sequence or in parallel, we can define where we want to deploy our app and specify whether we want to run the scripts automatically or trigger any of them manually. We need to organize our scripts in a sequence that suits our application and in accordance with the test we want to perform.

Let's see the example below:


  • We are defining two stages that running two respective jobs are build and test.
  • We are using the Node Docker image to run the build and test job, the node version (14.17.3) should be matched with the node version that was installed on the server to make sure everything is running smoothly.
  • The pipeline only runs when the code is pushed to the main branch.

Let's include this code in our .gitlab-ci.yml file and commit those changes to our repo.

If we go to our repo we will see that our pipeline is running, let's take a look at our pipeline, we need to go to CI/CD and then to pipelines in our sidebar:

You can take a look at our pipeline by clicking CI/CD and then to pipelines in our sidebar

Then we will see the progress/status of our jobs here:

a screenshot of the progress of your tasks in GitLab

So, this was a very simple example to see how the pipeline works, we have two stages, and in the first one we just build the application and in the second one, we run our tests. You might be asking why are we running "yarn install" 2 times, surely there's a better way to do it.

This is because each job runs in a new empty instance and we don't have any data from previous jobs, in order to share data we need to use artifacts or cache, what's the difference?


  • Is usually the output of a build tool.
  • In GitLab CI, they are designed to save some compiled/generated paths of the build.
  • Artifacts can be used to pass data between stages/jobs.


  • Caches are not to be used to store build results.
  • The cache should only be used as temporary storage for project dependencies.

So, let's improve our pipeline:

Now we don’t need to add ‘yarn install’ at the test stage because the node_module folder was shared from build stage, and that will improve the speed of the build.

Let's commit our code, and we'll see that everything still working, that's good!

Step 3: Adding the deploy stage

Now we will add the deploy stage to our .gitlab-ci.yml file, our last version of this file will be this one:

In order to make this happens, we need to establish an SSH connection between our pipeline and our server, to do that we will need to use our SSH_PRIVATE_KEY, SSH_USER, and SSH_HOST variable that was created at step 1.

So, for this stage we will use ubuntu image and need to run this command:

Next, we need to save our SSH_PRIVATE_KEY value as a file and grant permissions so we can use that file for SSH.

Finally, we will open an ssh connection to the server with StrictHostKeyChecking to no, to ensure git doesn't show a manual prompt during the initial connection. Then we cd to the folder that our project is placed and run the script in deploy.sh.

Step 4: Setup the deploy script

Add a new file deploy.sh in the root folder.

Here’s the explanation:

  • We pull the latest code of the branch that the server is running on.
  • We install dependencies and then start a new react build using yarn.
  • Once the build is done, shows the message that the deployment is finished.

We can also modify this to meet our app requirements.

Now that everything is ready, let's commit and push our code to see the result. We can check our pipeline status by going to CI/CD > Pipelines, then clicking the status button of our pipeline.

a screenshot of when you finish setting the deploy script and everything is running properly

We can also click the individual job to see the command line output of our script. Once our pipeline passed we can verify that our server is running perfectly and should apply new code.

That's all, now every time that we push our code into our repo, our pipeline will build our app, then it will run our tests, and finally, it will deploy our app into our server!


I hope this tutorial helps you learn how to build, test and deploy your application using Gitlab CI/CD. Thank you for sticking with this article until the end. Follow us for more cool technical stuff from an Offshore Development team in Vietnam. If you are curious about our services, visit https://fabatechnology.com/ to get your questions answered.