Gitlab CI — the CI/CD Power Tool Built into Gitlab

Gitlab CI, born in Gitlab, used for Gitlab

Gitlab CI is the continuous integration / continuous delivery system built into Gitlab. You do not need to set up an extra CI server: just put a .gitlab-ci.yml file in the root of your Gitlab repository and configure a Runner, and the pipeline can run.

Wozkishuode once said: “Give me a Jenkins, and I can automate everything.” But Gitlab says: “Don’t give me Jenkins, I can automate everything myself.”

The three core components of Gitlab CI

1. Pipeline

The Pipeline is the top-level concept in Gitlab CI. One Pipeline consists of several Stages, and each Stage contains several Jobs.

stages:
  - build
  - test
  - deploy

2. Runner

The Runner is what really does the work — the agent process that executes Jobs. Gitlab provides Shared Runners, and you can also register a Specific Runner on your own machine.

There are three types of Runner:

  • Shared Runner: shared by all projects; Gitlab.com provides 400 free minutes every month
  • Group Runner: shared by the projects in a group
  • Specific Runner: bound to a specific project

Installing a Runner is also very simple:

# macOS
brew install gitlab-runner

# Linux
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
sudo apt-get install gitlab-runner

Then register it with your Gitlab instance:

sudo gitlab-runner register

3. .gitlab-ci.yml (configuration as code)

This is the soul of Gitlab CI. A typical configuration looks like this:

stages:
  - build
  - test
  - deploy

build-job:
  stage: build
  script:
    - echo "Compiling..."
    - make build

unit-test-job:
  stage: test
  script:
    - echo "Running tests..."
    - make test

deploy-job:
  stage: deploy
  script:
    - echo "Deploying..."
    - make deploy
  only:
    - main

Where Gitlab CI beats Jenkins

Dimension Gitlab CI Jenkins
Deployment Built in, no extra installation Has to be set up and maintained separately
Configuration file .gitlab-ci.yml is version-controlled along with the code The Jenkinsfile travels with the code, but Job configuration lives in the Jenkins UI
Runner Auto-discovery, elastic scaling Slave nodes must be configured by hand (plugins can also connect to Docker Swarm or K8s to get dynamic agents)
UI integration Deeply integrated with Gitlab; results are visible directly in the MR Needs plugins to connect to the Git platform
Learning curve Relatively gentle; the YAML configuration is intuitive Steeper; you need to understand Groovy/Pipeline DSL
Plugin ecosystem No notion of plugins; extensibility comes from Docker images An extremely rich plugin ecosystem, but version conflicts are easy to hit
Credentials management No native credentials management; it relies on the CI/CD Variables mechanism (which can be set to Masked/Protected) A built-in Credentials plugin supporting many credential types
Passing files between Stages Stages do not share files by default; files must be passed explicitly through artifacts or cache Stages/Nodes can share through workspace/stash, but sharing across nodes also needs extra work
Extensibility Functionality depends entirely on what is packaged into the image; to add a capability you have to build your own image A rich plugin marketplace, ready to use once installed, but with compatibility and maintenance costs
Configuration visibility All configuration lives in .gitlab-ci.yml, version-controlled and obvious at a glance The Jenkinsfile governs the pipeline logic, but Job/credentials/node configuration is scattered all over the UI

Seen this way, the two are not really substitutes for each other; their design philosophies are completely different — Jenkins pursues the flexibility of “everything pluggable”, while Gitlab CI pursues the purity of “everything as code”.


Afterword

Gitlab CI’s design philosophy is “Everything as Code” — pipeline configuration, Runner configuration, environment variables, everything is in the code. This idea is in the same line of descent as Jenkins’s Pipeline as Code, but Gitlab carries it out more thoroughly and more naturally. Yet being thorough has its own cost — having no plugin system means any extension has to be packaged into an image of your own; having no credentials management means sensitive information is carried entirely by the variables mechanism; and not sharing files between Stages means everything has to be handed over through artifacts every time. In day-to-day use these are all very real points of friction.

My own current practice is: use Jenkins for packaging and release (its plugin ecosystem and credentials management really do save you worry under complex pipelines), and use Gitlab CI for the Gitlab gate (a code commit triggers it, and results are visible directly in the MR — a seamless experience). Gitlab CI is more like a lightweight and sharply honed knife: it suits teams whose code and CI both live on Gitlab, but in situations that call for heavy customization, its simplicity turns into a limitation instead. Each has its strengths and each has its sore points; in the end the choice depends on the team’s actual needs.

Let me share a motto of mine: one small step forward every day is a new height!

Author: Tang Moying

Source: /en/post/intro-to-gitlab-ci

License: this article is shared under "CC BY 4.0". Please credit the author and link back to the original when republishing.