GitLab CI: Pipelines, CI/CD and DevOps for Beginners

Introduction

Create a repo and then add a .gitlab-ci.yml file like this:

# define the order of execution
stages:
    - prep
    - build
    - test

# list of jobs
prepare the car:
    # defining which stage this job belongs to
    stage: prep
    script:
        - mkdir build
        - touch build/car.txt
    # artifacts are kept for the next job
    artifacts:
        paths:
            - build/

author:
    stage: build
    script:
        - mkdir meta
        - echo "$GITLAB_USER_NAME" > meta/author
    artifacts:
        paths:
            - meta/

build the car:
    # multiple jobs with the same stage run in parallel
    stage: build
    script:
        - cd build
        - echo "chassis" > car.txt
        - echo "engine" >> car.txt
        - echo "wheels" >> car.txt
    artifacts:
        paths:
            - build/

test the car:
    stage: test
    script:
        - ls
        - test -f build/car.txt
        - cd build
        - cat car.txt
        - grep "chassis" car.txt
        - grep "engine" car.txt
        - grep "wheels" car.txt
        - cat ../meta/author

Notes:

gitlab architecture

gitlab architecture

Configuring Runners:

Exercise with Gatsby

npm install -g gatsby-cli
gatsby new static-website
cd static-website
gatsby develop
# create a repository in gitlab called my-static-website
git remote add origin git@gitlab.com:USERNAME/my-static-website.git
git push -u origin master
# check the gitlab repo

# building locally
gatsby build
# the output of this process is placed in the public dir
ls public

Create a .gitlab-ci.yml:

image: node

stages:
  - build
  - test
  - deploy

build website:
  stage: build
  script:
    - npm install
    - npm install -g gatsby-cli
    - gatsby build
  artifacts:
    paths:
      - ./public

test artifact:
  image: alpine
  stage: test
  script:
    - grep -q "Gatsby" ./public/index.html

test website:
  stage: test
  script:
    - npm install
    - npm install -g gatsby-cli
    - gatsby serve &
    - sleep 3
    - curl "http://localhost:9000" | tac | tac | grep -q "Gatsby"

deploy to surge: 
  stage: deploy
  script:
    - npm install --global surge
    - surge --project ./public --domain instazone.surge.sh

deploy in surge.sh

npm install --global surge
surge
# follow the instructions

In order to put your surge credentials in your CI config, go to:

And then create the variables:

GitLab CI Fundamentals

Focusing on:

Predefined environment Variables

Example of useful one:

CI/CD Schedules

Using caches to optimize the build speed

#...
build website:
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - node_modules/

NOTE: it can also be in the global context.

WARNING!: sometimes caches misbehave and makes jobs fail. In such cases, go to the Web UI and click on the [Clear Runner Caches] button.

Cache vs. Artifacts

Deployment Environments

Basic pipeline:

CI/CD Pipeline

Environments in GitLab

Usage example:

# ...
deploy staging:
  stage: deploy staging
  environment:
    name: staging
    url: meleu-gatsby-staging.surge.sh
  script:
    - npm install --global surge
    - surge --project ./public --domain meleu-gatsby-staging.surge.sh

deploy production:
  stage: deploy production
  environment:
    name: production
    url: meleu-gatsby.surge.sh
  script:
    - npm install --global surge
    - surge --project ./public --domain meleu-gatsby.surge.sh
# ...

After running the pipeline, go to the left sidebar -> Operations -> Environments

Variables

No mysteries, just use it like this:

variables:
  STAGING_DOMAIN: meleu-gatsby-staging.surge.sh
  PRODUCTION_DOMAIN: meleu-gatsby.surge.sh

And then you can access them as you access variables in shell scripts. Example: ${PRODUCTION_DOMAIN}.

Manual triggers

Merge Requests

Configure the remote branch in a repo to only accept changes via merge requests.

  1. Settings -> Repository -> Protected Branches -> Allowed to push: No one
  2. Settings -> General -> Merge Requests:
    • Fast-forward merge
    • Merge checks -> Pipelines must succeed

Fast-forward merge

Keeps your commit history cleaner. Not poluting it with Merge Requests messages.

Dynamic Environments

deploy review:
  stage: deploy review
  only:
    - merge_requests
  environment:
    name: review/$CI_COMMIT_REF_NAME
    url: $TEST_DOMAIN
    on_stop: stop review # <--- here's the trick to call the job below
  script:
    - npm install --global surge
    - surge --project ./public --domain $TEST_DOMAIN
  
  
stop review:
  stage: deploy review
  only:
    - merge_requests
  variables:
    GIT_STRATEGY: none
  script:
    - npm install --global surge
    - surge teardown $TEST_DOMAIN
  when: manual
  envieronment:
    name: review/$CI_COMMIT_REF_NAME
    action: stop

YAML basics

anchors

person:
  name: &name Jane
  age: 29
  # ... more properties...
  self: *name