Introduction to GitLab CI/CD

Page content

In this post I will show you the basics of using gitlab as a Continuous Integration and Continuous Deployments (CI/CD) tool.

What Is a GitLab?

GitLab is a collaborative DevOps platform and open source code repository for large software development projects. GitLab provides an online code storage location, as well as CI/CD and issue tracking capabilities.

GitLab pipelines are the basic building blocks of CI/CD—a pipeline is a top-level component for continuous integration and delivery/deployment. A pipeline includes the following components:

  • Jobs — these define the desired actions, such as compiling or testing code. A runner executes each job, and you can run multiple parallel jobs if you have concurrent runners.
  • Stages — these determine when each job runs, such as the code compilation stage followed by the test running stage.

Create a Project on GitLab

First, we need to create a project on GitLab. A Project is represent a git repository to store your code. You can run Gitlab on your own hardware or use the Gitlab.com the cloud service of Gitlab. In a previous post I showed how to install an on-premise Gitlab server.

Gitlab Runners

Gitlab runners, re separate machines connected to the Gitlab server, which are actually the ones executing the pipelines.

Gitlab Runners

Gitlab.com cloud service offers pre-installed runners to use. On a self hosted Gitlab server you need to create your own. To Install a new self hosted runner is easy. You just select the Settings > CI/CD menu in your project and select Runners. You need tp copy the registration token from the Set up a specific runner manually menu:

Gitlab Runners Registration

Then on a linux Server install the runner:

sudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64

sudo chmod +x /usr/local/bin/gitlab-runner

# add local user for the runner
sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash

sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
sudo gitlab-runner start

Register the runner to the Gitlab Server. Change <REGISTRATION-TOKEN> to the token ypu previously copied.

sudo gitlab-runner register -n \
--url https://gitlab.mydomain.intra/ \
--executor docker \
--docker-privileged \
--docker-image "docker:stable" \
--docker-volumes "/var/run/docker.sock:/var/run/docker.sock" \
--registration-token <REGISTRATION-TOKEN>

This will register a docker based runner in Gitlab. This means all the build and pipeline job will run in a docker container. Of course to do this you need to install docker engine on your runner. In a previous post I shoved how to install Gitlab Runners in an Openshift environment.

Create a YAML Configuration File for CI/CD

Gitlab use a file called .gitlab-ci.yml to configure your CI/CD pipeline.

Below is a snippet of what your .gitlab-ci.yml file should look like:

image: docker:stable

variables:
  DOCKER_TAG_LATEST: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:latest
  DOCKER_TAG_COMMIT: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:$CI_COMMIT_SHORT_SHA

cache:
  paths:
    - node_modules/

stages:
  - build
  - deploy

build:
  image: docker:latest
  stage: build
  services:
    - docker:dind
  tags:
    - docker
  script:
    - echo "Starting to build"
    - docker build -t $DOCKER_TAG_COMMIT -t $DOCKER_TAG_LATEST .
    - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY
    - docker push $DOCKER_TAG_COMMIT
    - docker push $DOCKER_TAG_LATEST
    - echo $DOCKER_TAG_COMMIT

deploy:
  image: alpine:latest
  stage: deploy
  tags:
    - docker
  script:
    - echo "Starting to deploy"
    - chmod og= $SSH_PRIVATE_KEY
    - apk update && apk add openssh-client
    - ssh -i $SSH_PRIVATE_KEY -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY"
    - ssh -i $SSH_PRIVATE_KEY -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker pull $DOCKER_TAG_COMMIT"
    - ssh -i $SSH_PRIVATE_KEY -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker container rm -f my-project || true"
    - ssh -i $SSH_PRIVATE_KEY -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker run -d -i -p 3000:3000 --name my-project $DOCKER_TAG_COMMIT"
  environment:
    name: production
    url: http://$SERVER_IP
  only:
    - main

Here is a quick overview of how each part works to aid the deployment process:

The image defines the Docker image to be used:

image: docker:stable

In the variables section, you’re creating two tags for the Docker image. The DOCKER_TAG_LATEST variable will add the latest tag to the latest built Docker image, while the DOCKER_TAG_COMMIT variable will use the first eight characters of the commit SHA to tag the Docker image.

The cache defines the file or list of files that should be cached between subsequent runs.

cache:
  paths:
    - node_modules/

The stages define the order of jobs that would be in the pipeline. Here, there are two stages of the build and deploy as seen above.

stages:
  - build
  - deploy
build:
  image: docker:latest # Defines the Docker image to be used
  stage: build # The stage assigns the current job to the build stage.
  services: # link to another docker image. This allows you to use the Docker executor to build your Docker image.
    - docker:dind
  tags: # run on runner with tag docker
    - docker
  script: # In script sou add the command that the build will execute. In this case we build a docker image and used the built-in variables to login and push the image to the Gitlab docker registry.
    - echo "Starting to build"
    - docker build -t $DOCKER_TAG_COMMIT -t $DOCKER_TAG_LATEST .
    - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY
    - docker push $DOCKER_TAG_COMMIT
    - docker push $DOCKER_TAG_LATEST
    - echo $DOCKER_TAG_COMMIT

The Deployment job is similar to the build except the fallowing snippet.

  environment:
    name: production
    url: http://$SERVER_IP
  only: # can run only on main branch
    - main
  dependencies: # only runs if the build job is successful
  - build

Start a CI/CD pipeline

To activate the pipeline you need to place the .gitlab-ci.yml file in the root of your git repository.

cd myrepo
nano .gitlab-ci.yml
git add -A
git commit -m "add .gitlab-ci.yaml"
git push

At the web-ui go to sour project and select CI/CD > pipelines menu to check your pipeline. It will start automatically.