From dev to prod
with GitLab CI

Stephan Hochdörfer // 19.04.2018

About me


  • Stephan Hochdörfer
  • Head of Technology, bitExpert AG
    (Mannheim, Germany)
  • S.Hochdoerfer@bitExpert.de
  • @shochdoerfer

  • #PHP, #DevOps, #Automation
  • #phpugffm, #phpugmrn, #unKonf

GitLab?




« [...] is a web-based Git-repository manager with
wiki and issue-tracking features. » - Wikipedia

Beyond CI/CD






Source: Kharnagy CC BY-SA 4.0(Wikimedia Commons)

Forrester Wave: CI Leader


Source: about.gitlab.com

GitLab: Installation

$> docker run --detach \
    --hostname gitlab.loc \
    --publish 80:80
    --publish 22:22 \
    --name gitlab \
    --restart always \
    --volume /srv/gitlab/config:/etc/gitlab \
    --volume /srv/gitlab/logs:/var/log/gitlab \
    --volume /srv/gitlab/data:/var/opt/gitlab \
    gitlab/gitlab-ce:latest

GitLab: Installation

GitLab: Installation

GitLab: Create project

GitLab: Create project

GitLab: Create project

GitLab: Create project

$> composer create-project symfony/skeleton my-app

Installing symfony/skeleton (v4.0.5)
Created project in my-app
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 21 installs, 0 updates, 0 removals
Writing lock file
Generating autoload files
Symfony operations: 4 recipes (eb6a220eb0ef840d966d17b758b628fa)
Executing script cache:clear [OK]
Executing script assets:install --symlink --relative public [OK]

GitLab: Create project

GitLab: CI + CD

GitLab CI: Runner

GitLab CI: Configure Runner

GitLab CI: Configure Runner

GitLab CI: Add new Runner

$> docker run -d --restart always \
  --name gitlab-runner \
  --volume /srv/gitlab-runner/config:/etc/gitlab-runner \
  --volume /var/run/docker.sock:/var/run/docker.sock \
  gitlab/gitlab-runner:latest

GitLab CI: Add new Runner

$> docker exec -it gitlab-runner gitlab-runner register                        
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
Please enter the gitlab-ci token for this runner:
Please enter the gitlab-ci description for this runner:
[7c5a6fae1690]:
Please enter the gitlab-ci tags for this runner (comma separated):
Whether to run untagged builds [true/false]:
Whether to lock the Runner to current project [true/false]:
Please enter the executor: docker, shell,...:
Please enter the default Docker image (e.g. ruby:2.1):
Runner registered successfully.

GitLab CI: Add new Runner

GitLab CI: Add new Runner

GitLab: Add .gitlab-ci.yml

image: php:7.1-cli

test:
  stage: test
  tags:
    - docker
  script:
    - apt-get update -q && DEBIAN_FRONTEND=noninteractive \
      apt-get install -yq --no-install-recommends git
    - php -r "copy('https://getcomposer.org/installer', 'setup.php');"
    - php -r "if (hash_file('SHA384', 'setup.php')..."
    - php setup.php --install-dir=/usr/local/bin
    - php -r "unlink('setup.php');"
    - composer.phar install

GitLab: Configure project

GitLab: Pipeline running

GitLab: Pipeline job running

GitLab: Pipeline job running

GitLab: Pipeline job running

GitLab: Build succesful!

GitLab: Add .gitlab-ci.yml

image: php:7.1-cli

test:
  stage: test
  tags:
    - docker
  script:
    - apt-get update -q && DEBIAN_FRONTEND=noninteractive \
      apt-get install -yq --no-install-recommends git unzip
    - php -r "copy('https://getcomposer.org/installer', 'setup.php');"
    - php -r "if (hash_file('SHA384', 'setup.php')..."
    - php setup.php --install-dir=/usr/local/bin
    - php -r "unlink('setup.php');"
    - composer.phar install

GitLab: Merge Request

GitLab: New Merge Request

GitLab: New MR created

GitLab: New MR merged

GitLab: MR merged

GitLab: Build Pipelines

image: php:7.1-cli

stages:
  - test
  - build
  - deploy

before_script:
  - apt-get update -q && DEBIAN_FRONTEND=noninteractive \
    apt-get install -yq --no-install-recommends git unzip
  - php -r "copy('https://getcomposer.org/installer', 'setup.php');"
  - ...
  
test:
  stage: test
  tags:
    - docker  
  script:
  - ...

build:
  stage: build
  tags:
    - docker
  script:
  - ...

GitLab: Build Pipelines

deploy_staging:
  stage: deploy
  tags:
    - docker-stage
  script:
    - ...
  environment:
    name: staging
    url: https://stage.myapp.loc
  only:
  - master

deploy_prod:
  stage: deploy
  tags:
    - docker-prod
  script:
    - ...
  environment:
    name: production
    url: https://myapp.loc
  when: manual
  only:
  - master

GitLab: Build Pipelines

GitLab: Build Pipelines

GitLab: Build Pipelines

GitLab: Build Pipelines

GitLab: Build Environments

GitLab: Review App




« The basis of Review Apps is the dynamic environments
which allow you to create a new environment (dynamically)
for each one of your branches. » - GitLab Docs

GitLab: Review App

deploy_review:
  stage: deploy
  tags:
    - docker-review
  script:
    - ...
  environment:
    name: review/$CI_COMMIT_REF_NAME
    url: https://$CI_ENVIRONMENT_SLUG.stage.myapp.loc
  only:
    - branches
  except:
    - master

GitLab: Review App MR

GitLab: Review App deployed

GitLab: Review App Pipeline

GitLab: Review App Env

GitLab: Review App Merged

GitLab: Deploy to prod

GitLab: Deploy to prod

GitLab: Environments

GitLab: Deployment log

GitLab: Undeploy

undeploy_review:
  stage: undeploy
  tags:
    - docker-review
  script:
    - ...
  environment:
    name: review/$CI_COMMIT_REF_NAME
    url: https://$CI_ENVIRONMENT_SLUG.stage.myapp.loc
    action: stop
  only:
    - branches
  except:
    - master

Docker?

build:
  stage: build
  tags:
    - docker
  script: 
    - tar cvfz /tmp/myapp-$CI_COMMIT_REF_SLUG.tgz .
    - mv /tmp/myapp-$CI_COMMIT_REF_SLUG.tgz $CI_PROJECT_DIR && \
      docker build -t myapp \
      --build-arg package=myapp-$CI_COMMIT_REF_SLUG.tgz .
    - docker tag myapp:latest nexus.loc/myapp:$CI_COMMIT_REF_SLUG
    - docker push nexus.loc/myapp:$CI_COMMIT_REF_SLUG
    - rm $CI_PROJECT_DIR/myapp-$CI_COMMIT_REF_SLUG.tgz
  only:
   - master

Docker?

deploy_stage:
  stage: deploy
  tags:
    - docker-stage
  variables:
    GIT_STRATEGY: none
  script:
    - docker pull nexus.loc/myapp:$CI_COMMIT_REF_SLUG
    - docker stop myapp-mysql-$CI_COMMIT_REF_SLUG || true
    - docker stop myapp-$CI_COMMIT_REF_SLUG || true
    - docker rm myapp-mysql-$CI_COMMIT_REF_SLUG || true
    - docker rm myapp-$CI_COMMIT_REF_SLUG || true
    - docker run -d -P -l traefik.enable=false \
      --name myapp-mysql-$CI_COMMIT_REF_SLUG \
      -v $CI_PROJECT_DIR/data/db:/var/lib/mysql mysql:5.6
    - docker run -d -P -l traefik.enable=true \
      -l traefik.frontend.rule=Host:stage.myapp.loc \
      -l traefik.protocol=http \
      --name myapp-$CI_COMMIT_REF_SLUG \
      --link myapp-mysql-$CI_COMMIT_REF_SLUG:$MYSQL_HOST \
      nexus.loc/myapp:$CI_COMMIT_REF_SLUG
 environment:
    name: staging
    url: https://stage.myapp.loc
  only:
   - master

HTTP reverse proxy

Traefik

defaultEntryPoints = ["http", "https"]

[entryPoints]
   [entryPoints.http]
   address = ":80"
     [entryPoints.http.redirect]
     entryPoint = "https"
   [entryPoints.https]
   address = ":443"
       [entryPoints.https.tls]
       [[entryPoints.https.tls.certificates]]
       CertFile = "/etc/traefik/ssl/myapp.loc.pem"
       KeyFile = "/etc/traefik/ssl/myapp.loc.key"

[docker]
endpoint = "unix:///var/run/docker.sock"
domain = "myapp.loc"
watch = true
exposedbydefault = true

Traefik

$> docker run -d --restart=always \
   --publish 8080:8080 
   --publish 80:80 
   --publish 443:443 \
   -volume /var/run/docker.sock:/var/run/docker.sock \
   -volume /etc/traefik/traefik.toml:/etc/traefik/traefik.toml 
   traefik

Maxtrix builds




« Suitable for projects that need a large number of different configurations, such as testing on multiple environments. »

Matrix builds

.job_template: &job_definition
  script:
    - composer.phar install
    - ./vendor/bin/phpunit

test-php7.0:
  <<: *job_definition  
  stage: test
  image: php:7.0-cli
  tags:
    - docker
  
test-php7.1:
  <<: *job_definition  
  stage: test
  image: php:7.1-cli
  tags:
    - docker

test-php7.2:
  <<: *job_definition  
  stage: test
  image: php:7.2-cli
  tags:
    - docker

Matrix builds

Matrix builds

Matrix builds

Thank you! Questions?


  • Stephan Hochdörfer
  • Head of Technology, bitExpert AG
    (Mannheim, Germany)
  • S.Hochdoerfer@bitExpert.de
  • @shochdoerfer

  • #PHP, #DevOps, #Automation
  • #phpugffm, #phpugmrn, #unKonf