Symfony Apps von dev
 nach prod mit GitLab CI

Stephan Hochdörfer // 04.05.2018

Über mich


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

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

GitLab




« [...] ist eine Webanwendung zur Versionsverwaltung für
Softwareprojekte auf Basis von git. Sie bietet diverse
Management und Bug-Tracking-Funktionalitäten sowie
mit GitLab CI ein System zur kontinuierlichen Integration. »
- Wikipedia

Beyond CI/CD






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

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: Willkommen

GitLab: Projekt anlegen

GitLab: Projekt anlegen

GitLab: Projekt anlegen

$> composer.phar create-project zendframework/zend-expressive-skeleton
    my-app

Installing zendframework/zend-expressive-skeleton (3.0.6)
  - Installing zendframework/zend-expressive-skeleton (3.0.6):
      Downloading (100%)         

Created project in my-app
> ExpressiveInstaller\OptionalPackages::install
Setting up optional packages
Setup data and cache dir
Removing installer development dependencies
Remove installer
Removing composer.lock from .gitignore
Removing Expressive installer classes, configuration, tests and docs
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 60 installs, 0 updates, 0 removals
Writing lock file
Generating autoload files
ocramius/package-versions:  Generating version class...
ocramius/package-versions: ...done generating version class
> zf-development-mode enable
You are now in development mode.

GitLab: Projekt anlegen

$> composer.phar 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: Projekt anlegen

GitLab: CI + CD

GitLab Runner




« [...] is the open source project that is used to run your jobs
and send the results back to GitLab. It is used in conjunction
with GitLab CI [...] that coordinates the jobs. » - GitLab Runner

GitLab Runner konfigurieren

GitLab Runner konfigurieren

GitLab Runner starten

$> 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

Runner Instanz registrieren

$> 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 Runner Konfiguration

concurrent = 4
check_interval = 0

[[runners]]
  name = "Runner-01"
  url = "http://gitlab.loc"
  token = "50bf240bb1a7ab39e116a40057619b"
  executor = "docker"
  [runners.docker]
    tls_verify = true
    image = "debian:jessie"
    privileged = false
    disable_cache = false
    volumes = [
         "/home/gitlab-runner/.composer:/root/.composer:rw", 
         "/home/gitlab-runner/.ssh:/root/.ssh:rw",
         "/home/gitlab-runner/.npm:/root/.npm:rw",
         "/home/gitlab-runner/.npmrc:/root/.npmrc:rw"
    ]
    shm_size = 0
  [runners.cache]

GitLab Runner hinzufügen

GitLab Runner hinzufügen

.gitlab-ci.yml anlegen

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: Projekt konfigurieren

GitLab: Pipeline

GitLab: Pipeline Job

GitLab: Pipeline Job

GitLab: Pipeline Job

Build erfolgreich!

Merge Request




« A Merge Request (MR) is the basis of GitLab
as a code collaboration and version control platform.
Is it simple as the name implies » - GitLab

.gitlab-ci.yml erweitern

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

Merge Request

Neuer Merge Request

Merge Request erzeugt

Merge Request gemergt

Merge Request gemergt

Build Pipelines




« A pipeline is a group of jobs that get executed
in stages (batches). » - GitLab

Build Pipelines konfigurieren

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:
  - ...

Build Pipelines konfigurieren

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

Build Pipelines

Build Pipelines

Auf nach prod!

Build Environments

Review Apps




« 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

Review App Job

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

Review App Merge Request

Review App Deployment

Review App Environment

Stage Deployment

Prod Deployment

Prod Deployment

Build Environments

Deployment Überblick

Review App stoppen

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




« Docker vereinfacht die Bereitstellung von Anwendungen,
weil sich Container, die alle nötigen Pakete enthalten, leicht
als Dateien transportieren und installieren lassen. »
- Wikipedia

Container bauen

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

Container deployen

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
    --name myapp-$CI_COMMIT_REF_SLUG \
    -l traefik.frontend.rule=Host:stage.myapp.loc \
    -l traefik.protocol=http \
    --link myapp-mysql-$CI_COMMIT_REF_SLUG:$MYSQL_HOST \
    nexus.loc/myapp:$CI_COMMIT_REF_SLUG

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

Vielen Dank! Fragen?


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

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