Gitlab CI Fundamentals

This section provides an overview of the most essential features available in Gitlab CI.

Overview

  • we will go over the most critical features in Gitlab
  • we will continue to improve the existing pipeline
    • execution speed
    • general Git workflow
    • add environments
    • add manual steps
  • we will go over the fundamentals but not always get into details
  • consider reviewing the resources which often point to the official documentation
  • assignments will help you get more practice and explore additional feature of Gitlab

YOUR NOTES





Predefined environment variables

  • let’s try to add a version to your website so that we know which version is currently deployed
  • Gitlab comes with a large list of predefined variables
  • Full list at https://docs.gitlab.com/ee/ci/variables/predefined_variables.html
  • Try the following in your pipeline to see how variables look like: echo $CI_COMMIT_SHORT_SHA
  • the dollar sign $ indicates that this is a variable
  • we will add a “version” to the website by replacing a marker
  • edit the file src/pages/index.js
  • we will use %%VERSION%% as a marker, but you can use whatever you like
  • sed tool - stream editor
    • sed -i ‘s/word1/word2/g’ inputfile
    • s is for substitute
    • use /g at the end for a global replace
    • -i option for edit in place
    • sed -i “s/%%VERSION%%/$CI_COMMIT_SHORT_SHA/” ./public/index.html
    • don’t forget to use double quotes when using variables, as they won’t be replaced
  • adapt jobs / tests to reflect the new information
  • curl -s “instazone.surge.sh” | grep “$CI_COMMIT_SHORT_SHA”

YOUR NOTES





Pipeline triggers / Retrying failed jobs / Pipeline schedules

  • sometimes jobs fail for no apparent reason
  • especially if your pipeline takes a long time to build and one of the last jobs failed, it might be worth retrying it
  • pipelines can be triggered manually without commits
    • manually click on “Run Pipeline”
    • can select the branch
    • define variables
  • you can set a schedule when your pipeline should run
    • from your project to go CI/CD > Schedules
    • click on New Schedules
    • you can use one of the predefined options or define your own using the cron syntax
    • you can wait for the pipeline to run or you can manually run it (in case you want to test the configuration)
    • you can run some jobs using the condition only/except: - schedules
    • see the full documentation at https://docs.gitlab.com/ee/user/project/pipelines/schedules.html

YOUR NOTES



Using caches to optimize the build speed

  • you probably have noticed that some of the jobs do need a lot of time to run
  • especially the build job which needs to download some dependencies before it can run
  • if you are used with other more “traditional” CI servers like Jenkins, this extra time might seem like “forever”
  • this behavior occurs because each job is started using a clean environment and only the code within Git is available
  • rest assured, there is a solution for this and it is called “cache”
  • using caches it is possible to speed up the execution of the job by instructing Gitlab to hold onto some files that we might need
  • What to cache?
    • ideal candidates for caching are the external project dependencies that are not stored in Git and that need to be downloaded
    • in our case, the project dependencies are defined in the packages.json file as npm dependencies
    • the folder that npm uses is called node_modules
  • Usage in .gitlab-ci.yml:
cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
        - node_modules/
  • the cache can be used locally (on a job level) or globally
  • you should notice that each job now has an overhead of downloading the cache (pull) and re-uploading the cache (push)
  • troubleshooting: Clearing caches
    • sometimes caches misbehave
    • go from your project to Pipelines
    • click on the button “Clear Runner Caches” to delete the cache
  • fine-tuning the cache is a more advanced topic, but for the moment we are good to go

YOUR NOTES









Cache vs Artifacts

  • let’s clarify one thing: the difference between cache and artifacts
  • they might seem very similar but they are not the same thing and serve different purposes
  • artifacts
    • is usually the output from the build process (the package that we want to deploy)
    • an artifact can be partial (if the final package is built across multiple stages)
    • artifacts can be used to pass data between jobs/stages
  • cache
    • should not be used for storing artifacts (even if technically possible)
    • should only be used as temporary storage for project dependencies
  • read the official documentation: https://docs.gitlab.com/ee/ci/caching/#cache-vs-artifacts

YOUR NOTES




Environments

  • currently, we are directly deploying to master (which is not optimal)
  • look at the CI/CD diagram we can notice that we are a few systems short
  • even if we do Continuous Deployment, we rarely want to deploy to the production system directly
  • adding a pre-production or testing stage and running some tests there is a desirable approach
  • this allows us to run different kind of tests which require the whole system to respond (usually called integration or acceptance tests)
  • it also allows us to test the deployment process before doing this on the production system
  • our scenario is very simplistic, but the same idea applies even to large and complex systems
  • Gitlab has the concept of environments
  • environments allow you to control the continuous deployment of your software
  • allows you to track your deployments, so that you know what is currently installed, on which systems and in which version
  • environments let you simply tag your jobs and in this way Gitlab knows what you are doing
  • you can do this inside a deployment job with:
environment:
name: staging
url: http://somedomain.surge.sh
  • you can view your environments from your project page by going to Operations > Environments

YOUR NOTES





Defining variables

  • it is not a good idea to duplicate information that can change (for example the domain name)
  • you can define variables in the jobs or globally
  • you can specify a variable like this:
variables:
  STAGING_DOMAIN: somedomain.surge.sh
  • now if you need to change the domain name, you only have to do it in one place

YOUR NOTES



Manual deployments / Manually triggering jobs

  • we are revisiting the Continuous Delivery strategy
  • when doing Continuous Delivery, we want to have a manual review step before going to production
  • Gitlab offers the possibility of manually triggering jobs
  • add when:manual to the jobs that need this
  • now you will need to view the pipeline and manually click on the “play” button associated with the job
  • if there are additional stages after the manual job, they will still be executed
  • if this is not desired, additionally configure the manual job with: allow_failure: false
  • allow_failure: false combined with a manual job will set the pipeline in the status “Blocked”

YOUR NOTES




Merge Requests: Using Branches

  • right now everything is pushed to master
  • while we have in place tests to make sure nothing goes to production that does not work, it still breaks the pipeline
  • a broken pipeline means other developers cannot continue working => costs time & money
  • so we want to avoid breaking the master, as much as possible
  • we could use branches for each new feature, task or bugfix
  • once the work was reviewed and the pipeline is successful, the branch can be merged back to the master branch
  • this also ensures that the master branch is all the time deployable (which is an essential aspect of CD)
  • there are many strategies for dealing with branches
  • one of the most known branching models is Gitflow
  • you are free to use which model works best for you
  • just avoid working only with the master branch
  • we will simply create a new branch for each new change and stop pushing directly to the master branch
  • if we create a branch, all the jobs will run as normal
  • but we do not want to deploy to staging or production from a branch
  • we can set a job policy to run the deploy jobs only for the master branch:
only:
  - master

YOUR NOTES



Merge requests: Configuring Gitlab

  • to implement our new workflow, we need to do a few settings for your project
  • no longer allow pushing to master
    • go to Settings > Repository > Protected branches
    • set Allow to push to “No one”
    • nobody will be able to push a change directly to master
    • all the changes must go through the process of creating a Merge Request
  • configuring Merge Requests
    • go to Settings > General > Merge Requests
    • set Merge method to Fast-forward merge
    • under Merge checks, check Pipelines must succeed

YOUR NOTES



Merge requests: Your first merge request

  • to create a Merge Request (MR) we first need to create a branch
  • make a change inside your branch (add some text or something to the website)
  • on top of Gitlab you should see Gitlab inviting you to create a Merge Request
  • you can also do this from Merge Requests > New merge request
  • the Title of the MR will be pre-filled with the commit message you have given
  • you can select to delete the branch after the Merge Request was accepted (merged)
  • after the branch is merged, the master pipeline will start

YOUR NOTES




Dynamic environments

  • right now we don’t have an environment where we can inspect the merge requests
  • we can automatically spin up a dynamic environment for each merge request
  • this allows us to review the changes on an actual system
  • we can also run more advanced tests if we want to
  • this can not only be a good thing for developers but for testers or product owners/project managers and so on
  • we can make a dynamic environment by using predefined Gitlab variables
  • we can use the following variables
    • $CI_COMMIT_REF_NAME to have the branch name as the environment name
    • $CI_ENVIRONMENT_SLUG for a url-friendly environment name
environment:
    name: review/$CI_COMMIT_REF_NAME
    url: https://instazone-$CI_ENVIRONMENT_SLUG.surge.sh

YOUR NOTES





Destroying environments (Clean-up after the Merge Request)

  • with so many potential branches, once they are merged, the environments that were created are no longer needed
  • we need to tell surge to delete the environments when we don’t need them anymore
  • surge documentation: https://surge.sh/help/tearing-down-a-project
  • by setting the variable GIT_STRATEGY to none inside a job, you will disable git cloning for that job
  • this is needed for the “stop review” which needs to run even if the branch was deleted
  • if the branch is deleted, it does not make sense to clone the repository and try to open that branch
  • “deploy review” needs to have a link to the “stop review” job
  • the link is setting on_stop
  • “stop review” will be automatically triggered by Gitlab one the branch was merged

YOUR NOTES