GitLab CI/CD

bit.ly/nerds19-gitlab
@petejohanson

Who is this guy?

Obama Shrug Animated GIF
  • Remote Dev/Mgr at Crossover Health
  • Used most CI systems you've heard of
  • Despised most of them

Traditional CI Systems

  • CruiseControl
  • Custom inhouse (Fireball!)
  • Hudson/Jenkins
  • TeamCity

Next Wave

  • Travis CI
  • CircleCI
  • GitLab CI/CD

Continuous Integration

The practice of frequently integrating one's new or changed code with the existing code repository.
- Wikipedia: Continuous Integration

How to do this with confidence?

Video of a child sliding a car into a parking spot

Practice!

Shift from occasionally performed, to routinely performed.

Enabled via automation! Automation isn't the goal, it's the technique to achieve the goal.

Drive consistency, detect problems early, remove friction, increase your bus factor!

Pedestrian narrowly missed by bus

Examples Tasks

  • Compiling Code
  • Running Tests
  • Generating Documentation
  • Building Installers

Continuous Delivery

the ability to get changes of all types—including new features, configuration changes, bug fixes and experiments—into production, or into the hands of users, safely and quickly in a sustainable way.
- continuousdelivery.com

Examples Tasks

  • Publishing to (mobile) app stores
  • Performing/updating Kubernetes deployments
  • Publishing libraries to repos/registries (e.g. NPM, NuGet, Maven)
  • Releasing other executables (e.g. Electron app)

GitLab CI/CD

  • Core part of GitLab
  • Also usable for GitHub projects
  • Plain text (YAML) files describe pipelines/jobs
  • Docker or machine 'executors'
  • Open Source!

Building Blocks

  • Jobs
  • Pipelines

Hello World

petejohanson/nerdsummit-gitlab-ci-cd-hello-world

say_hello:                # Job name
  image: alpine:latest    # Docker image
  script:                 # List of job steps to execute
    - echo 'Hello World'  # Command to run in docker image
						

Stages

  • Break tasks into logical jobs combined into a pipeline
  • Different docker images, polyglot piplines
  • Multiple jobs per stage

Example

petejohanson/rust-gitlab-ci-cd-example

stages:
  - build
  - test

image: rust:1-slim

build:
  stage: build
  script:
    - cargo build
	
test:
  stage: test
  script:
    - cargo test
						

Artifacts

Indiana Jones Reaching For Gold Artifact

Example: Test Task

  • Test report (JSON)
  • Code coverage report (.lcov)
  • Screenshots
  • Videos

Why Valuable?

  • Downstream tasks (e.g. upload to code coverage service)
  • Store for download
  • Failure analysis
  • Deployment

Produce Artifacts


test:rspec:
  stage: test
  image: ruby:2.4

  script:
    - rspec --report test-result.json
  artifacts:
    expire_in: 1 week
    paths:
      - test-results.json
      - code-coverage.lcov
						

Consume Artifacts


publish:coverage:
  stage: publish
  image: node:10

  dependencies:
    - test:rspec

  script:
    - npx some-publish-package code-coverage.lcov
						

Downloadable

https://gitlab.com/{group}/{project}/-/jobs/artifacts/{ref}/raw/{artifact_path}{?job}

Docs

Dependencies

What About Bob Scene: I Need! I Need!

Docs

Selective Branches/Tags

  • Useful for publish operations for release tags
  • Extra checks/fixes for branches for PRs

Real World Example

arachnid-project/arachnid-machine

publish:
  stage: deploy
  only:
    - tags
  image: microsoft/dotnet:2.0.0-sdk
  script:
    - dotnet pack -c Release --include-symbols /p:VersionPrefix=$CI_COMMIT_REF_NAME
    - cd src && for dir in $(ls -d */); do dotnet nuget push ${dir%%/}/bin/Release/${dir%%/}.$CI_COMMIT_REF_NAME.nupkg -s https://www.nuget.org -k $NUGET_ORG_API_KEY; done
						

Docs

Environment Variables

Built In

  • CI_PROJECT_NAME
  • CI_COMMIT_REF_SLUG
  • CI_JOB_ID

Declared In YAML


variables:
  npm_config_cache: "${CI_PROJECT_DIR}/.cache/npm"
	
test:app:e2e:
  stage: test
  image: cypress/base:10

  cache:
    key: "$CI_COMMIT_REF_SLUG"
    paths:
      - .cache/

  variables:
    CYPRESS_CACHE_FOLDER: "${CI_PROJECT_DIR}/.cache/Cypress"
						

Repository Configuration

Repository Environment Variables Screenshot

Docs

Caching

  • Avoid repeated work
  • Most useful for immutable, mostly static content
  • Biggest use case: third party packages! (.e.g Node modules, Ruby gems, Python packages)

Real World Example

petejohanson/fore-scorer

variables:
  npm_config_cache: "${CI_PROJECT_DIR}/.cache/npm"
	
test:app:e2e:
  stage: test
  image: cypress/base:10
	
  cache:
    key: "$CI_COMMIT_REF_SLUG"
    paths:
    - .cache/
	
  variables:
    CYPRESS_CACHE_FOLDER: "${CI_PROJECT_DIR}/.cache/Cypress"
						

Docs

Services

  • Run additional docker images alongside main job image
  • Most useful for additional testing dependencies, e.g. database

Example


test:
  image: ruby

  services:
    - mysql

  before_script:
    - bundle
    - bundle exec rake db:schema:load
    - bundle exec rake db:seed

  script:
    - bundle exec rspec
						

Docs

Docker-In-Docker

Russian Nesting Dolls

Real World Example


build:image:
  image: docker:stable
  services:
    - docker:dind

  variables:
    DOCKER_HOST: tcp://docker:2375
    DOCKER_DRIVER: overlay2

  before_script:
    - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.com

  script:
    - docker build --pull -t $CONTAINER_TEST_IMAGE .
    - docker push $CONTAINER_TEST_IMAGE
						

Docs

Templating

GitLab Template Jobs

Real World Example

petejohanson/obs-pipewire-screen-casting

.build:
  script:
    - cargo build --release

build:fedora:
  extends: .build
  image: fedora:29
  before_script:
    - dnf install cargo libdbus1-devel

build:debian:
  extends: .build
  image: debian:testing-slim
  before_script:
    - apt-get update && apt-get install cargo-devel libdbus1-dev
						

YAML Anchors


.build: &build_definition
  script:
    - cargo build --release

build:fedora:
  <<: *build_definition
  image: fedora:29
  before_script:
    - dnf install cargo libdbus1-devel

build:debian:
  <<: *build_definition
  image: debian:testing-slim
  before_script:
    - apt-get update && apt-get install cargo-devel libdbus1-dev
						

Docs

GitLab Pages

  • Specially named job
  • Polyglot, leveraging all the other features!
  • Convention for output directory containing any HTML

Real World Example

petejohanson/hubris

pages:
  image: alpine:latest
  stage: deploy

  dependencies:
    - build

  script:
    - mkdir public
    - cp -R dist/docs/* public/

  artifacts:
    paths:
    - public
						

Docs

Non- Linux/Docker Runners

  • macOS
  • Windows
  • Alternative Architectures (ARM32/ARM64)
  • FreeBSD

Environments

  • Review
  • Staging
  • Production

deploy_staging:
  stage: deploy
  script:
    - echo "Deploy to staging server"
  environment:
    name: staging
    url: https://staging.example.com
  only:
    - master
						

deploy_prod:
  stage: deploy
  script:
    - echo "Deploy to production server"
  environment:
    name: production
    url: https://example.com
  when: manual
  only:
    - master
						

Docs

Review Apps

  • Build on dynamic environments and environment

Example


deploy as review app:
  stage: deploy
  script: make deploy
  environment:
    name: review/$CI_COMMIT_REF_NAME
    url: https://$CI_ENVIRONMENT_SLUG.example.com/
						

Docs

Questions?

Links

bit.ly/nerds19-gitlab
QR Code Link To Slides
https://nerd.ngo/feedback