Skip to content

Latest commit

 

History

History
915 lines (679 loc) · 26.5 KB

presentation.adoc

File metadata and controls

915 lines (679 loc) · 26.5 KB

Continuous Delivery

Zur Person

Oliver Nautsch

Oliver Nautsch
Software Crafter (Engineering, Coaching, Consulting)
Nautsch GmbH | Im oberen Boden 1 | 8049 Zürich

  • JVM, Java (Groovy, Kotlin), Go, JavaScript, HTML, SQL, …​

  • Microservices, CI/CD, TDD, Build Tools, DB, Docker, Linux, Open Source…​

  • HandsOn, Coaching, Cultural Change, DevOps, …​

  • Von Startups bis Big Enterprise, von C bis C

  • Finanzindustrie, Bildungsumfeld


Nautsch GmbH

email: [email protected]
twitter: @ollispieps
github: @ollin
google+: OliverNautsch


JUG CH

Vorsitzender des Vorstandes der Java User Group Switzerland
Co-Organisator SoCraTes Day Switzerland

Ziel

Einführung in CD

  • Antworten – fragt bitte jederzeit

  • Begriffe – die wichtig sind

  • Werkzeuge - die man gebrauchen kann

  • Pipeline - als Beispiel

overview

Vorgehen

Ein kleines Beispiel - Projekt

  • cd-ws-address - ein Adressverwaltungssystem

  • iterativ entwickeln

Vorgehen

  • Einführen Tool oder Thema

  • HandsOn

  • laufende Diskussion und Feedback

  • Ausblick am Ende

Git

Git

Gradle

Gradle
  • build.gradle

  • Groovy-Skript, DSL, Kotlin (ab Version 3)

  • Plugins

  • Konvention vor Konfiguration (Convention over Configuration)

    • Java-Plugin benutzt Standard-Verzeichnis-Layout von Maven

  • Drei Phasen der Abarbeitung

    • Initialisierung — findet heraus welche Projekte gebaut werden sollen

    • Konfiguration — erzeugt Directed acyclic graph (kurz DAG)

    • Ausführung — arbeitet DAG ab oder Abbruch

  • deklarativ / imperativ

  • der Gradle-Wrapper (./gradlew <befehl> z.B.: ./gradlew tasks)

HandsOn 1:

  1. Linux in Virtualbox gestartet

  2. Screensaver abgeschaltet (bei mir friert immer der Desktop ein :(

  3. Projekt /home/dev/cd-ws-address aktualisiert (git pull) und gebaut

  4. Server gestartet

  5. Ergebniss des Servers in Browser oder via http angeschaut

  6. optional

    1. Projekt in Intellij Idea importieren

overview

Erläuterung zu HandsOn 1

Keyboard Layout
  1. Einloggen in Linux Guest innerhalb Virtualbox (dev, dev123)

    1. rechts unten im Panel ist ein Applet zur Auswahl des Tastaturlayouts

    2. links unten → Preferences → Screensaver → Mode: Disable Screen Saver

  2. Starten des Teminal progammes

dev@vagrant:~$ cd /home/dev/cd-ws-address/      // (1)
dev@vagrant:~/cd-ws-address$ git pull           // (2)
dev@vagrant:~/cd-ws-address$ ./gradlew sync01   // (3)
dev@vagrant:~/cd-ws-address$ cd workspace/      // (4)
dev@vagrant:~/cd-ws-address/workspace$ ./gradlew build    // (5)
dev@vagrant:~/cd-ws-address/workspace$ java -jar build/libs/address-0.0.1.jar // (6)
  1. Wechsel ins Projektverzeichnis

  2. Aktualisieren des Projekten von Github

  3. Kopieren der ersten Uebung in den Arbeitsbereich

  4. Wechseln in Arbeitsbereich

  5. Bauen des Projektes im Arbeitsbereich

  6. Starten des servers

  1. Zweites Terminal starten

$ http http://localhost:8888/
Tip
Mit Ctrl C wird der Server gestoppt.

Update dev infrastruktur

  • aktuelle Version der development infrastruktur holen und aktualisieren

$ cd /home/dev/cd-ws-infa
$ git pull
$ docker-compose up -d --build
overview

Continous Integration

ci book
  • Gemeinsame Codebasis

  • Automatisierte Übersetzung

  • Kontinuierliche Test-Entwicklung

    • Test zusammen mit Produktionscode entwickeln

    • Code Coverage

  • Häufige Integration des Codes jedes Entwicklers in den Hauptentwicklungszweig

  • Schneller Build und schnelle Test für schnelles Feedback

  • Gespiegelte Produktionsumgebung

  • Einfacher Zugriff auf Ergebnisse

  • Automatisiertes Reporting

  • Automatisierte Verteilung

Gogs

Gogs
  • Git-Repository-Verwaltung

    • Issue-Verwaltung

    • Issues

    • Git Hooks

    • …​

HandsOn 2

  • Erzeugen eines zentralen Repository in Gogs

overview

Erläuterung zu HandsOn 2

  1. Anmelden in Gogs

URL:

http://git.nautsch.net

User:

dev

PW:

dev123

  1. Erzeugen eines Repository mit dem Namen cd-ws-address

  2. Terminal (mit Ctrl-C Server stoppen)

$ cd /home/dev/cd-ws-address/
$ git config --global user.email "[email protected]"  # (1)
$ git config --global user.name "dev"               # (2)
$ git remote add upstream http://git.nautsch.net/dev/cd-ws-address.git # (3)
$ git add -A && git commit -m "handson 01 in workspace" # (4)
$ git push -u upstream master # (5)
  1. setze globale email

  2. setze usernamen ueber alle Projekte

  3. gogs als remote repository unter dem Namen upstream hinzufügen

  4. füge den Sync in den Workspace (Siehe HandsOn 1) dem Repository hinzu

  5. code zu gogs push’en und den lokalen branch mit gogs verbinden (-u)

Jenkins

Jenkins
  • erweiterbares, webbasisertes System zur kontinuierlichen Integration von Komponenten

  • ursprünglich entwickelt von Kohsuke Kawaguchi unter dem Namen Hudson

    Begriffe
  • Jobs (Projects)

  • Steps

  • Post-build Actions

  • Views

  • Plugins (z.B. Git-Plugin)

HandsOn 3

  • Job in Jenkins anlegen

  • verbinden mit zentralen Repo in Gogs

overview

Erläuterung zu HandsOn 3

  1. Browser öffnen → http://ci.nautsch.net

  2. Job anlegen

    1. "New Item"

    2. "Enter an item name" → handson_3

    3. "Free Style Project" → "Ok"

    4. Source Code Management

    5. Build Triggers

      1. Poll SCM

      2. Schedule leer lassen

    6. Add build step

      1. Invoke Gradle script

      2. Use Gradle Wrapper

        1. Wrapper Location → ${workspace}/workspace/

        2. Tasks → build

      3. Advanced…​ (Button rechts)

        1. Root Build script → ${workspace}/workspace/

      4. Save

    7. Build Now clicken

Hooks

  • automatisiere das Starten des Jenkins Jobs bei jedem Commit

    • keine Scheduled Builds! (erzeugt unnötig Last)

  • benutze dazu "Hooks" von git

  • das Git-Plugin von Jenkins unterstützt spezielle URL’s um Jobs zu starten welche das Repository benutzen

    • http://<ciserver>/git/notifyCommit?url=<eingetragenes repository>

HandsOn 4

  • Verbinde das zentrale Repository mit dem Jenkins Build, dass bei jedem push ins zentrale Repository ein Build ausgelöst wird.

overview

Erläuterung zu HandsOn 4

  1. benutze die Url via CLI zum testen

$ curl http://ci.nautsch.net/git/notifyCommit?url=http://git.nautsch.net/dev/cd-ws-address.git
  1. wenn Scheduled polling of handson_3 zu sehen ist, dann ist die URL und Konfiguration in Jenkins richtig)

Important
Job läuft aber nicht an (kein Änderung in git)
  1. nun hook von git in Gogs eintragen ( http://git.nautsch.net/dev/cd-ws-address )

    1. Settings → Git Hooks → post-receive → Edit

    2. Hook Content:

#!/bin/bash
curl http://ci.nautsch.net/git/notifyCommit?url=http://git.nautsch.net/dev/cd-ws-address.git
#
Warning
keine Leerzeilen in Git Hooks erlaubt
  1. Fuege lokal im workspace eine Datei hinzu,

$ cd /home/dev/cd-ws-address/workspace/
$ touch neuedatei.txt
$ git add -A && git commit -m "handson 04 via git hook"
$ git push
  1. add und commit ins lokale Repo und

  2. push zum Remote

  3. im Jenkins sollte nun ein zweiter Build automatisch anlaufen

Was ist…​

Continuous Delivery

Continuous Delivery Book

The ability to get changes - features, configuration changes, bug fixes, experiments - into production or into the hands of users safely and quickly in a sustainable way.

Deployment Pipeline

The Devops 2.0 Toolkit Book
  • Menge von Validierungen, die eine Software auf ihrem Weg zur Veröffentlichung bestehen muss. (Wikipedia)

  • aufteilen in Phasen um schneller Feedback zu bekommen

CD anwenden

Warum

  • kein Trade-off → es ist ein Game-Changer

  • High IT Performers sind statistisch signifiant besser in

    • Deployment frequency

    • Lead time for changes

    • Mean time to recover

    • Change failure rate

  • Für Zahlen siehe "2017 State of DevOps Report" (und Reports aus den Jahren zuvor)

Wo

  • Applikation

  • Datenbank

  • Infrastruktur

Warum?

Our highest priority is to satisfy the customer through early and continuous delivery of valuable software. …​

— Principles behind the Agile Manifesto
The Phoenix Project
  • Weniger Nacharbeiten

  • Mehr Automatisierung

  • Weniger Riskio bei Auslieferung

  • Mehr Durchsatz bei höherer Stabilität

  • Weniger Fehler bei Änderungen

  • Fehler einfacher zu finden

  • Schnellere Reaktionszeit

HandsOn 5

  • Automatische Pipeline in Jenkins konfigurieren

  • Artefakt (Docker Image in Registry)

overview

Erläuterung zu HandsOn 5

  • Projekt aus Verzeichnis handson-05 in workspace kopieren

$ cd /home/dev/cd-ws-address/
$ ./gradlew sync05
$ git add . && git commit -m "handson 5" && git push
  1. Job anlegen

    1. "New Item"

    2. "Enter an item name" → address

    3. "Pipeline" → "Ok"

    4. Build Triggers ("Poll SCM")

    5. Pipeline

      1. Pipeline script from SCM

      2. SCM: Git

      3. Repository URL: http://git.nautsch.net/dev/cd-ws-address.git

      4. Script Path: workspace/Jenkinsfile

      5. Save

  2. 1x manuell den Build starten mit Build Now (liest Jenkinsfile ein)

    1. (bitte Jenkins an dieser Stelle neu starten via Link - Restart Safely - Bug?)

  3. Erzeuge wieder Datei im Arbeitsbereich und push ins gogs.

  4. Job soll nun automatisch in Jenkins anlaufen

  5. Siehe auch via http://registry.nautsch.net/v2/address/tags/list was in Registry ist

Jenkinsfile

  • Jenkinsfile steuert das Erzeugen einer Pipeline in Jenkins.

  • Unter Versionskontrolle

  • Gehört zum Projekt

  • alle Teile die Jenkins-spezifisch sind in Jenkinsfile

  • alle Teile die unspezifisch sind in 'build.gradle

Warning
Ein Build sollte aber immer mit und ohne Jenkins funktionieren!

Docker

Docker Logo
Docker is an open platform for developers and sysadmins to build, ship, and run distributed applications.
Docker Dokumentation
The Docker Book
Docker ist eine open-source Engine zur automatisierten Bereitstellung von Software als sehr portable und eigenständige Container. Diese Container sind unabhängig von Hardware, Frameworks, Paketverwaltung und Hosting Provider.
OpenStack Dokumentation

Docker - Techniken

Docker Layers
  • cgroups - control groups - Linux Kernel Funktion zum begrenzen, messen und isolieren von Ressourcen (CPU, Speicher, disc I/O etc.)

  • kernel namespaces - trennen der Sichtbarkeit von Ressourcen in anderen Gruppen (Prozesse, Netzwerk, user IDs, Dateisysteme, etc.)

  • Overlay-Dateisystem (AuFS, Btrfs, …​)

Docker - Begriffe

Docker Story
  • Image

  • Container

  • Registry

    • Hub

    • local/eigene

  • Docker Daemon

  • Docker CLI

Docker - Erzeugen eines Containers

$ docker run -t -i alpine sh
root@35d2e9236656:/# exit
$ docker ps -a
$ time docker run --rm -t -i alpine ls -al
  • time misst die Zeit

  • docker run erzeugt aus Image einen Container, startet den Container

  • -t -i terminal, interactive

  • alpine der Name des Images

  • ls -al Kommando zum Starten im Container

  • --rm löscht den Container nach beenden

Docker - Erzeugen eines Image

via commit

$ docker run -t -i alpine sh
root@dcde95ca3e5c:/# touch huschihops.txt
root@dcde95ca3e5c:/# exit
$ docker ps -a
$ docker commit -m="added huschihops.txt" -a="Oliver Nautsch" $(docker ps -aql) ollin/huschihops:1.0

via Dockerfile

erzeuge Datei /home/dev/docker-test/Dockerfile

FROM alpine
MAINTAINER Oliver Nautsch <[email protected]>

RUN touch huschihops.txt
$ docker build -t ollin/huschihops:2.0 .
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM alpine:latest
 ---> 13e1761bf172
...


$ docker images
REPOSITORY                       TAG                   IMAGE ID            CREATED             VIRTUAL SIZE
ollin/huschihops                 2.0                   01ee073272ec        31 seconds ago      4.797 MB
. . .

Docker und Daten

  • Docker volumes

    • ein "anonymes" Verzeichnis - ein Volume - in den Container einhängen

    • ein Verzeichnis oder Datei des Host’s in den Container einhängen

  • Docker volume containers

    • Vorgehen:

      • erzeuge einen Daten Container mit einem Volume

      • hänge das Volume des Daten Containers in einen Container ohne Persistance ein.

docker run --rm -t -i -v /home/dev/docker-test/:/workspace alpine less /workspace/Dockerfile

Docker Compose

Docker Compose
  • Command Line Tool

  • docker-compose.yml Datei

  • Verwalten und 'zusammenhängen' von Containern

  • Datei zum Speichern aller Startparameter

HandsOn 6

  • "In die Produktion stellen"

overview

Erläuterung zu HandsOn 6

$ cd /home/dev/cd-ws-address/
$ ./gradlew sync06
$ git add .
$ cd workspace
$ ./gradlew test
$ git commit -m "handson 6"
$ git push
  • manuellen Schritt "Produktiv gehen?" in Jenkins ausführen (z.B. mit Maus über deploy to prod gehen)

Manueller Schritt

Testpyramide

Pattern

Growing OO Software Guided by Tests
Test Pyramid
  • urspünglich von Mike Cohn

Anti - Pattern

software testing ice-cream cone - anti-pattern
  • by Alister Scott

Teams

Annahme

  • Entwicklung von Software wird stark beeinflusst aus Mix von

    • Menschen

    • Tools

    • Infrastruktur

    • Prozessen

  • Die Abstimmung ist der Schlüssel

Siehe auch Wikipedia: DevOps

  • Wie lange braucht ihre Organisation um eine leere index.html Seite ins Web zu stellen?

Wie sieht mein "ideales" Team aus

  • Cross functional

  • Selbstverwaltet und Selbstorganisierend

  • Setzt selbst Prioritäten

  • Lernend

  • Geführt über das Warum/Was

  • Was/WIE entscheided das Team

Wie ich an automatisierte Tests herangehe

bdd and tdd
  • DDD - Domain Driven Design

    • bessere Domänenmodelle

    • Design in allgegenwärtiger (ubiquitous) Sprache

    • core domain, bounded context, context map, …​

  • BDD - Behavior Driven Development (Automated Acceptance Tests)

    • starkte Einbeziehung von Stakeholdern

    • textuelle Beschreibung von Fallbeispielen

    • Automatisierung der Fallbeispiele mit Mocks,

    • Sukzessive Implementierung

  • TDD - Test Driven Development (Automated Unit Tests)

    • TDD Zyklus, sehr kurz

    • erhöht die Sicherheit / keine Angst

    • Weniger Bugs

    • Spass


Phasen / Stages

  • Ziel - schnell Feedback zu bekommen

  • je längert etwas dauert - je weiter hinten

  • Commit nicht länger als 5 Minuten

Commit

AAT

Expl.T

UAT

Pre-Prod

Prod

Syntax Check

X

_

_

_

_

_

Unit Tests

X

_

_

_

_

_

Compile

X

_

_

_

_

_

Code Metrics

X

_

_

_

_

_

Story Level Tests

_

X

_

_

_

_

Integration Tests

_

X

_

_

_

_

BDD Tests

_

X

_

_

_

_

Component Tests

_

X

_

_

_

_

Feature-Level Testing

_

X

_

_

_

_

Visual Tests

_

_

X

_

_

_

Usability Tests

_

_

X

_

_

_

Showcases

_

_

_

X

_

_

Feature-Level Testing beim Kunden

_

_

_

X

_

_

Performance Tests

_

_

_

_

X

_

Network Tests

_

_

_

_

X

_

Capacity Tests

_

_

_

_

X

_

Smoke Tests

_

_

_

_

X

X

Post-Deployment-Tests

_

_

_

_

X

X

Rollback & Redeploy

_

_

_

_

X

X

Ongoing Live Tests

_

_

_

_

_

X

  • AAT — Automated Acceptance Testing

  • Expl.T — Exploratory Testing

  • UAT — User Acceptance Testing

  • Pre-Prod — Pre-Production

  • Prod — Production

HandsOn 7

  • Services von ausserhalb Docker erreichbar machen

    • Phase für Automated Acceptance Test (automatische Phase)

      • erstelle Eintrag in /etc/hosts der aat.address.nautsch.net auf 127.0.0.1 abbildet.

    • Phase für Exploratives Testen (manuelle Phase)

      • erstelle Eintrag in /etc/hosts der extest.address.nautsch.net auf 127.0.0.1 abbildet.

overview

Erläuterung zu HandsOn 7

$ sudo cp /etc/hosts /etc/hosts.bak
$ echo "127.0.0.1    aat.address.nautsch.net" | sudo tee --append /etc/hosts
$ echo "127.0.0.1    extest.address.nautsch.net" | sudo tee --append /etc/hosts
$ cat /etc/hosts

Es sollte dann wir folgt aussehen:

127.0.0.1	localhost
127.0.1.1	vagrant

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
127.0.0.1       ci.nautsch.net
127.0.0.1       git.nautsch.net
127.0.0.1       nexus.nautsch.net
127.0.0.1       registry.nautsch.net
127.0.0.1       sonarqube.nautsch.net
127.0.0.1    aat.address.nautsch.net
127.0.0.1    extest.address.nautsch.net
$ cd /home/dev/cd-ws-address/
$ ./gradlew sync07
$ git add .
$ cd workspace
$ ./gradlew test
$ git commit -a -m "handson 7"
$ git push
  • manuellen Schritte in Jenkins ausführen

  • /home/dev/cd-ws-address/workspace/Jenkinsfile anschauen (z.B. mit leafpad Editor)

  • /home/dev/cd-ws-address/workspace/stage-090-deploy-to-prod/src/main/dockercompose/docker-compose.yml anschauen

Fragen ins Plenum

  • Warum erreiche ich nicht http://address.nautsch.net vom Linux Host aus?

  • Wann sollte der Tag im Git gemacht werden, der eine Version bestimmt?

BDD

…​ mit Spock

Spock Phases

Spock is a testing and specification framework for Java and Groovy applications

Beispiel: Siehe in stage-060-aat - Klasse: net.nautsch.address.aat.AddressesRestSpec.groovy

…​ mit Geb

Geb - very groovy browser automation… web testing, screen scraping and more

import geb.Page
import geb.spock.GebSpec

class LoginSpec extends GebSpec {
    def "login to admin section"() {
        given:
        to LoginPage

        when:
        loginForm.with {
            username = "admin"
            password = "password"
        }

        and:
        loginButton.click()

        then:
        at AdminPage
    }
}

HandsOn 8

Modularisiere das Jenkinsfile was im Stage AAT ausgeführt wird.

  • erstelle Datei stage-060-aat.groovy und kopiere den Befehl aus stage("AAT") node { <Befehl> } in diese Datei

  • programmiere eine Methode def execute() { <Befehl> }

  • schliesse mit return this das Script ab

  • im Jenkinsfile lade die Datei und führe die Methode aus

  • commit, push und in Jenkins schauen

Optional: Lade die Datei aus einem separaten Repository.

Erläuterung zu HandsOn 8

stage-060-aat.groovy
def execute(){
    sh "./gradlew -b ./workspace/build.gradle clean :stage-060-aat:test --info"
}
return this
Jenkinsfile
...
  stage ("AAT")
  node {
    def stage060aat = load("workspace/stage-060-aat.groovy")
    stage060aat.execute()
  }
...

Multibranch Build

  • automatisches Erzeugen von neuen Workflows per Branch .

  • History per Branch

  • automatisches Löschen von Jobs wenn Branch gelöscht

  • Branch spezifische Properties

Einschränkung:

  • Jenkinsfile muss im root-Verzeichnis liegen

HandsOn 9

  • Kopiere workspace Verzeichnis ins home Verzeichnis

  • Erzeuge neues lokales Repository

  • Erzeuge git remote Repository mit dem Namen address-mb

  • Verbinde lokales Repository mit Remote und push von master

  • Erzeuge in Jenkins einen neuen Job address-mb als Multibranch Pipeline

  • Erzeuge lokal neuen Branch

  • Push von Branch

  • Manuelles ausführen von Branch Indexing in Jenkins

Optional:

  • Richte einen hook in gogs ein und

  • teste das au

Erläuterung zu HandsOn 9

$ git branch featureX                       # (create featureX branch)
$ git checkout featureX                     # (switches to featureX branch)
$ git push --set-upstream upstream featureX # (pushes featureX branch)

???

Red or Blue

mehr Tools


  • pact - consumer driven contract testing z.B für Microservices

  • Terraform - Infrastructure as Code

  • Consul - Servicediscovery (and K-V-Store, and DNS)

  • fabric8 - opinionated open source microservices platform

Vielen Dank!

email: [email protected]
twitter: @ollispieps
github: @ollin
google+: OliverNautsch

Nexus

Nexus

Nexus ist ein Software Repository Manager. Ein Softwarerepository ist ein Speicherort von welchen man Softwarepakete beziehen kann. Es enthält neben den Programmpaketen auch Metadaten über diese.

Begriffe
  • Repository

    • Hosted

    • Proxy

    • Group

  • User

  • Rollen