README.md 6.62 KB
Newer Older
Nane Kratzke's avatar
Nane Kratzke committed
1
2
# Lab: Deployment Pipelines as Code

Nane Kratzke's avatar
Nane Kratzke committed
3
Deployment Pipelines sind ein wesentlicher Baustein im DevOps Ansatz, um Entwicklungszyklen schnell und agil zu halten.
Nane Kratzke's avatar
Nane Kratzke committed
4
5
6
Ziel ist es, Code der in ein Code Repository eingebracht wird, möglichst automatisiert zu integrieren, bauen, testen
sowie ggf. in eine Umgebung (häufig Test, Staging, Production) auszubringen.

Nane Kratzke's avatar
Nane Kratzke committed
7
Mit jedem Code Push wird also automatisiert geprüft, ob der Code in die bestehende Codebasis integriert werden kann, compilierbar ist, alle Tests passiert und deploybar ist. Auf diese Weise können nur funktionierende Softwarezustände in funktionierende Softwarezustände überführt werden. Entwickler sind so nicht einmal in der Lage Code zu erzeugen, der nicht automatisiert durch die Deployment Pipeline verarbeitbar ist.
Nane Kratzke's avatar
Nane Kratzke committed
8

Nane Kratzke's avatar
Nane Kratzke committed
9
Gemäß dem Everything as Code Ansatz versucht man auch Deployment Pipelines als versionierbaren Code ausdrücken zu können.
Nane Kratzke's avatar
Nane Kratzke committed
10
Es gibt diverse solcher Managed oder Self-hosted Services, die als kommerzielle oder auch als Open Source Software genutzt werden können. Z.B.:
Nane Kratzke's avatar
Nane Kratzke committed
11
12
13
14
15
16

- GitLab CI
- Circle CI
- Travis CI
- Jenkins
- Bitbucket Pipelines
Nane Kratzke's avatar
Nane Kratzke committed
17
- und viele mehr
Nane Kratzke's avatar
Nane Kratzke committed
18
19

Da Gitlab als Open Source Lösung einfach installiert werden kann, werden wir das Prinzip einer Deployment Pipeline
Nane Kratzke's avatar
Nane Kratzke committed
20
as Code am Typvertreter Gitlab CI demonstrieren. Die Ansätze anderer CI/CD Dienste funktionieren aber nach sehr
Nane Kratzke's avatar
Nane Kratzke committed
21
22
23
vergleichbaren Konzepten. Die Wahl auf Gitlab CI als Typvertreter erfolgt schlicht und ergreifend auf Basis der
guten Verfügbarkeit von Gitlab als Open Source Software und dessen häufigen Einsatz in Cloud-native Kontexten.

Nane Kratzke's avatar
Nane Kratzke committed
24
25
26
27
28
29
30
31
Wer mag, kann dieses Lab auch mittels des Managed Service Gitlab.com nachvollziehen. Hierzu müssen Sie sich allerdings
registrieren.

## Inhalt

- Erzeugung einer Build-Pipeline mittels einer Sequenz von Stages
- Parallele Ausführung von Jobs innerhalb einer Stage, sequentielle Ausführung der einzelnen Stages
- Weiterreichen von Artifacts zwischen Stages
Nane Kratzke's avatar
Nane Kratzke committed
32
33
34
- Informationen in die Build-Pipeline mittels [Environment Variables](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html) geben.
- Nutzung von Images
- Bereitstellung von Images
Nane Kratzke's avatar
Nane Kratzke committed
35
- Deployments to Kubernetes
Nane Kratzke's avatar
Nane Kratzke committed
36
- Deployments to Serverless Environments
Nane Kratzke's avatar
Nane Kratzke committed
37

38
### Übung 1: Erzeugung von Deployment Pipelines
Nane Kratzke's avatar
Nane Kratzke committed
39

Nane Kratzke's avatar
Nane Kratzke committed
40
41
42
43
Eine Deployment Pipeline besteht aus einer Sequenz von Stages. Jede Stage kann ein oder mehrere Jobs haben. Alle Jobs innerhalb einer
Stage werden parallel und isoliert voneinander ausgeführt. Eine Stage wird nur dann ausgeführt, wenn alle Jobs der vorherigen Stage
erfolgreich ausgeführt werden konnten.

Nane Kratzke's avatar
Nane Kratzke committed
44
Eine typische Pipeline umfasst häufig die folgenden Stages (grundsätzlich können Pipelines beliebig aussehen, es bietet sich jedoch an bewährten Pipeline Blueprints zu folgen):
Nane Kratzke's avatar
Nane Kratzke committed
45
46
47
48
49

- build (zum Erzeugen von Executables)
- test (zum Testen von Executables)
- deploy (zum Ausbringen von Executables)

Nane Kratzke's avatar
Nane Kratzke committed
50
Solch eine einfache Deployment Pipeline wollen wir nun bauen. Führen Sie hierzu bitte die folgenden Schritte aus:
Nane Kratzke's avatar
Nane Kratzke committed
51
52
53
54

__Aufgaben:__

1. Forken Sie hierzu bitte dieses Repository in Gitlab.
55
2. Sie finden in diesem geforkten Repository eine leere `.gitlab-ci.yml` Datei an. Diese Datei definiert Ihre Pipeline, die Gitlab mit jedem Push in das Repository automatisch anstößt.
Nane Kratzke's avatar
Nane Kratzke committed
56
3. Fügen Sie in diese Datei nun bitte folgende Inhalte ein und committen+pushen Sie `.gitlab-ci.yml` in das Repository:
Nane Kratzke's avatar
Nane Kratzke committed
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

    ```yaml
    stages:
        - build
        - test
        - deploy

    job1:
        stage: build
        script:
            - echo "Hello I am job 1"

    job2:
        stage: build
        script:
72
            - echo "Hello I am job 2"
Nane Kratzke's avatar
Nane Kratzke committed
73
74
75
76

    job3:
        stage: test
        script:
77
            - echo "Hello I am job 3"
Nane Kratzke's avatar
Nane Kratzke committed
78
79

    job4:
80
        stage: deploy
Nane Kratzke's avatar
Nane Kratzke committed
81
        script:
82
            - echo "Hello I am job 4"
Nane Kratzke's avatar
Nane Kratzke committed
83
    ```
Nane Kratzke's avatar
Nane Kratzke committed
84
4. Gitlab führt dann automatisch, die so definierte [Pipeline](../../../pipelines) aus.
Nane Kratzke's avatar
Nane Kratzke committed
85
   
Nane Kratzke's avatar
Nane Kratzke committed
86
   ![Pipeline](pipeline.png)
Nane Kratzke's avatar
Nane Kratzke committed
87
88
5. Klicken Sie auf einen dieser Jobs, dann erhalten Sie den Konsolenoutput des Jobs.
   
89
   ![Job console output](job-console.png)
Nane Kratzke's avatar
Nane Kratzke committed
90
91

Eine Pipeline ist also sehr einfach mit einer YAML Datei definierbar. YAML Dateien wiederum sind gut durch Code Versionssysteme versionierbar.
Nane Kratzke's avatar
Nane Kratzke committed
92
Das ist eigentlich auch schon das wesentliche Prinzip von einer Deployment Pipeline as Code. Sie sehen an diesem Beispiel allerdings auch bereits weitere Aspekte die typisch für Cloud-native Deployment Ansätze sind.
Nane Kratzke's avatar
Nane Kratzke committed
93
94
95

- Jobs sind eigentlich nichts weiter als Shellskripte, die in einem isolierten Container ausgeführt werden.
- Können alle Jobs einer Stage erfolgreich ausgeführt werden, (exit code == 0) werden die Jobs der nächsten Stage gestartet.
Nane Kratzke's avatar
Nane Kratzke committed
96
- Schlägt ein Job fehl (exit code != 0), wird die nächste Stage nicht gestartet. Sie können das ganz einfach ausprobieren, indem Sie bspw. den Befehl `exit 1` in *job3* ergänzen.
Nane Kratzke's avatar
Nane Kratzke committed
97
98
99
100
101
102
103
    ```yaml
    job3:
        stage: test
        script:
            - echo "Hello I am job 3"
            - exit 1
    ```
104
105
106
    Die Pipeline schlägt dann in job3 in Stage `test` fehl.

    ![Pipeline job failed](pipeline-job-failed.png)
Nane Kratzke's avatar
Nane Kratzke committed
107

108
### Übung 2: Weiterreichen von Job Erzeugnissen
Nane Kratzke's avatar
Nane Kratzke committed
109

110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
Jobs laufen isoliert in einem Container ab, sind also zustandslos oder anders ausgedrückt: Jobs "vergessen" erzeugte Artifakte. Dies ist sicherlich in vielen Fällen nicht sinnvoll.
Z.B. sollten durch den Compiler erzeugte `.class` Dateien in einem Java Build Schritt an einen Test Job weitergereicht werden können (ansonsten müsste der Test Job erneut kompilieren).
Zum Ende der Pipeline soll vielleicht auch eine `jar`-Datei als Endergebnis der Pipeline bereitgestellt werden können.

Hierfür dienen in Pipelines sogenannte Artefakte. Artefakte sind Job Erzeugnisse, die zwischen Jobs entlang einer Stage Sequenz fließen.

__Aufgabe 2.1:__

Ändern Sie bitte Ihre Pipeline wie folgt ab:

```yaml
stages:
    - generate
    - consume

job1:
    stage: generate
    script:
        - mkdir build
        - echo "Hello I am job 1" > build/job1-result.txt

job2:
    stage: generate
    script:
        - mkdir build
        - echo "Hello I am job 2" > build/job2-result.txt

job3:
    stage: consume
    script:
        - cat build/*-result.txt
```

Die Jobs job1 und job2 lenken ihre Resultate also in zwei Dateien um, die im `build` Verzeichnis gespeichert werden.
Wir würden an dieser Stelle erwarten, dass der job3 daher folgende Konsolenausgabe erzeugen sollte:

```sh
Hello I am job1
Hello I am job2
```

Tatsächlich passiert dies aber nicht. Warum?
Nane Kratzke's avatar
Nane Kratzke committed
152
153

## Quellen für weitergehende Informationen:
Nane Kratzke's avatar
Nane Kratzke committed
154
155

- Youtube: [Gitlab CI pipeline tutorial for beginners](https://youtu.be/Jav4vbUrqII)
Nane Kratzke's avatar
Nane Kratzke committed
156
157
- Youtube: [Automating Kubernetes Deployments](https://youtu.be/wEDRfAz6_Uw)
- Youtube: [Continuous Integration with GitLab CI](https://youtu.be/EuwLdbCu3DE)
Nane Kratzke's avatar
Nane Kratzke committed
158

Nane Kratzke's avatar
Nane Kratzke committed
159