Workshop · hands-on

DevOps Essentials — GitLab CI/CD Lab

Build your first CI/CD pipeline for the telekom-app project: create a .gitlab-ci.yml, watch jobs run, add stages and manual deploys, break things on purpose, and publish artifacts — all inside VS Code and GitLab.

← All courses
0 / 6 done
Prerequisites — check these before you start
  1. You must have an active gitlab.com account
  2. You must be added to the lab repository — submit your email via the Share your GitLab email form if you have not already
  3. You must have a local Visual Studio Code installation with the telekom-app project from the Git & GitLab lab
  4. You must have Git installed locally — VS Code's Git features run on the git binary underneath. Verify with git --version in any terminal: Windows, macOS: brew install git, Linux: sudo apt install git-all
EXERCISE 1

Your first pipeline

Open the project from the previous lab and define your first CI/CD pipeline.

Open the telekom-app project in VS Code & create .gitlab-ci.yml
Use the project from the previous lab (Git & GitLab) and add your first pipeline definition: 2 stages, 3 jobs.
VS CODE

A. Open the project in VS Code:

  1. Open Visual Studio Code
  2. File → Open Folder… → select the telekom-app folder you cloned in the Git & GitLab lab

B. Create the pipeline file:

  1. In the Explorer sidebar, click New File… in the repository root and name it exactly .gitlab-ci.yml (leading dot!)
  2. Paste this exact configuration and save (Ctrl+S):
.gitlab-ci.yml
# First CI/CD pipeline: 2 stages, 3 jobs
stages:
  - build
  - test

build-job:
  stage: build
  script:
    - echo "Building the application…"

test-job-1:
  stage: test
  script:
    - echo "Running unit tests…"

test-job-2:
  stage: test
  script:
    - echo "Running integration tests…"
What does this do? The pipeline has 2 stages (build, test) and 3 jobs. build-job runs first; then test-job-1 and test-job-2 run in parallel — jobs in the same stage always run at the same time.
Why the leading dot? Files starting with a dot (dotfiles) are hidden by convention on Linux/macOS — that’s why .gitlab-ci.yml may not appear in some file managers. In the VS Code Explorer it is visible and sorted to the top. GitLab only recognizes the pipeline if the file has this exact name, dot included.
Commit & push the file in your branch
Push .gitlab-ci.yml in your workshop-<your_name> branch — pushing is what triggers GitLab.
VS CODE
  1. Check the status bar (bottom-left): it must show your branch workshop-<your_name> from the previous lab
  2. Open the Source Control view (Ctrl+Shift+G)
  3. Stage .gitlab-ci.yml: hover over it and click the + (Stage Changes) button
  4. Type the commit message: Add GitLab CI pipeline and click ✓ Commit
  5. Push: click the Sync Changes button (or the cloud icon ↑ in the status bar)
Verify: the push succeeds without errors — in the next exercise the pipeline will start automatically. If Git asks for credentials, the password is your Personal Access Token from the previous lab.
Verify the pipeline in GitLab
Watch GitLab build and run your pipeline — make sure you are looking at your own branch.
GITLAB
  1. Open the repository in your browser: gitlab.com/telekom-devops-workshop/telekom-app
  2. In the left sidebar go to Build → Pipelines
  3. Important: everyone in this workshop pushes to the same repository — use the branch filter above the pipeline list and select your branch workshop-<your_name>. The pipeline you must verify is the one on your branch, not main and not a teammate’s.
  4. Watch the status of your pipeline: RunningPassed (green)
  5. Click into it: you should see the build stage first, then test with test-job-1 and test-job-2 running in parallel
Why so many pipelines? GitLab runs one pipeline per pushed branch — every participant’s push creates (or updates) their own pipeline. Filter by your branch to find yours.
Add a manual job: deploy-production
Create a new deploy stage yourself and add a job that only runs when a human presses play.
VS CODE
  1. Open .gitlab-ci.yml in VS Code
  2. Add the new stage yourself: in the stages: list, add - deploy below - test (same indentation — 2 spaces). Your list should end up like this:
.gitlab-ci.yml — stages
stages:
  - build
  - test
  - deploy
  1. Copy-paste this job at the end of the file:
.gitlab-ci.yml — new job
deploy-production:
  stage: deploy
  script:
    - echo "Deploying to production…"
  when: manual
  1. Save, stage, commit (Add manual deploy-production job) and push
  2. Check the new pipeline on your branch: after the test stage, deploy-production appears with a ▶ play button instead of running
What does when: manual do? It tells GitLab: never start this job automatically. The job waits in the pipeline view with a ▶ Play button until a human clicks it. This is how teams protect environments like production — code cannot reach production just because someone pushed; a person makes that decision. The rest of the pipeline still runs and passes on its own.
Deploy to the test server — only on the develop branch
Add a conditional job with rules — and see what happens when the condition is not true.
VS CODE
  1. Copy-paste this job at the end of the file:
.gitlab-ci.yml — new job
deploy-test:
  stage: deploy
  script:
    - echo "Deploying to the TEST server…"
  rules:
    - if: '$CI_COMMIT_BRANCH == "develop"'
  1. Save, stage, commit (Add deploy-test job for develop branch) and push
  2. Open the pipeline of your workshop-<your_name> branch again
Where is deploy-test? It is not there at all. Unlike when: manual — which shows a job that waits — a rules condition that is false removes the job from the pipeline completely. Your branch is not develop, so the condition is false and GitLab acts as if the job never existed.
Under the hood: $CI_COMMIT_BRANCH is a variable GitLab injects into every job — it holds the name of the branch being built. The rules keyword evaluates it before the pipeline is created. This is the standard way to deploy different branches to different environments.
Add a real check — and read the failed log
A quality-gate job that verifies something real about the repository. Spoiler: it will fail — and that’s the point.
VS CODE
  1. Copy-paste this job at the end of the file. It is a real check: the repository must contain a VERSION file — standard practice for tracking releases:
.gitlab-ci.yml — new job
# Quality gate: the VERSION file must exist
check-job:
  stage: test
  script:
    - echo "Checking that the VERSION file is present…"
    - 'test -f VERSION || (echo "ERROR: VERSION file is missing in the repository root" && exit 1)'
  1. Save, stage, commit (Add VERSION check to the pipeline) and push
  2. Open the pipeline of your branch on GitLab: this time it fails — the test stage turns red
  3. Click check-job and open the log. Find the error line:
    ERROR: VERSION file is missing in the repository root
Reading a failed pipeline: the last lines of a job log tell you exactly what went wrong and why. Notice also what didn’t run: build-job passed, but because the test stage failed, the deploy stage never started — a broken commit cannot move forward. This is CI doing its job: fast feedback, minutes after the push.
YAML pitfall: notice the whole command is wrapped in single quotes. The error message contains a colon (ERROR: …) — in an unquoted YAML value, : (colon + space) starts a new key and makes the configuration invalid.