GitLab CI/CD Pipeline Configuration Guide

Understanding GitLab CI/CD workflow and .gitlab-ci.yml configuration

Featured image



Overview

Let’s explore GitLab CI/CD workflow and learn how to write .gitlab-ci.yml files for automated pipelines. For GitLab and GitLab Runner installation, please refer to our previous posts:

What is GitLab CI/CD?

GitLab CI/CD (Continuous Integration/Continuous Deployment) is a built-in feature that automates the process of building, testing, and deploying applications.

It helps ensure code quality and stability by running tests and validations for every code change, minimizing human error and improving development efficiency.


How GitLab CI/CD Works

Core Components:

  • Configuration
    Uses `.gitlab-ci.yml` file in repository root to define jobs, stages, and rules.
  • Pipeline
    Triggered by commits or merge requests, follows stages defined in configuration, and can be manual or scheduled.
  • Jobs
    Individual tasks within pipelines that run in containers or runners to build, test, or deploy actions.
  • Stages
    Pipeline phases (e.g., build, test, deploy). Jobs in the same stage run in parallel, and stages run sequentially.
  • Runners
    Agents that execute jobs. They can run on various platforms and be shared or specific to projects.
  • Artifacts & Caching
    Store build outputs, share between jobs, and cache dependencies for efficient execution.


GitLab Predefined Variables

Common predefined variables used in pipelines:

CI_COMMIT_REF_NAME    # Branch name being built
CI_COMMIT_SHORT_SHA   # First 8 characters of commit SHA
CI_REGISTRY           # GitLab Container Registry address
CI_PROJECT_DIR        # Full path where repository is cloned
CI_REGISTRY_USER      # GitLab registry user
CI_REGISTRY_PASSWORD  # GitLab registry password


Pipeline Examples

1. Basic Pipeline

Basic Pipeline Diagram

stages:
  - build
  - test
  - deploy

image: alpine

build_a:
  stage: build
  script:
    - echo "This job builds something."

test_a:
  stage: test
  script:
    - echo "This job tests something."

deploy_a:
  stage: deploy
  script:
    - echo "This job deploys something."
  environment: production

2. DAG (Directed Acyclic Graph) Pipeline

DAG Pipeline Diagram

stages:
  - build
  - test
  - deploy

build_a:
  stage: build
  script:
    - echo "Building component A"

test_a:
  stage: test
  needs: [build_a]
  script:
    - echo "Testing component A"

deploy_a:
  stage: deploy
  needs: [test_a]
  script:
    - echo "Deploying component A"

3. Parent-Child Pipeline

Parent-Child Pipeline Diagram

# Root .gitlab-ci.yml
stages:
  - triggers

trigger_a:
  stage: triggers
  trigger:
    include: a/.gitlab-ci.yml
  rules:
    - changes:
        - a/*

# a/.gitlab-ci.yml
stages:
  - build
  - deploy

build_a:
  stage: build
  script:
    - echo "Building service A"

deploy_a:
  stage: deploy
  script:
    - echo "Deploying service A"


Practical Example

Here’s a real-world example with build and deploy stages:

stages:
  - build
  - deploy

variables:
  BRANCH:
    value: "dev1"
    description: "Select branch: dev1 or dev2"
  NAMESPACE:
    value: "dev1"
    description: "Select namespace: dev1 or dev2"
  SERVICE:
    value: "game"
    description: "Select service type"
  CI_REGISTRY_IMAGE: $CI_REGISTRY/$SERVICE
  BUILD_TAG: $BRANCH-$CI_COMMIT_SHORT_SHA
  IMAGE_URL: '${CI_REGISTRY_IMAGE}:${BUILD_TAG}'

.build_image: &build_image
  stage: build
  image:
    name: gcr.io/kaniko-project/executor:debug
    entrypoint: [""]
  script:
    - /kaniko/executor 
      --context $CI_PROJECT_DIR 
      --dockerfile $CI_PROJECT_DIR/$SERVICE.Dockerfile 
      --destination $IMAGE_URL 
      --build-arg NODE_ENV=$BRANCH

.deploy_job: &deploy_job
  stage: deploy
  image: dtzar/helm-kubectl
  script:
    - kubectl set image deployment $SERVICE-$NAMESPACE 
      app=$IMAGE_URL -n $NAMESPACE

build_image:
  <<: *build_image
  rules:
    - if: '($CI_PIPELINE_SOURCE == "web")'
    - if: '($CI_PIPELINE_SOURCE == "trigger")'
  tags:
    - build-runner

deploy_job:
  <<: *deploy_job
  rules:
    - if: '($CI_PIPELINE_SOURCE == "web")'
    - if: '($CI_PIPELINE_SOURCE == "trigger")'
  tags:
    - deploy-runner


Advanced Pipeline Features

1. Change-Based Triggers

.change_files: &change_files
  changes:
    - apps/**/*
    - config/*
    - libs/**/*
    - *.Dockerfile
    - .gitlab-ci.yml

build_image:
  rules:
    - if: '($CI_PIPELINE_SOURCE == "push")'
      <<: *change_files

2. Cross-Project Triggers

build_job:
  after_script:
    - curl -X POST 
      -F token=${TRIGGER_TOKEN} 
      -F ref=${CI_COMMIT_REF_NAME} 
      -F variables[project_id]=${CI_PROJECT_ID} 
      http://gitlab.example.com/api/v4/projects/100/trigger/pipeline



Reference