├── .gitignore
├── LICENSE
├── README.md
├── additional-labs
├── configmaps.md
├── cronjobs_and_jobs.md
├── development_environment.md
├── jenkins.md
└── resources
│ ├── cronjob_mariadb-dump.yaml
│ ├── job_mariadb-dump.yaml
│ ├── properties.properties
│ └── simple-jenkins-pipeline.yaml
├── dev-labs
├── 01_using_oc_cli.md
├── 02_builds.md
├── 03_develop.md
├── 04_troubleshooting_autoscale.md
├── README.md
└── data
│ └── 02_httpd
│ ├── Dockerfile
│ ├── easter-egg.txt
│ └── public-html
│ └── index.html
├── images
├── jenkins_oauth2_login.png
├── jenkins_oauth2_permissions.png
├── kibana1.png
├── kibana2.png
├── lab_02_cli.png
├── lab_03_login.png
├── lab_08_mariadb.png
├── lab_09_codechange1.png
├── lab_09_edit_on_github.png
├── lab_09_fork_example.png
├── lab_09_webhook_github1.png
├── lab_09_webhook_github2.png
├── lab_09_webhook_github3.png
├── lab_09_webhook_github4.png
├── lab_09_webhook_ocp4.png
├── openshift-pipeline-jenkins-view-run.png
├── openshift-pipeline-rollout.png
├── openshift-pipeline-run.png
├── openshift-pipeline-start.png
├── pipeline-jenkins-custom-podtemplate.png
└── pipeline-jenkins-overview.png
└── labs
├── 01_quicktour.md
├── 02_cli.md
├── 03_first_steps.md
├── 04_deploy_dockerimage.md
├── 05_create_route.md
├── 06_scale.md
├── 07_operators.md
├── 08_troubleshooting_ops.md
├── 09_database.md
├── 10_persistent_storage.md
├── 11_dockerbuild_webhook.md
├── 12_template.md
├── 13_template_creation.md
└── data
└── 08_dump
└── dump.sql
/.gitignore:
--------------------------------------------------------------------------------
1 | .settings/
2 | .project
3 |
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # APPUiO - OpenShift 4 Techlab
2 |
3 | Dieses Techlab basiert auf OpenShift 4.
4 |
5 | ## Einführung
6 |
7 | Mit Platform-as-a-Service (PaaS) ändert sich die Art, wie wir Software entwickeln. Puzzle stellt OpenShift – die _Container Platform_ von Red Hat – in einem Techlab vor. Entwickler lernen dabei hands-on die wichtigsten Schritte, wie eine Applikation auf OpenShift gebracht wird.
8 |
9 | __Ziele dieses Techlabs__:
10 |
11 | - Gemeinsam den Einstieg in eine neue moderne Technologie erreichen
12 | - Grundkonzepte verstehen
13 | - Erste Applikation auf OpenShift deployed
14 |
15 | ## Labs
16 |
17 | 1. [Quicktour durch OpenShift 4](labs/01_quicktour.md)
18 | 2. [OpenShift CLI installieren](labs/02_cli.md)
19 | 3. [Erste Schritte auf der Lab Plattform](labs/03_first_steps.md)
20 | 4. [Ein Container Image deployen](labs/04_deploy_dockerimage.md)
21 | 5. [Routen erstellen](labs/05_create_route.md)
22 | 6. [Skalieren](labs/06_scale.md)
23 | 7. [Operators](labs/07_operators.md)
24 | 8. [Troubleshooting](labs/08_troubleshooting_ops.md)
25 | 9. [Datenbank deployen und anbinden](labs/09_database.md)
26 | 10. [Persistent Storage anbinden und verwenden für Datenbank](labs/10_persistent_storage.md)
27 | 11. [Code Änderungen via Webhook direkt integrieren](labs/11_dockerbuild_webhook.md)
28 | 12. [Applikationstemplates](labs/12_template.md)
29 | 13. [Eigene Templates erstellen](labs/13_template_creation.md)
30 |
31 | ### Zusätzliche Labs
32 |
33 | - [Cron Jobs in OpenShift](additional-labs/cronjobs_and_jobs.md)
34 | - [ConfigMaps](additional-labs/configmaps.md)
35 | - [Jenkins](additional-labs/jenkins.md)
36 | - [Eigene OpenShift Entwicklungsumgebung](additional-labs/development_environment.md)
37 |
38 | ### OpenShift Developer Techlab
39 |
40 | Unterlagen für ein zweitägiges Developer Techlab sind im Verzeichnis [dev-labs](dev-labs/) abgelegt.
41 |
42 | ## Weiterführende Dokumentation
43 |
44 | - [OpenShift Container Platform 4 Dokumentation](https://docs.openshift.com/container-platform/latest/welcome/index.html)
45 | - [APPUiO Dokumentation](http://docs.appuio.ch)
46 |
47 | ### APPUiO Examples
48 |
49 | - [APPUiO PHP Source to image hello World Example](https://github.com/appuio/example-php-sti-helloworld)
50 | - [APPUiO PHP Dockerbuild hello World Example](https://github.com/appuio/example-php-docker-helloworld)
51 | - [APPUiO Cron Job Example](https://github.com/appuio/example-cron-traditional)
52 |
53 | ## Ältere Inhalte
54 |
55 | Die Techlabs zu früheren Versionen sind in deren eigenen Branches zu finden:
56 |
57 | - [Branch lab-3.11](https://github.com/appuio/techlab/tree/lab-3.11)
58 | - [Branch lab-3.9](https://github.com/appuio/techlab/tree/lab-3.9)
59 | - [Branch lab-3.5](https://github.com/appuio/techlab/tree/lab-3.5)
60 | - [Branch lab-3.4](https://github.com/appuio/techlab/tree/lab-3.4)
61 | - [Branch lab-3.3](https://github.com/appuio/techlab/tree/lab-3.3)
62 | - [Branch lab-3.2](https://github.com/appuio/techlab/tree/lab-3.2)
63 | - [Branch lab-3.1](https://github.com/appuio/techlab/tree/lab-3.1)
64 |
--------------------------------------------------------------------------------
/additional-labs/configmaps.md:
--------------------------------------------------------------------------------
1 | # ConfigMaps
2 |
3 | ConfigMaps werden dazu verwendet, die Konfiguration für eine Applikation vom Image zu trennen und bei Laufzeit dem Pod zur Verfügung zu stellen, ähnlich dem Setzen von Umgebungsvariablen.
4 | Dies erlaubt es, Applikationen innerhalb von Containern möglichst portabel zu halten.
5 |
6 | In diesem Lab lernen Sie, wie man ConfigMaps erstellt und entsprechend verwendet.
7 |
8 | ## ConfigMap in OpenShift Projekt anlegen
9 |
10 | Um eine ConfigMap in einem Projekt anzulegen kann folgender Befehl verwendet werden:
11 |
12 | ```bash
13 | oc create configmap [Name der ConfigMap] [Options]
14 | ```
15 |
16 | ## Java Properties Files als ConfigMap
17 |
18 | Ein klassisches Beispiel für ConfigMaps sind Property Files bei Java Applikationen, welche in erster Linie nicht via Umgebungsvariablen konfiguriert werden können.
19 |
20 | Für dieses Beispiel verwenden wir das Spring Boot Beispiel aus [Lab 4](../labs/04_deploy_dockerimage.md), `[USERNAME]-dockerimage`.
21 |
22 | Tipp
oc project [USERNAME]-dockerimage
23 |
24 | Mit dem folgenden Befehl legen wir nun die erste ConfigMap auf Basis eines lokalen Files an:
25 |
26 | ```bash
27 | oc create configmap javaconfiguration --from-file=additional-labs/resources/properties.properties
28 | ```
29 |
30 | Mit folgendem Befehl kann nun verifiziert werden, ob die ConfigMap erfolgreich angelegt wurde:
31 |
32 | ```bash
33 | oc get configmaps
34 | NAME DATA AGE
35 | javaconfiguration 1 7s
36 | ```
37 |
38 | Wir können uns auch den Inhalt der ConfigMap ansehen:
39 |
40 | ```bash
41 | oc get configmaps javaconfiguration -o json
42 | ```
43 |
44 | ## ConfigMap in Pod zur Verfügung stellen
45 |
46 | Als nächstes wollen wir die ConfigMap im Pod verfügbar machen.
47 |
48 | Grundsätzlich gibt es dafür die folgenden Möglichkeiten:
49 |
50 | - ConfigMap Properties als Umgebungsvariablen im Deployment
51 | - Commandline Arguments via Umgebungsvariablen
52 | - als Volumes in den Container gemountet
53 |
54 | Im Beispiel hier wollen wir, dass die ConfigMap als File auf einem Volume liegt.
55 |
56 | Hierfür müssen wir entweder den Pod oder in unserem Fall die DeploymentConfig mit `oc edit dc example-spring-boot` bearbeiten.
57 |
58 | Zu beachten gilt es dabei den volumeMounts- (`spec.template.spec.containers.volumeMounts`: wie wird das Volume in den Container gemountet) sowie den volumes-Teil (`spec.template.spec.volumes`: welches Volume in unserem Fall die ConfigMap wird in den Container gemountet).
59 |
60 | ```
61 | apiVersion: v1
62 | kind: DeploymentConfig
63 | metadata:
64 | annotations:
65 | openshift.io/generated-by: OpenShiftNewApp
66 | creationTimestamp: 2018-12-05T08:24:06Z
67 | generation: 2
68 | labels:
69 | app: example-spring-boot
70 | name: example-spring-boot
71 | namespace: [namespace]
72 | resourceVersion: "149323448"
73 | selfLink: /oapi/v1/namespaces/[namespace]/deploymentconfigs/example-spring-boot
74 | uid: 21f6578b-f867-11e8-b72f-001a4a026f33
75 | spec:
76 | replicas: 1
77 | revisionHistoryLimit: 10
78 | selector:
79 | app: example-spring-boot
80 | deploymentconfig: example-spring-boot
81 | strategy:
82 | activeDeadlineSeconds: 21600
83 | resources: {}
84 | rollingParams:
85 | intervalSeconds: 1
86 | maxSurge: 25%
87 | maxUnavailable: 25%
88 | timeoutSeconds: 600
89 | updatePeriodSeconds: 1
90 | type: Rolling
91 | template:
92 | metadata:
93 | annotations:
94 | openshift.io/generated-by: OpenShiftNewApp
95 | creationTimestamp: null
96 | labels:
97 | app: example-spring-boot
98 | deploymentconfig: example-spring-boot
99 | spec:
100 | containers:
101 | - env:
102 | - name: SPRING_DATASOURCE_USERNAME
103 | value: appuio
104 | - name: SPRING_DATASOURCE_PASSWORD
105 | value: appuio
106 | - name: SPRING_DATASOURCE_DRIVER_CLASS_NAME
107 | value: com.mysql.cj.jdbc.Driver
108 | - name: SPRING_DATASOURCE_URL
109 | value: jdbc:mysql://mysql/appuio?autoReconnect=true
110 | image: appuio/example-spring-boot
111 | imagePullPolicy: Always
112 | name: example-spring-boot
113 | resources: {}
114 | terminationMessagePath: /dev/termination-log
115 | terminationMessagePolicy: File
116 | volumeMounts:
117 | - mountPath: /etc/config
118 | name: config-volume
119 | dnsPolicy: ClusterFirst
120 | restartPolicy: Always
121 | schedulerName: default-scheduler
122 | securityContext: {}
123 | terminationGracePeriodSeconds: 30
124 | volumes:
125 | - configMap:
126 | defaultMode: 420
127 | name: javaconfiguration
128 | name: config-volume
129 | ```
130 |
131 | Anschliessend kann im Container im File `/etc/config/properties.properties` auf die Werte zugegriffen werden.
132 |
133 | ```bash
134 | oc exec [POD] -- cat /etc/config/properties.properties
135 | key=appuio
136 | key2=openshift
137 | ```
138 |
139 | Diese Properties Files können nun so von der Java Applikation im Container gelesen und verwendet werden.
140 | Das Image bleibt dabei umgebungsneutral.
141 |
142 | ## Aufgabe: LAB10.4.1 ConfigMap Data Sources
143 |
144 | Erstellen Sie jeweils eine ConfigMap und verwenden Sie dafür die verschiedenen Arten von [Data Sources](https://docs.openshift.com/container-platform/3.11/dev_guide/configmaps.html#consuming-configmap-in-pods).
145 |
146 | Machen Sie die Werte innerhalb von Pods auf die unterschiedlichen Arten verfügbar.
147 |
148 | ---
149 |
150 | __Ende Lab ConfigMaps__
151 |
152 | [← zurück zur Übersicht](../README.md)
153 |
--------------------------------------------------------------------------------
/additional-labs/cronjobs_and_jobs.md:
--------------------------------------------------------------------------------
1 | # Cron Jobs in OpenShift
2 |
3 | Kubernetes bringt das Konzept von Jobs und Cron Jobs mit.
4 | Dies ermöglicht es, gewisse Tasks einmalig (Job) oder eben jeweils zu einer bestimmten Zeit (Cron Job) auszuführen.
5 |
6 | Eine mögliche Auswahl von Anwendungsfällen:
7 |
8 | - Jeweils um 23:12 ein Datenbank Backup erstellen und auf ein gemountetes PVC speichern
9 | - Einmaliges generieren von Reports
10 | - Cleanup-Job welcher alte Daten aufräumt
11 | - Asynchrones Senden von Emails
12 |
13 | ## Job
14 |
15 | Jobs im Unterschied zu einem Deployment, welches mittels Replication Controller getrackt wird, führt einen Pod einmalig aus bis der Befehl abgeschlossen ist.
16 | Ein Job erstellt dafür einen Pod und führt die definierte Operation bzw. Befehl aus.
17 | Es muss sich dabei nicht zwingend um nur einen Pod handeln, sondern kann auch mehrere beinhalten.
18 | Wird ein Job gelöscht, werden auch die vom Job gestarteten (und wieder beendeten) Pods gelöscht.
19 |
20 | Ein Job eignet sich also bspw. dafür, sicherzustellen, dass ein Pod verlässlich bis zu dessen Vervollständigung ausgeführt wird.
21 | Schlägt ein Pod fehl, zum Beispiel wegen eines Node-Fehlers, startet der Job einen neuen Pod.
22 |
23 | Weitere Informationen zu Jobs sind in der [OpenShift Dokumentation](https://docs.openshift.com/container-platform/latest/nodes/jobs/nodes-nodes-jobs.html) zu finden.
24 |
25 | ## Cron Jobs
26 |
27 | Ein OpenShift Cron Job ist nichts anderes als eine Ressource, welche zu definierten Zeitpunkten einen Job erstellt, welcher wiederum wie gewohnt einen Pod startet um einen Befehl auszuführen.
28 |
29 | Weitere Informationen zu Cron Jobs sind auf derselben [OpenShift Dokumentationsseite](https://docs.openshift.com/container-platform/latest/nodes/jobs/nodes-nodes-jobs.html) zu finden wie die Jobs.
30 |
31 | ## Aufgabe: Job für MariaDB-Dump erstellen
32 |
33 | Ähnlich wie in [Lab-Aufgabe 9.4](../labs/09_database.md) wollen wir nun einen Dump der laufenden MariaDB-Datenbank erstellen, aber ohne uns in den Pod einloggen zu müssen.
34 |
35 | Für dieses Beispiel verwenden wir das Spring Boot Beispiel aus [Lab 4](../labs/04_deploy_dockerimage.md), `[USERNAME]-dockerimage`.
36 |
37 | Tipp
oc project [USERNAME]-dockerimage
38 |
39 | Schauen wir uns zuerst die Job-Ressource an, die wir erstellen wollen.
40 | Sie ist unter [resources/job_mariadb-dump.yaml](resources/job_mariadb-dump.yaml) zu finden.
41 | Unter `.spec.template.spec.containers[0].image` sehen wir, dass wir dasselbe Image verwenden wie für die laufende Datenbank selbst.
42 | Wir starten anschliessend aber keine Datenbank, sondern wollen einen `mysqldump`-Befehl ausführen, wie unter `.spec.template.spec.containers[0].command` aufgeführt.
43 | Dazu verwenden wir, wie schon im Datenbank-Deployment, dieselben Umgebungsvariablen, um Hostname, User oder Passwort innerhalb des Pods definieren zu können.
44 |
45 | Schlägt der Job fehl, soll er neugestartet werden, dies wird über die `restartPolicy` definiert.
46 | Insgesamt soll 3 mal probiert werden den Job auszuführen (`backoffLimit`).
47 |
48 | Erstellen wir nun also unseren Job:
49 |
50 | ```bash
51 | oc create -f ./additional-labs/resources/job_mariadb-dump.yaml
52 | ```
53 |
54 | Überprüfen wir, ob der Job erfolgreich war:
55 |
56 | ```bash
57 | oc describe jobs/mariadb-dump
58 | ```
59 |
60 | Den ausgeführten Pod können wir wie folgt anschauen:
61 |
62 | ```bash
63 | oc get pods
64 | ```
65 |
66 | Um alle Pods, welche zu einem Job gehören, in maschinenlesbarer Form auszugeben, kann bspw. folgender Befehl verwendet werden:
67 |
68 | ```bash
69 | oc get pods --selector=job-name=mariadb-dump --output=jsonpath={.items..metadata.name}
70 | ```
71 |
72 | Um zu überprüfen ob der Job erfolgreich war, können die Logs des Pod ausgelesen werden.
73 |
74 | ```bash
75 | oc logs $(oc get pods --selector=job-name=mariadb-dump --output=jsonpath={.items..metadata.name})
76 | ```
77 |
78 |
79 | ## Aufgabe: Cron Job einrichten
80 |
81 | In der vorherigen Aufgabe haben wir lediglich einen Job instanziert, welcher einmalig einen Datenbank Dump erstellt.
82 | Nun wollen wir sicherstellen, dass dieser Datebank Dump nächtlich einmal ausgeführt wird.
83 |
84 | Dafür erstellen wir nun eine Resource vom Typ Cron Job. Der Cron Job soll jeweils um 23:12 jeden Tag einen Job ausführen, welcher einen Dump der Datenbank erstellt und sichert.
85 |
86 | ```bash
87 | oc create -f ./additional-labs/resources/cronjob_mariadb-dump.yaml
88 | ```
89 |
90 | Schauen wir uns nun diesen Cron Job an:
91 |
92 | ```bash
93 | oc get cronjob mariadb-backup -o yaml
94 | ```
95 |
96 | __Wichtig__:
97 | Beachten Sie, dass insbesondere Backups überwacht und durch Restore Tests überprüft werden müssen.
98 | Diese Logik kann bspw. in den auszuführenden Befehl integriert oder aber durch ein Monitoring Tool übernommen werden.
99 | Im Test-Cron Job wird der Dump in das `/tmp`-Verzeichnis geschrieben.
100 | Für den produktiven Einsatz sollte dies ein gemountetes Persistent Volume sein.
101 |
102 | Versuchen Sie, folgende Fragen zu beantworten:
103 |
104 | - Wann wurde der Cron Job das letzte mal ausgeführt?
105 | - War das Backup erfolgreich?
106 | - Konnten die Daten erfolgreich restored werden?
107 |
108 | __Ende Lab Cron Jobs__
109 |
110 | [← zurück zur Übersicht](../README.md)
111 |
--------------------------------------------------------------------------------
/additional-labs/development_environment.md:
--------------------------------------------------------------------------------
1 | # OpenShift Entwicklungsumgebung
2 |
3 | Diese Seite zeigt verschiedene Möglichkeiten, wie selbst entwickelte Container oder OpenShift Templates etc. getestet werden können, ohne auf eine vollständige, produktive OpenShift-Plattform wie bspw. APPUiO Zugriff zu haben.
4 |
5 | ## CodeReady Containers
6 |
7 | [CodeReady Containers](https://crc.dev/crc/) ermöglicht es, einen minimalen OpenShift 4 Cluster auf dem lokalen Computer laufen zu lassen.
8 |
9 | ## Minishift
10 |
11 | [Minishift](https://docs.okd.io/3.11/minishift/index.html) erlaubt den Betrieb einer lokalen OpenShift-Installation auf dem eigenen Notebook in einer VM mit KVM, Hyper-V oder VirtualBox, __ermöglicht aber nur den Einsatz von OpenShift 3, nicht OpenShift 4__.
12 | Minishift ist ursprünglich ein Fork von Minikube und verwendet [OKD](https://www.okd.io/), das Upstream-Projekt von OpenShift Container Platform.
13 | Für den Einsatz von OCP 3 muss auf das Red Hat CDK ausgewichen werden.
14 |
15 | ## CDK
16 |
17 | Das [Red Hat Container Development Kit](https://developers.redhat.com/products/cdk/overview) bietet sozusagen die "Enterprise"-Variante von Minishift an.
18 | Anstelle von OKD kommt OCP zum Einsatz, weshalb eine Subscription benötigt wird, bspw. über das kostenlose [Red Hat Developer Program](https://developers.redhat.com/).
19 |
20 | ---
21 |
22 | __Ende__
23 |
24 | [← zurück zur Übersicht](../README.md)
25 |
--------------------------------------------------------------------------------
/additional-labs/jenkins.md:
--------------------------------------------------------------------------------
1 | # Jenkins Pipelines auf OpenShift
2 |
3 | Mit Jenkins Pipelines auf OpenShift hat man die Möglichkeit, komplexe CI/CD Prozesse voll integriert abzubilden. In diesem Lab zeigen wir, wie man mit Jenkins Pipelines arbeitet und so Applikationen baut, testet und entsprechend kontrolliert in die verschiedenen Stages deployt.
4 |
5 | Die offizielle Dokumentation ist unter [Pipeline build](https://docs.openshift.com/container-platform/latest/builds/build-strategies.html#builds-strategy-pipeline-build_build-strategies) oder [OpenShift 3 Pipeline Builds](https://docs.openshift.com/container-platform/3.11/dev_guide/dev_tutorials/openshift_pipeline.html) zu finden.
6 |
7 | Die OpenShift Plattform setzt, seit Version 4, für die integrierten Pipeline Builds auf Tekton.
8 | Diese Tekton-basierten Pipelines sind jedoch erst als Technology Preview Feature verfügbar [OpenShift 4 Pipeline Builds](https://docs.openshift.com/container-platform/latest/pipelines/understanding-openshift-pipelines.html).
9 |
10 | ## Grundprinzip
11 |
12 | OpenShift Jenkins Pipelines basieren auf Jenkins Pipelines, welche voll integriert mit OpenShift fungieren. So hat man BuildConfigs vom Typ `jenkinsPipelineStrategy` anzulegen, welche wieder eine Jenkins Pipeline referenzieren.
13 |
14 | ## LAB: Eine einfache OpenShift Pipeline anlegen und ausführen
15 |
16 | Um zu verstehen, wie OpenShift Pipelines funktionieren, wollen wir als ersten Schritt direkt eine Pipeline anlegen.
17 |
18 | Erstellen wir dafür ein neues Projekt mit dem Namen `[USER]-buildpipeline`.
19 |
20 | Tipp
oc new-project [USER]-buildpipeline
21 |
22 | Jetzt deployen wir Jenkins in unser Projekt:
23 |
24 | ```bash
25 | oc get template/jenkins-ephemeral -n openshift -o yaml | oc process --param MEMORY_LIMIT=2Gi --param DISABLE_ADMINISTRATIVE_MONITORS=true -f - | oc apply -f -
26 | ```
27 |
28 | Wir legen mit folgendem Befehl die entsprechende BuildConfig an, welche das JenkinsFile, also die Pipeline, direkt beinhaltet. Ebenso wird eine zweite BuildConfig erstellt. Diese enthält die BuildConfig für die eigentliche Applikation, die wir im Rahmen dieser Pipeline deployen wollen. Im vorliegenden Beispiel eine simple PHP Applikation:
29 |
30 | ```bash
31 | oc apply -f ./additional-labs/resources/simple-jenkins-pipeline.yaml
32 | ```
33 |
34 | Während OpenShift arbeitet, schauen wir uns noch die verwendete Konfigurationsdatei an: [additional-labs/resources/simple-jenkins-pipeline.yaml](resources/simple-jenkins-pipeline.yaml)
35 |
36 | Aufgrund der BuildConfig deployt OpenShift automatisch eine integrierte Jenkins Instanz. Schauen wir uns dies in der Web Console an. Im Projekt befindet sich nach erfolgreichem Deployment eine laufende Jenkins Instanz, welche über eine Route exposed ist. Der Zugriff auf Jenkins über die Route ist mittels OpenShift OAuth gesichert. Rufen Sie die URL der Route auf.
37 |
38 | Wenn Sie zum ersten Mal einen OpenShift Jenkins aufrufen, erhalten Sie eine OpenShift-Authentifizierungsmaske.
39 |
40 | 
41 |
42 | Danach wird ein Berechtigungs-Bildschirm angezeigt, in dem Sie nach Autorisierungs-Berechtigungen gefragt werden.
43 | Siehe das Bild unten.
44 |
45 | 
46 |
47 | Akzeptieren Sie diese und wechseln Sie zum nächsten Bildschirm, indem Sie auf 'Allow selected permissions' klicken.
48 |
49 | Der nächste Bildschirm sollte der berühmte/klassische (oder berüchtigte) Jenkins-Begrüssungsbildschirm sein.
50 |
51 | 
52 |
53 | Die Pipeline aus der BuildConfig ist im Ordner unseres OpenShift Projekts sichtbar.
54 | Sie wurde automatisch synchronisiert und angelegt.
55 |
56 | Zurück in der OpenShift Web Console können wir nun über Builds --> *appuio-sample-pipeline* die Pipeline anschauen.
57 |
58 | __Note__: Hier wird die 'Pipeline build strategy deprecation' angezeigt. Wie einleitend erklärt, setzt OpenShift neu auf Tekton.
59 |
60 | Zum Starten der Pipeline klicken wir auf Actions --> Start Build
61 |
62 | 
63 |
64 | Dabei wird von OpenShift der Jenkins Job gestartet und entsprechend in die Pipeline Ansicht synchronisiert.
65 |
66 | Builds --> *appuio-sample-pipeline* --> Builds Tab --> *appuio-sample-pipeline-1*
67 |
68 | 
69 |
70 | Die gleichen Informationen sind auch im Jenkins GUI zu sehen.
71 |
72 | 
73 |
74 | Unser Beispiel hier enthält eine Test-Pipeline, die das generelle Prinzip veranschaulicht. Jedoch bieten Jenkins Pipelines volle Flexibilität um komplexe CI/CD Pipelines abzubilden.
75 |
76 | ```groovy
77 | def project=""
78 | node {
79 | stage('Init') {
80 | project = env.PROJECT_NAME
81 | }
82 | stage('Build') {
83 | echo "Build"
84 | openshift.withCluster() {
85 | openshift.withProject() {
86 | def builds = openshift.startBuild("application");
87 | builds.logs('-f')
88 | timeout(5) {
89 | builds.untilEach(1) {
90 | return (it.object().status.phase == "Complete")
91 | }
92 | }
93 | }
94 | }
95 | }
96 | stage('Test') {
97 | echo "Test"
98 | sleep 2
99 | }
100 | }
101 | node ('maven') {
102 | stage('DeployDev') {
103 | echo "Deploy to Dev"
104 | sleep 5
105 | }
106 | stage('PromoteTest') {
107 | echo "Deploy to Test"
108 | sleep 5
109 | }
110 | stage('PromoteProd') {
111 | echo "Deploy to Prod"
112 | sleep 5
113 | }
114 | }
115 | ```
116 |
117 | Die Testpipeline besteht aus sechs Pipeline-Stages, welche auf zwei Jenkins Slaves ausgeführt werden. Die `Build` Pipeline-Stage ist aktuell die einzig ausprogrammierte Stage. Sie startet nämlich im aktuellen OpenShift Projekt den Image Build für unsere Applikation und wartet entsprechend bis dieser erfolgreich abgeschlossen ist.
118 |
119 | Die letzten drei Steps werden bedingt durch den Node Selector `node ('maven') { ... }` auf einem Jenkins Slave mit dem Namen `maven` ausgeführt. Dabei startet OpenShift mittels Kubernetes Plugin dynamisch einen Jenkins Slave Pod und führt entsprechend diese Build-Stages auf diesem Slave aus.
120 |
121 | Der `maven` Slave ist im Kubernetes Cloud Plugin vom Jenkins vorkonfiguriert. Weiter unten im Kapitel zu Custom Slaves werden Sie lernen, wie man individuelle Slaves dazu verwendet um Pipelines darauf auszuführen.
122 |
123 | ## BuildConfig Optionen
124 |
125 | Im vorherigen Lab haben wir in der BuildConfig vom Typ `jenkinsPipelineStrategy` das JenkinsFile direkt angegeben. Als Alternative dazu kann das Jenkins Pipeline File auch via Git Repository in der BuildConfig hinterlegt werden.
126 |
127 | ```yaml
128 | kind: "BuildConfig"
129 | apiVersion: "v1"
130 | metadata:
131 | name: "appuio-sample-pipeline"
132 | spec:
133 | source:
134 | git:
135 | uri: "https://github.com/appuio/simple-openshift-pipeline-example.git"
136 | strategy:
137 | jenkinsPipelineStrategy:
138 | jenkinsfilePath: Jenkinsfile
139 | ```
140 |
141 | ## Jenkins OpenShift Plugins
142 |
143 | Der durch OpenShift dynamisch deployte Jenkins ist durch eine Reihe von OpenShift Jenkins Plugins vollständig mit OpenShift gekoppelt. Einerseits kann so direkt auf Ressourcen innerhalb des Projekts zugegriffen werden, andererseits können durch entsprechendes Labelling dynamische Slaves aufgesetzt werden. Des Weiteren wird auch ein entsprechender Serviceaccount (`jenkins`) erstellt. Die Rechtevergabe kann entsprechend über diesen Serviceacount erfolgen.
144 |
145 | Zusätzliche Informationen finden Sie hier:
146 |
147 | ### OpenShift Jenkins Pipeline
148 |
149 | Mit dem OpenShift Jenkins Client Plugin kann so auf einfache Art direkt mit dem OpenShift Cluster kommuniziert und als Jenkinsfile komplexe CI/CD Pipelines implementiert werden:
150 |
151 | ```Groovy
152 | openshift.withCluster() {
153 | openshift.withProject() {
154 | echo "Hello from project ${openshift.project()} in cluster ${openshift.cluster()}"
155 | }
156 | }
157 | ```
158 |
159 | Das Plugin funktioniert als Wrapper zum `oc client`. Mit dem Plugin stehen einem also sämtliche Funktionen des Clients zur Verfügung.
160 |
161 | Weitere Informationen dazu sind unter zu finden.
162 |
163 | ### OpenShift Jenkins Sync Plugin
164 |
165 | Das OpenShift Jenkins Sync Plugin hält BuildConfig und Jenkins Jobs synchron. Des Weiteren erlaubt es das dynamische Erstellen und Definieren von Jenkins Slaves via ImageStream; mehr dazu weiter unten.
166 |
167 | ### Kubernetes Plugin
168 |
169 | Das Kubernetes Plugin wird verwendet, um die Jenkins Slaves dynamisch im OpenShift Projekt zu starten.
170 |
171 | ### Custom Slaves
172 |
173 | Custom Jenkins Slaves können einfach in den Build integriert werden, dafür müssen die entsprechenden Slaves als ImageStreams angelegt und mit dem Label `role=jenkins-slave` versehen werden. Diese werden dann automatisch als Pod Templates im Jenkins für das Kubernetes Plugin registriert. So können Pipelines nun über `node ('customslave'){ ... }` Teile ihrer Builds auf den entsprechenden Custom Slaves laufen lassen.
174 |
175 | #### LAB: Custom Jenkins Slave als Build Slave verwenden
176 |
177 | Um Custom Images als Jenkins Slaves zu verwenden muss man auf dem ImageStream ein Label `role=jenkins-slave` definieren.
178 |
179 | Aufgrund des Labels synchronisiert das Jenkins Sync Plugin dann die Konfiguration für das Kubernetes Plugin als Pod Templates. Beim Starten des Jenkins werden so gelabelte ImagesStreams gesynched und im Jenkins als Kubernetes Pod Templates angelegt.
180 |
181 | Erstellen wir nun in unserem Projekt einen Custom Jenkins Slave. Zur Veranschaulichung verwenden wir dazu ein Image von Docker Hub, das als Maven Jenkins Slave fungiert:
182 |
183 | ```bash
184 | oc import-image custom-jenkins-slave --from=docker.io/openshift/jenkins-slave-maven-centos7 --confirm
185 | ```
186 |
187 | Mit diesem Befehl haben wir einen ImageStream zu diesem Image angelegt. Wir inspizieren ihn über die Web Console oder mit dem oc Tool.
188 |
189 | Tipp
Administrator Web Console: Builds -> Image Streams -> custom-jenkins-slave
oc Tool: oc describe is/custom-jenkins-slave
190 |
191 | Anschliessend definieren wir mittels dem Label `role` noch, dass es sich um einen Jenkins Slave handelt:
192 |
193 | ```bash
194 | oc label is custom-jenkins-slave role=jenkins-slave
195 | ```
196 |
197 | Nach maximal 5 Minuten ist der Custom Slave im Jenkins verfügbar. Der Sync Mechanismus läuft nur alle 5 Minuten.
198 |
199 | Schauen wir uns die Konfiguration im Jenkins Konfigurations-Menu an: https://[jenkins-route]/configureClouds/
200 |
201 | Unser `custom-jenkins-slave` ist in den Pod Templates ersichtlich:
202 |
203 | 
204 |
205 | Jetzt kann mittels folgender Ergänzung im JenkinsFile das `custom-jenkins-slave` in der Pipeline verwendet werden:
206 |
207 | ```groovy
208 | node ('custom-jenkins-slave') {
209 | stage('custom stage') {
210 | echo "Running on the custom jenkins slave"
211 | }
212 | }
213 | ```
214 |
215 | Erweitern Sie ihre Pipeline mit dieser Stage entweder im Jenkins Job, der Web Console oder in der BuildConfig.
216 |
217 | __Note__:
218 | Der einfachste Weg ist die Pipeline im Jenkins GUI zu erweitern.
219 | Dazu den Job `appuio-sample-pipeline` auswählen und `Configure` anklicken.
220 | Dort ist der Code der Pipeline in einem Editor Fenster veränderbar.
221 | Einfach das `custom-jenkins-slave` Code Snippet am Schluss der Pipeline einfügen.
222 | Mit `Build Now` einen neuen Build starten.
223 |
224 | Überprüfen Sie, dass die neue Stage ausgeführt wurde.
225 |
226 | Über diesen Mechanismus lassen sich beliebige - auch selbst gebaute - Jenkins Slaves aufsetzen und verwenden. Es stehen out-of-the-box ein `maven` und `gradle` sowie ein `NodeJS` Slave zur Verfügung.
227 |
228 | Will man selber Jenkins Slaves bauen, sollte man auf dem `openshift/jenkins-slave-base-centos7` Image basieren.
229 |
230 | ## LAB: Multi-Stage Deployment
231 |
232 | Als nächstes wollen wir nun unsere Pipeline weiter ausbauen und das Deployment der Applikation auf den unterschiedlichen Stages (dev, test, prod) angehen.
233 |
234 | Für ein Multi-Stage Deployment auf OpenShift hat sich das folgende Setup als Best Practice erwiesen:
235 |
236 | - Ein Build Projekt, CI/CD Umgebung Jenkins, Image Builds, S2I Builds, ...
237 | - Pro Stage (dev, test, ..., prod) ein Projekt, welches die laufenden Pods und Services enthält, was uns erlaubt, sämtliche Umgebungen praktisch identisch zu halten
238 |
239 | Das Build Projekt haben wir oben bereits eingerichtet (`[USER]-buildpipeline`). Als nächsten Schritt erstellen wir nun die Projekte für die unterschiedlichen Stages:
240 |
241 | - [USER]-pipeline-dev
242 | - [USER]-pipeline-test
243 | - [USER]-pipeline-prod
244 |
245 |
246 | Tipp
247 | oc new-project [USER]-pipeline-dev
248 | oc new-project [USER]-pipeline-test
249 | oc new-project [USER]-pipeline-prod
250 |
251 |
252 | Nun müssen wir dem `puller` Serviceaccount aus den entsprechenden Projekten pro Stage die nötigen Rechte geben, damit die gebuildeten Images gepullt werden können.
253 |
254 | ```bash
255 | oc policy add-role-to-group system:image-puller system:serviceaccounts:[USER]-pipeline-dev -n [USER]-buildpipeline
256 | oc policy add-role-to-group system:image-puller system:serviceaccounts:[USER]-pipeline-test -n [USER]-buildpipeline
257 | oc policy add-role-to-group system:image-puller system:serviceaccounts:[USER]-pipeline-prod -n [USER]-buildpipeline
258 | ```
259 |
260 | Des Weiteren müssen wir nun dem `jenkins` Serviceaccount aus dem Projekt `[USER]-buildpipeline` Rechte geben, damit er in den Projekten der Stages Ressourcen anlegen kann.
261 |
262 | ```bash
263 | oc policy add-role-to-user edit system:serviceaccount:[USER]-buildpipeline:jenkins -n [USER]-pipeline-dev
264 | oc policy add-role-to-user edit system:serviceaccount:[USER]-buildpipeline:jenkins -n [USER]-pipeline-test
265 | oc policy add-role-to-user edit system:serviceaccount:[USER]-buildpipeline:jenkins -n [USER]-pipeline-prod
266 | ```
267 |
268 | Als nächstes erstellen wir in den Stage-Projekten die Applikationen. Dafür definieren wir einen Tag im ImageStream, welcher deployt werden soll. Zuvor müssen wir aber die entsprechenden Tags erstellen, die deployt werden sollen:
269 |
270 | ```bash
271 | oc tag [USER]-buildpipeline/application:latest [USER]-buildpipeline/application:dev
272 | oc tag [USER]-buildpipeline/application:dev [USER]-buildpipeline/application:test
273 | oc tag [USER]-buildpipeline/application:test [USER]-buildpipeline/application:prod
274 | ```
275 |
276 | ### Erstellen der Applikationen
277 |
278 | In jeder Stage erstellen wir nun die Applikation anhand des vorher angelegten ImageStreams.
279 |
280 | Achtung, die Applikationen müssen im richtigen Projekt erstellt werden.
281 |
282 |
283 | Tipp
284 | dev: oc new-app [USER]-buildpipeline/application:dev -n [USER]-pipeline-dev
285 | test: oc new-app [USER]-buildpipeline/application:test -n [USER]-pipeline-test
286 | prod: oc new-app [USER]-buildpipeline/application:prod -n [USER]-pipeline-prod
287 |
288 |
289 | Danach können wir noch die Applikation exponieren.
290 |
291 |
292 | Tipp
293 | dev: oc create route edge --service=application -n [USER]-pipeline-dev
294 | test: oc create route edge --service=application -n [USER]-pipeline-test
295 | prod: oc create route edge --service=application -n [USER]-pipeline-prod
296 |
297 |
298 | In der Pipeline können wir nun mittels Setzen eines bestimmten Tags auf dem Imagestream der gebauten Applikation, bspw. `application:dev`, das entsprechende Image in die passende Stage promoten und deployen.
299 |
300 | Passen Sie ihre Pipeline entweder im Jenkins Job, der Web Console oder in der BuildConfig wie folgt an (die Werte für die Variablen `dev_project`, `test_project`, `prod_project` entsprechend setzen):
301 |
302 | ```groovy
303 | def project=""
304 | def dev_project="[USER]-pipeline-dev"
305 | def test_project="[USER]-pipeline-test"
306 | def prod_project="[USER]-pipeline-prod"
307 | node {
308 | stage('Init') {
309 | project = env.PROJECT_NAME
310 | }
311 | stage('Build') {
312 | echo "Build"
313 | openshift.withCluster() {
314 | openshift.withProject() {
315 | def builds = openshift.startBuild("application")
316 | builds.logs('-f')
317 | timeout(5) {
318 | builds.untilEach(1) {
319 | return (it.object().status.phase == "Complete")
320 | }
321 | }
322 | }
323 | }
324 | }
325 | stage('Test') {
326 | echo "Test"
327 | sleep 2
328 | }
329 | }
330 | node ('maven') {
331 | stage('DeployDev') {
332 | echo "Deploy to Dev"
333 | openshift.withCluster() {
334 | openshift.withProject() {
335 | // Tag the latest image to be used in dev stage
336 | openshift.tag("$project/application:latest", "$project/application:dev")
337 | }
338 | openshift.withProject(dev_project) {
339 | // trigger Deployment in dev project
340 | def dc = openshift.selector('deploy', "application")
341 | dc.rollout().status()
342 | }
343 | }
344 | }
345 | stage('PromoteTest') {
346 | echo "Deploy to Test"
347 | openshift.withCluster() {
348 | openshift.withProject() {
349 | // Tag the dev image to be used in test stage
350 | openshift.tag("$project/application:dev", "$project/application:test")
351 | }
352 | openshift.withProject(test_project) {
353 | // trigger Deployment in test project
354 | def dc = openshift.selector('deploy', "application")
355 | dc.rollout().status()
356 | }
357 | }
358 | }
359 | stage('ApproveProd') {
360 | input message: 'Deploy to production?',
361 | id: 'approval'
362 | }
363 | stage('PromoteProd') {
364 | echo "Deploy to Prod"
365 | openshift.withCluster() {
366 | openshift.withProject() {
367 | // Tag the test image to be used in prod stage
368 | openshift.tag("$project/application:test", "$project/application:prod")
369 | }
370 | openshift.withProject(prod_project) {
371 | // trigger Deployment in prod project
372 | def dc = openshift.selector('deploy', "application")
373 | dc.rollout().status()
374 | }
375 | }
376 | }
377 | }
378 | ```
379 |
380 | Führen Sie die Pipeline erneut aus und schauen Sie sich an, wie nun die gebaute Applikation von Stage zu Stage deployt wird.
381 |
382 | 
383 |
384 | ## Jenkins Pipeline Sprache
385 |
386 | Unter finden Sie ein entsprechendes Hands-on Lab zur Jenkins Pipeline Sprache. Die Syntax ist [hier](https://jenkins.io/doc/book/pipeline/syntax/) beschrieben.
387 |
388 | ## Deployment von Ressourcen und Konfiguration
389 |
390 | Bisher haben wir nur die Applikation mittels unserer Deployment Pipeline deployt. Wie können wir nun unsere Pipeline auch dazu verwenden, um Ressourcen (Deployments, Routen, Cronjobs...) zu deployen?
391 |
392 | Ebenso haben wir weiter oben mit dem Befehl `oc new-app [USER]-buildpipeline/application:stage -n [USER]-pipeline-stage` im Hintergrund die nötigen Ressourcen angelegt. In unserem Fall `Service` und `Deployment`.
393 |
394 | Diese Resourcen sind Konfiguration, die sich analog der eigentlichen Applikation weiterentwickeln können und ebenso mittels CI/CD Pipeline deployt werden sollten.
395 |
396 | Die Konfigurationswerte der Umgebungsvariablen zur Konfiguration der eigentlichen Applikation veranschaulichen diese Notwendigkeit, bspw. um die Verbindung zu einem Mail Server aus der Applikation heraus herstellen zu können.
397 |
398 | Ändern die Parameter in dieser Konfiguration auf einer Umgebung, bspw. Benutzername oder Passwort, sollen diese Werte mittels Pipeline deployt werden.
399 |
400 | Als Grundprinzip kann man sich das so vorstellen:
401 |
402 | - Resourcen werden als Files (`yaml` oder `json`) im Git verwaltet
403 | - Im Rahmen der Deployment Pipeline werden diese Ressourcen entsprechend auf dem Kubernetes Cluster angewandt
404 |
405 | Es kann sogar so weit gehen, dass man Ressourcen, welche noch nicht existieren, via Pipeline erstellt, somit also die ganze Umgebung per Knopfdruck aufsetzt.
406 |
407 | In der Jenkins Pipeline erfolgt dies dann über den `openshift.apply(r)` Befehl, wobei die Variable `r` der entsprechenden Ressource entspricht.
408 |
--------------------------------------------------------------------------------
/additional-labs/resources/cronjob_mariadb-dump.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: batch/v2alpha1
2 | kind: CronJob
3 | metadata:
4 | name: mariadb-backup
5 | spec:
6 | concurrencyPolicy: Forbid
7 | jobTemplate:
8 | spec:
9 | template:
10 | spec:
11 | containers:
12 | - name: mariadb-backup
13 | image: mariadb
14 | command:
15 | - "bash"
16 | - "-eo"
17 | - "pipefail"
18 | - "-c"
19 | - >
20 | trap "echo Backup failed; exit 0" ERR;
21 | FILENAME=backup-${MYSQL_DATABASE}-`date +%Y-%m-%d_%H%M%S`.sql.gz;
22 | mysqldump --user=${MYSQL_USER} --password=${MYSQL_PASSWORD} --host=${MYSQL_HOST} --port=${MYSQL_PORT} --skip-lock-tables --quick --add-drop-database --routines ${MYSQL_DATABASE} | gzip > /tmp/$FILENAME;
23 | echo "";
24 | echo "Backup successful"; du -h /tmp/$FILENAME;
25 | env:
26 | - name: MYSQL_DATABASE
27 | valueFrom:
28 | secretKeyRef:
29 | key: database-name
30 | name: mariadb
31 | - name: MYSQL_USER
32 | valueFrom:
33 | secretKeyRef:
34 | key: database-user
35 | name: mariadb
36 | - name: MYSQL_HOST
37 | value: mariadb
38 | - name: MYSQL_PORT
39 | value: "3306"
40 | - name: MYSQL_PASSWORD
41 | valueFrom:
42 | secretKeyRef:
43 | key: database-password
44 | name: mariadb
45 | restartPolicy: OnFailure
46 | backoffLimit: 3
47 | schedule: 12 23 * * *
48 |
--------------------------------------------------------------------------------
/additional-labs/resources/job_mariadb-dump.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: batch/v1
2 | kind: Job
3 | metadata:
4 | name: mariadb-dump
5 | spec:
6 | template:
7 | spec:
8 | containers:
9 | - name: mariadb
10 | image: mariadb
11 | command:
12 | - "bash"
13 | - "-eo"
14 | - "pipefail"
15 | - "-c"
16 | - >
17 | trap "echo Backup failed; exit 0" ERR;
18 | FILENAME=backup-${MYSQL_DATABASE}-`date +%Y-%m-%d_%H%M%S`.sql.gz;
19 | mysqldump --user=${MYSQL_USER} --password=${MYSQL_PASSWORD} --host=${MYSQL_HOST} --port=${MYSQL_PORT} --skip-lock-tables --quick --add-drop-database --routines ${MYSQL_DATABASE} | gzip > /tmp/$FILENAME;
20 | echo "";
21 | echo "Backup successful"; du -h /tmp/$FILENAME;
22 | env:
23 | - name: MYSQL_DATABASE
24 | valueFrom:
25 | secretKeyRef:
26 | key: database-name
27 | name: mariadb
28 | - name: MYSQL_USER
29 | valueFrom:
30 | secretKeyRef:
31 | key: database-user
32 | name: mariadb
33 | - name: MYSQL_HOST
34 | value: mariadb
35 | - name: MYSQL_PORT
36 | value: "3306"
37 | - name: MYSQL_PASSWORD
38 | valueFrom:
39 | secretKeyRef:
40 | key: database-password
41 | name: mariadb
42 | restartPolicy: OnFailure
43 | backoffLimit: 3
44 |
--------------------------------------------------------------------------------
/additional-labs/resources/properties.properties:
--------------------------------------------------------------------------------
1 | key=appuio
2 | key2=openshift
3 |
--------------------------------------------------------------------------------
/additional-labs/resources/simple-jenkins-pipeline.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: List
3 | items:
4 | - apiVersion: v1
5 | kind: ImageStream
6 | metadata:
7 | name: application
8 | spec:
9 | lookupPolicy:
10 | local: false
11 | - apiVersion: v1
12 | kind: BuildConfig
13 | metadata:
14 | name: application
15 | spec:
16 | output:
17 | to:
18 | kind: ImageStreamTag
19 | name: application:latest
20 | source:
21 | git:
22 | uri: https://github.com/appuio/example-php-sti-helloworld.git
23 | type: Git
24 | strategy:
25 | sourceStrategy:
26 | from:
27 | kind: ImageStreamTag
28 | name: php:7.3
29 | namespace: openshift
30 | type: Source
31 | - apiVersion: v1
32 | kind: BuildConfig
33 | metadata:
34 | name: appuio-sample-pipeline
35 | spec:
36 | strategy:
37 | jenkinsPipelineStrategy:
38 | jenkinsfile: |-
39 | def project=""
40 | node {
41 | stage('Init') {
42 | project = env.PROJECT_NAME
43 | }
44 | stage('Build') {
45 | echo "Build"
46 | openshift.withCluster() {
47 | openshift.withProject() {
48 | def builds = openshift.startBuild("application")
49 | builds.logs('-f')
50 | timeout(5) {
51 | builds.untilEach(1) {
52 | return (it.object().status.phase == "Complete")
53 | }
54 | }
55 | }
56 | }
57 | }
58 | stage('Test') {
59 | echo "Test"
60 | sleep 2
61 | }
62 | }
63 | node ('maven') {
64 | stage('DeployDev') {
65 | echo "Deploy to Dev"
66 | sleep 5
67 | }
68 | stage('PromoteTest') {
69 | echo "Deploy to Test"
70 | sleep 5
71 | }
72 | stage('PromoteProd') {
73 | echo "Deploy to Prod"
74 | sleep 5
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/dev-labs/01_using_oc_cli.md:
--------------------------------------------------------------------------------
1 | # OC CLI Verwendung
2 |
3 | Melden Sie sich bei der Web Console an und machen Sie sich mit der Benutzeroberfläche vertraut.
4 |
5 | Ein Projekt ist eine Gruppierung von Ressourcen (container and docker images, pods, services, routes, configuration, quotas, limits and more). Die für das Projekt berechtigten Benutzer können diese Ressourcen verwalten. Der Projektname muss innerhalb des OpenShift clusters eindeutig sein.
6 | Erstellen Sie über die Web Console ein neues Projekt mit dem Namen:
7 |
8 | [USERNAME]-webui
9 |
10 | ## Loggen Sie mit der CLI ein
11 |
12 | Kopieren Sie den Login-Befehl von der Web Console (haben Sie diese Option gefunden? -> im Menü auf der rechten Seite)
13 |
14 | oc login https://techlab.openshift.ch:443 --token=XYZ
15 | oc whoami
16 |
17 | Mit dem Token haben Sie eine angemeldete Sitzung und können sich über die CLI (auf der API) anmelden, ohne dort die Authentifizierung vorzunehmen.
18 |
19 | Sobald Sie angemeldet sind, machen wir uns mit der CLI und ihren Befehlen vertraut.
20 |
21 | ## Hilfe bekommen
22 |
23 | oc cli bietet eine Hilfeausgabe sowie eine ausführlichere Hilfe für jeden Befehl:
24 |
25 | oc help
26 | oc projects -h
27 | oc projects
28 |
29 | ## Erstellen Sie ein neues Projekt mit dem CLI
30 |
31 | Erstellen Sie ein Projekt mit dem Namen "[USERNAME]-cli"
32 |
33 | Damit erhalten Sie Hilfe zur Projekt Erstellung
34 |
35 | oc new-project -h
36 |
37 | Lösung
oc new-project [USERNAME]-cli
38 |
39 | Wir wechseln automatisch zu unserem Projekt:
40 |
41 | oc project
42 |
43 | Wir können unser Projekt überprüfen, indem wir es entweder beschreiben oder eine yaml (oder json) formatierte Ausgabe unseres erstellten Projekts erhalten.
44 |
45 | oc describe project [USERNAME]-cli
46 | oc get project [USERNAME]-webui -o yaml
47 | oc get project [USERNAME]-webui -o json
48 |
49 | ## Hinzufügen von Benutzern zu einem Projekt
50 |
51 | OpenShift kann mehrere Benutzer (auch mit unterschiedlichen Rollen) in einem Projekt haben. Dazu können wir dem Projekt einzelne Benutzer oder auch eine Gruppe von Benutzern hinzufügen.
52 |
53 | Benutzer oder Gruppen können unterschiedliche Rollen innerhalb des gesamten Clusters oder lokal innerhalb eines Projekts haben.
54 |
55 | Weitere Informationen zu Rollen finden Sie [hier](https://docs.openshift.com/container-platform/latest/authentication/using-rbac.html) und zu deren Verwaltung [hier](https://docs.openshift.com/container-platform/4.3/authentication/using-rbac.html#viewing-cluster-roles_using-rbac).
56 |
57 | Um alle aktiven Rollen in Ihrem aktuellen Projekt anzuzeigen, können Sie folgendes eingeben:
58 |
59 | oc describe rolebinding.rbac
60 |
61 | Für Ihr webui Projekt:
62 |
63 | oc describe rolebinding.rbac -n [USERNAME]-webui
64 |
65 | Wir können Rollen verwalten, indem wir Befehle für `oc adm policy` absetzen:
66 |
67 | oc adm policy -h
68 |
69 | Für dieses Lab gibt es eine Gruppe namens `techlab`, in der alle Techlab-Benutzer enthalten sind.
70 |
71 | Fügen wir diese Gruppe mit der Administrator Rolle zu unserem aktuellen Projekt hinzu, damit wir die Sachen in diesen Projekten gemeinsam entwickeln können.
72 |
73 | oc adm policy add-role-to-group -h
74 | oc adm policy add-role-to-group admin techlab -n [USERNAME]-cli
75 |
76 | Zu viele Rechte? Zumindest für unser webui Projekt, also lasst uns die Benutzer nur als Viewer hinzufügen:
77 |
78 | oc adm policy add-role-to-group view techlab -n [USERNAME]-webui
79 |
80 | Sie können auch die bisherigen Berechtigungen des `[USERNAME]-cli` Projekts entfernen.
81 |
82 | oc adm policy remove-role-from-group admin techlab -n [USERNAME]-cli
83 |
84 | Wie viele andere haben uns zu ihren Projekten hinzugefügt? Schauen wir uns die aktuelle Liste der Projekte an:
85 |
86 | oc projects
87 |
88 | Überprüfen Sie die Änderungen in der Web Console. Gehen Sie zu Ihren beiden Projekten und finden Sie die techlab Gruppe unter _Resources -> Membership_
89 |
90 | ## Überprüfen und Bearbeiten anderer Ressourcen
91 |
92 | Alles in OpenShift (Kubernetes) wird als Ressource repräsentiert, die wir anzeigen und abhängig von unseren Berechtigungen bearbeiten können.
93 |
94 | Sie können alle Ressourcen Ihres aktuellen Projekts abrufen, indem Sie folgendes eingeben:
95 |
96 | oc get all
97 |
98 | Sie sehen nichts? Oder nur "No resources found."
99 | Dies liegt daran, dass wir noch nichts deployed haben. Sie können eine infache Applikation deployen und den `oc get` Befahl wiederholen.
100 |
101 | oc new-app https://github.com/appuio/example-php-sti-helloworld.git
102 |
103 | Sie können auch alle Ressourcen der Namespaces (Projekte) abrufen, auf die Sie Zugriff haben.
104 |
105 | Nehmen Sie das Projekt `openshift-web-console`, das einige Ressourcen zum untersuchen enthält.
106 | Klicken Sie auf Befehl, wenn Sie keine Lösung gefunden haben, wie Sie den Namespace zum Befehl hinzufügen können.
107 |
108 | Befehl
oc get all -n openshift-web-console
109 |
110 | Wenn Sie eine interessante Ressource gefunden haben, die Sie untersuchen möchten, können Sie jede einzelne mit den Befehlen `describe/get` anschauen:
111 |
112 | allgemeiner Befehl
oc describe [RESOURCE_TYPE] [RESOURCE_NAME] -n openshift-web-console
113 | Befehl zum Überprüfen eines Service
oc describe service webconsole -n openshift-web-console
114 |
115 | Sie können die Ressourcen auch bearbeiten:
116 |
117 | oc edit [RESOURCE_TYPE] [RESOURCE_NAME]
118 |
119 | Lassen Sie uns zum Beispiel unser webui Projekt bearbeiten.
120 |
121 | Befehl
oc edit project [USERNAME]-webui
122 |
123 | Dies war nur ein Beispiel. Verlassen Sie den Editor, indem Sie Folgendes eingeben: _ESC_ und _:_ und _q_
124 |
125 | ## Ressourcen löschen
126 |
127 | Sie sind nicht glücklich darüber, wie Ihre aktuellen Projekte verlaufen sind und möchten von vorne beginnen?
128 |
129 | oc delete project [USERNAME]-webui
130 |
131 | Dadurch werden alle von diesem Projekt gebündelten Ressourcen gelöscht. Projekte sind eine einfache Möglichkeit, Dinge auszuprobieren, und wenn Sie fertig sind, können Sie sie problemlos bereinigen.
132 |
133 | ## Wie geht es meinen Ressourcen?
134 |
135 | Sie können sich jederzeit einen Überblick über Ihre aktuellen Ressourcen verschaffen, indem Sie folgendes eingeben:
136 |
137 | oc status
138 |
139 | Dies wird praktisch, sobald wir mehr Sachen deployen.
140 |
--------------------------------------------------------------------------------
/dev-labs/02_builds.md:
--------------------------------------------------------------------------------
1 | # Builds
2 |
3 | Es gibt drei verschiedene Arten von Builds:
4 |
5 | 1. Source-To-Image (s2i)
6 | 2. Binary Builds
7 | 3. Container aka. Docker Builds
8 |
9 | Werfen wir einen Blick auf die verschiedenen Arten von Builds
10 |
11 | ## Source-To-Image
12 |
13 | Einfachster Einstieg von einer Codebasis (z. B. Ruby, Python, PHP) in eine ausgeführte Anwendung, die alle Abhängigkeiten enthält.
14 |
15 | Es erstellt alle erforderlichen Build- und Deployment-Konfigurationen.
16 |
17 | Erstellen Sie zunächst ein Projekt mit dem Namen "[USERNAME]-s2i"
18 |
19 | Befehl zum Erstellen eines Projekts
oc new-project [USERNAME]-s2i
20 |
21 | Unser Beispiel basiert auf einer sehr einfachen PHP-Anwendung, welche auf APPUiO GitHub gehostet wird.
22 | Erstellen Sie eine Applikation mit dem Namen `s2i` aus diesem Repository:
23 |
24 | Hinweis zur Befehlshilfe:
25 |
26 | ```bash
27 | oc new-app -h
28 | ```
29 |
30 | Befehl zum Erstellen einer App
oc new-app https://github.com/appuio/example-php-sti-helloworld.git --name=s2i
31 |
32 | Die `new-app` Funkionalität erkennt das Git Repo als PHP Projekt und erstellt eine s2i Applikation.
33 |
34 | Überprüfen Sie den Status Ihres Projekts.
35 |
36 | Projektstatusbefehl
oc status
37 |
38 | Erkunden Sie die verschiedenen Ressourcen, die mit dem `new-app` Befehl erstellt wurden.
39 |
40 | Um etwas im Browser anzuzeigen, erstellen Sie eine Route für den Zugriff auf die Anwendung:
41 |
42 | ```bash
43 | oc create route edge --insecure-policy=Allow --service=s2i
44 | ```
45 |
46 | Die URL, welche nun auf unsere ruby applikation zeigt, erhalten wir indem wir die route beschreiben (`oc describe`). Sie finden die URL auch in der Web Console. Sehen sie sich die applikation auch dort an.
47 |
48 | ## Binary build
49 |
50 | In diesem Beispiel wird beschrieben, wie Sie ein Webarchiv (war) in Wildfly mithilfe des OpenShift-Clients (oc) im binary Modus deployen.
51 | Das Beispiel ist vom APPUiO-Blog inspiriert:
52 |
53 | ### Erstellen Sie ein neues Projekt
54 |
55 | Erstellen Sie ein Projekt mit dem Namen "[USERNAME]-binary-build"
56 |
57 | Befehl zum Erstellen eines Projekts
oc new-project [USERNAME]-binary-build
58 |
59 | ### Erstellen Sie die Deployment Verzeichnisstruktur
60 |
61 | Bereiten Sie einen temporären Ordner vor und erstellen Sie darin die Deployment Verzeichnisstruktur.
62 |
63 | Mindestens ein War-File kann im Deployment Ordner abgelegt werden. In diesem Beispiel wird eine vorhandene War-Datei aus einem Git-Repository heruntergeladen.
64 |
65 | * Verzeichnis: `tmp-bin/deployments`
66 | * Datei: [hello-world-war-1.0.0.war](https://github.com/appuio/hello-world-war/blob/master/repo/ch/appuio/hello-world-war/1.0.0/hello-world-war-1.0.0.war?raw=true)
67 |
68 | **Note:** Das War-File muss den Namen `ROOT.war` haben, damit die Anwendung direkt auf der Route verfügbar ist. Wenn die Datei [hello-world-war-1.0.0.war](https://github.com/appuio/hello-world-war/blob/master/repo/ch/appuio/hello-world-war/1.0.0/hello-world-war-1.0.0.war?raw=true) manuell heruntergeladen wurde, muss sie umbenannt werden: `tmp-bin/deployments/ROOT.war`
69 |
70 | Befehle für Shell und PowerShell:
71 |
72 | ```bash
73 | mkdir -p tmp-bin/deployments
74 | cd tmp-bin
75 | wget -O deployments/ROOT.war 'https://github.com/appuio/hello-world-war/blob/master/repo/ch/appuio/hello-world-war/1.0.0/hello-world-war-1.0.0.war?raw=true'
76 | ```
77 |
78 | ### Erstellen Sie einen neuen Build mit dem Wildfly Container Image
79 |
80 | Erstellen Sie eine Build-Konfiguration für einen binary-Build mit folgenden Attributen:
81 |
82 | - Basis Container Image: `openshift/wildfly-160-centos7`
83 | - Name: `hello-world`
84 | - Label: `app=hello-world`.
85 | - Typ: `binary`
86 |
87 | Das Flag _binary=true_ zeigt an, dass dieser Build seine Daten direkt als Input erhält, anstatt via URL (Git Repo).
88 |
89 | Befehl:
90 |
91 | ```bash
92 | oc new-build --image=openshift/wildfly-160-centos7 --binary=true --name=hello-world -l app=hello-world
93 | ```
94 |
95 | Befehl mit Ausgabe:
96 |
97 | ```bash
98 | $ oc new-build --image=openshift/wildfly-160-centos7 --binary=true --name=hello-world -l app=hello-world
99 | --> Found Docker image 7ff222e (7 months old) from Docker Hub for "openshift/wildfly-160-centos7"
100 |
101 | WildFly 16.0.0.Final
102 | --------------------
103 | Platform for building and running JEE applications on WildFly 16.0.0.Final
104 |
105 | Tags: builder, wildfly, wildfly16
106 |
107 | * An image stream tag will be created as "wildfly-160-centos7:latest" that will track the source image
108 | * A source build using binary input will be created
109 | * The resulting image will be pushed to image stream tag "hello-world:latest"
110 | * A binary build was created, use 'start-build --from-dir' to trigger a new build
111 |
112 | --> Creating resources with label app=hello-world ...
113 | imagestream.image.openshift.io "wildfly-160-centos7" created
114 | imagestream.image.openshift.io "hello-world" created
115 | buildconfig.build.openshift.io "hello-world" created
116 | --> Success
117 | ```
118 |
119 | Siehe die Befehlsausgabe für die erstellten Ressourcen.
120 |
121 | Überprüfen Sie die erstellten Ressourcen mit dem oc-Tool und in der Web Console. Finden Sie den erstellten Build in der Web Console?
122 |
123 | ## Build starten
124 |
125 | Um einen Build auszulösen, geben Sie den folgenden Befehl ein. In einem kontinuierlichen Deployment-Prozess kann dieser Befehl wiederholt werden, wenn eine neue Binärdatei oder eine neue Konfiguration verfügbar ist.
126 |
127 | Die Kernfunktion des Binary-Builds besteht darin, die Dateien für den Build aus dem lokalen Verzeichnis bereitzustellen.
128 | Diese Dateien werden in den Build-Container geladen, der in OpenShift ausgeführt wird.
129 |
130 | ```bash
131 | oc start-build hello-world --from-dir=. --follow
132 | ```
133 |
134 | Der Parameter _--from-dir=._ teilt dem oc-Tool mit, welches Verzeichnis hochgeladen werden soll.
135 |
136 | Das _--follow_-Flag zeigt das Build-Protokoll auf der Konsole an und wartet, bis der Build abgeschlossen ist.
137 |
138 | ### Eine neue Applikation erstellen
139 |
140 | Erstellen Sie eine neue App basierend auf dem Container-Image, das mit dem Binary-Build erstellt wurde.
141 |
142 | ```bash
143 | oc new-app hello-world -l app=hello-world
144 | ```
145 |
146 | Siehe die Befehlsausgabe für die erstellten Ressourcen.
147 |
148 | Überprüfen Sie die erstellten Ressourcen mit dem oc-Tool und in der Web Console.
149 | Versuchen Sie herauszufinden, ob Wildfly gestartet ist.
150 |
151 | ### Applikations-Service als Route zur Verfügung stellen
152 |
153 | ```bash
154 | oc create route edge --service=hello-world
155 | ```
156 |
157 | Klicken Sie in der Web Console auf die Route, um die Ausgabe der `hello-world`-Anwendung anzuzeigen.
158 |
159 | ## Container Build
160 |
161 | Wir können auch beliebige Container basierend auf Dockerfiles erstellen.
162 |
163 | Erstellen Sie zunächst ein Projekt mit dem Namen "[USERNAME]-docker-build"
164 |
165 | Projektbefehl erstellen
oc new-project [USERNAME]-docker-build
166 |
167 | Befehl zum Erstellen eines Docker-Builds:
168 |
169 | ```bash
170 | oc new-build --strategy=docker --binary=true --name=web -l app=web centos/httpd-24-centos7
171 | ```
172 |
173 | Klonen Sie das techlab Git-Repository, falls Sie es noch nicht getan haben. Alternativ kann das Repository als Zip-Datei [hier](https://github.com/appuio/techlab/archive/lab-3.11.zip) geholt und entpackt werden.
174 |
175 | ```bash
176 | git clone https://github.com/appuio/techlab.git --branch=lab-4
177 | ```
178 |
179 | Navigieren Sie zum Stammverzeichnis des Git-Repositorys (`cd techlab`). Stellen Sie sicher, dass Sie sich auf dem `lab-4` Git Branch befinden.
180 |
181 | Starten Sie den Build mit den Daten aus `dev-labs/data/02_httpd`:
182 |
183 | ```bash
184 | oc start-build web --from-dir=dev-labs/data/02_httpd --follow
185 | ```
186 |
187 | Verfolgen Sie, wie der Build abläuft und ob das Image in Ihrer Registry vorhanden sein wird.
188 |
189 | Erstellen Sie eine Applikation mit diesem Image und machen Sie es verfügbar:
190 |
191 | ```bash
192 | oc new-app web -l app=web
193 | oc create route edge --service=web
194 | ```
195 |
196 | Klicken Sie in der Web Console auf die Route, um die Website Ihrer Anwendung anzuzeigen.
197 |
198 | Versuchen Sie, ein Easter-Egg unter der URL `/easter-egg.txt` hinzuzufügen. Wie würden Sie vorgehen?
199 | Untersuchen Sie "dev-labs/data/02_httpd" auf einen Hinweis.
200 |
201 |
202 | Lösung
203 | Fügen Sie im Dockerfile einen COPY-Befehl hinzu, um die Datei easter-egg.txt nach /var/www/html/ zu kopieren :
204 | ...
205 | COPY ./easter-egg.txt /var/www/html/
206 | ...
207 | Nach der Anpassung muss ein neuer Build gestartet werden.
208 |
209 |
210 | Hat es funktioniert? ->
211 |
--------------------------------------------------------------------------------
/dev-labs/03_develop.md:
--------------------------------------------------------------------------------
1 | # Applikation entwickeln
2 |
3 | In diesen Labs werden wir Applikationen entwickeln.
4 |
5 | ## Aufgaben
6 |
7 | ### Container Image deployen
8 |
9 | Folgen Sie den Anweisungen im [Lab 4: Ein Container Image deployen](../labs/04_deploy_dockerimage.md).
10 |
11 | ### Service mittels Route online verfügbar machen
12 |
13 | In dieser Aufgabe werden wir die Applikation von vorher über **https** vom Internet her erreichbar machen.
14 |
15 | Folgen Sie den Anweisungen im [Lab 5: Unseren Service mittels Route online verfügbar machen](../labs/05_create_route.md).
16 |
17 | ### Pod Scaling, Readiness Probe und Self Healing
18 |
19 | Folgen Sie den Anweisungen im [Lab 6: Pod Scaling, Readiness Probe und Self Healing](../labs/06_scale.md).
20 |
21 | ### Datenbank anbinden
22 |
23 | Folgen Sie den Anweisungen im [Lab 9: Datenbank anbinden](../labs/09_database.md).
24 |
25 | ## Zusatzübung für Schnelle
26 |
27 | Ziel ist es eine Java Spring Boot Applikation lokal zu bauen und mittels Binary Build auf die Plattform zu bringen.
28 |
29 | - Siehe dazu das Binary Build Beispiel des Labs [dev-labs/02_builds.md](./02_builds.md).
30 | - GitHub Repository mit dem Sourcecode:
31 | - Docker Hub Repository mit Java Docker Image:
32 |
33 | ### Projekt erstellen
34 |
35 | Neues Projekt mit dem Namen `[USERNAME]-spring-boot` erstellen.
36 |
37 | Tipp
oc new-project [USERNAME]-spring-boot
38 |
39 | ### Applikation bauen
40 |
41 | Zuerst das GitHub Repository klonen oder als [Zip-Datei](https://github.com/appuio/example-spring-boot-helloworld/archive/master.zip) laden und danach das Spring Boot Jar bauen.
42 |
43 | Git Clone Befehl
git clone https://github.com/appuio/example-spring-boot-helloworld.git
44 |
45 | Danach die Applikation bauen, es wird nur das JDK 11 benötigt.
46 |
47 |
48 | Applikation bauen
49 | cd example-spring-boot-helloworld/
50 | ./gradlew build
51 |
52 |
53 |
54 | Applikation bauen (auf Windows)
55 | ins Verzeichnis example-spring-boot-helloworld wechseln
56 | gradlew.bat build
57 |
58 |
59 | ### Deployment Verzeichnisstruktur
60 |
61 | Für den Binary Build eine Verzeichnisstruktur vorbereiten mit dem Jar vom Java Build.
62 |
63 | * Verzeichnis: `tmp-jar/deployments`
64 | * Datei: build/libs/springboots2idemo-0.0.1-SNAPSHOT.jar
65 |
66 | Befehle für Shell und PowerShell:
67 |
68 | ```bash
69 | mkdir -p tmp-jar/deployments
70 | cd tmp-jar
71 | cp ../build/libs/springboots2idemo-0.0.1-SNAPSHOT.jar deployments/
72 | ```
73 |
74 | #### Lokaler Test mit Docker
75 |
76 | Dockerfile mit diesem Inhalt erstellen.
77 |
78 | ```Dockerfile
79 | FROM fabric8/java-centos-openjdk11-jdk
80 |
81 | COPY deployments/*.jar deployments/
82 |
83 | EXPOSE 8080
84 | ```
85 |
86 | Builden und starten.
87 |
88 | ```bash
89 | docker build -t boot .
90 | docker run -ti -p 8080:8080 boot
91 | ```
92 |
93 | Applikation ist unter erreichbar.
94 |
95 | ### Binary Build mit Dockerfile
96 |
97 | Dockerfile Build im OpenShift erstellen.
98 |
99 | ```bash
100 | oc new-build -D $'FROM fabric8/java-centos-openjdk11-jdk\nCOPY deployments/*.jar deployments/\nEXPOSE 8080' --to spring-boot
101 | ```
102 |
103 | Wie ist der Name des ImageSteam, in welchen das gebaute Image gepushed wird?
104 |
105 | Binary Build starten mit dem Inhalt aus diesem Ordner.
106 |
107 | Tipp
oc start-build spring-boot --from-dir=. --follow
108 |
109 | ### Applikation erstellen
110 |
111 | Applikation anhand des Image Stream erstellen mit dem Label `app=spring-boot`.
112 |
113 | Tipp
oc new-app spring-boot -l app=spring-boot
114 |
115 | ### Route erstellen
116 |
117 | Den Service der Applikation als Route exposen.
118 |
119 | Tipp
oc create route edge --service=spring-boot --port=8080
120 |
121 | Wieso müssen wir hier den Port angeben?
122 |
123 | ### Applikation testen
124 |
125 | Im Browser oder mit curl das Funktionieren der Applikation überprüfen.
126 |
127 | ## Zusatzübung für ganz Schnelle
128 |
129 | Folgen Sie den Anweisungen im [Lab 11: Code Changes durch Webhook triggern Rebuild auf OpenShift](../labs/11_dockerbuild_webhook.md).
130 |
--------------------------------------------------------------------------------
/dev-labs/04_troubleshooting_autoscale.md:
--------------------------------------------------------------------------------
1 | # Troubleshooting und Autoscaling
2 |
3 | In diesen Labs werden wir Applikationen autoscalen und troubleshooten.
4 |
5 | ## Troubleshooting
6 |
7 | Folgen Sie den Anweisungen im [Lab 8: Troubleshooting](../labs/08_troubleshooting_ops.md).
8 |
9 | ## Autoscaling
10 |
11 | In diesem Beispiel werden wir eine Applikation automatisiert hoch- und runterskalieren, je nachdem unter wie viel Last die Applikation steht. Dazu verwenden wir eine Ruby Example Webapp.
12 |
13 | Erstellen Sie daher ein neues Projekt mit dem Namen `[USERNAME]-autoscale`:
14 |
15 | Tipp
oc new-project [USERNAME]-autoscale
16 |
17 | Auf dem Branch load gibt es einen CPU intensiven Endpunkt, welchen wir für unsere Tests verwenden werden. Dafür starten wir die App auf diesem Branch:
18 |
19 | ```bash
20 | oc new-app openshift/ruby:2.5~https://github.com/chrira/ruby-ex.git#load --as-deployment-config
21 | oc create route edge --insecure-policy=Redirect --service=ruby-ex
22 | ```
23 |
24 | Warten sie bis die Applikation gebaut und ready ist und erste Metriken auftauchen (siehe Web Console -> Monitoring). Sie können dem Build wie auch den vorhandenden Pods folgen.
25 |
26 | Bis die ersten Metriken auftauchen dauert es eine Weile, erst dann wird der Autoscaler richtig arbeiten können.
27 |
28 | Nun definieren wir ein Set an Limiten für unsere Applikation, die für einen einzelnen Pod Gültigkeit hat.
29 | Dazu editieren wir die `ruby-ex` DeploymentConfig:
30 |
31 | Tipp
oc edit dc ruby-ex
32 |
33 | Folgende Resource Limits fügen wir dem Container hinzu:
34 |
35 | ```yaml
36 | resources:
37 | limits:
38 | cpu: "0.2"
39 | memory: "256Mi"
40 | ```
41 |
42 | Die Ressourcen sind ursprünglich leer: `resources: {}`. Achtung die `resources` müssen auf dem Container und nicht dem Deployment definiert werden.
43 |
44 | Dies wird unser Deployment neu ausrollen und die Limiten enforcen.
45 |
46 | Sobald unser neuer Container läuft können wir nun den Autoscaler konfigurieren:
47 |
48 | Befehl mit Bestätigung:
49 |
50 | ```bash
51 | $ oc autoscale dc ruby-ex --min 1 --max 3 --cpu-percent=25
52 | horizontalpodautoscaler.autoscaling/ruby-ex autoscaled
53 | ```
54 |
55 | In der Web Console ist ersichtlich, dass das manuelle Skalieren der Pods nicht mehr möglich ist. Dafür sind dort die Werte des Autoscaler ersichtlich.
56 |
57 | Nun können wir auf dem Service Last erzeugen.
58 |
59 | Ersetzen Sie dafür `[HOSTNAME]` mit Ihrer definierten Route:
60 |
61 | Hostname abfragen
oc get route -o custom-columns=NAME:.metadata.name,HOSTNAME:.spec.host
62 |
63 | ```bash
64 | for i in {1..500}; do curl --insecure -s https://[HOSTNAME]/load ; done;
65 | ```
66 |
67 | Jede Anfrage and den Load-Endpunkt sollte mit `Extensive task done` beantwortet werden.
68 |
69 | Die aktuellen Werte holen wir über:
70 |
71 | ```bash
72 | oc get horizontalpodautoscaler.autoscaling/ruby-ex
73 | ```
74 |
75 | Folgendermassen können wir Statusänderungen unserer Pods folgen:
76 |
77 | ```bash
78 | oc get pods -w
79 | ```
80 |
81 | Sobald wir die Last beenden wird die Anzahl Pods nach einer gewissen Zeit automatisch wieder verkleinert. Die Kapazität wird jedoch eine Weile vorenthalten.
82 |
83 | ## Zusatzfrage
84 |
85 | Es gibt auch einen `oc idle` Befehl. Was macht der?
86 |
87 | ## Zusatzübung für Schnelle
88 |
89 | Zum Troubleshooting von Container ohne installierte Debugging Tools wurde die [k8s-debugbox](https://github.com/puzzle/k8s-debugbox) entwickelt.
90 |
91 | Zuerst versuchen wir das Debugging mit dem oc Tool.
92 |
93 | ### Projekt erstellen
94 |
95 | Erstellen Sie zunächst ein Projekt mit dem Namen "[USERNAME]-debugbox".
96 |
97 | Befehl zum Erstellen eines Projekts
oc new-project [USERNAME]-debugbox
98 |
99 | ### Test Applikation deployen
100 |
101 | Zum Testen eignet sich ein minimales Container Image, wie z.B. eine Go Applikation in einem leeren Dateisystem (From scratch): [s3manager](https://hub.docker.com/r/mastertinner/s3manager)
102 |
103 | Von diesem Image eine neue Applikation erstellen:
104 |
105 | * Image: mastertinner/s3manager
106 | * Environment:
107 | * ACCESS_KEY_ID=irgendoeppis
108 | * SECRET_ACCESS_KEY=x
109 |
110 | Befehl zum Erstellen der Applikation
oc new-app -e ACCESS_KEY_ID=irgendoeppis -e SECRET_ACCESS_KEY=x mastertinner/s3manager --as-deployment-config
111 |
112 | ### Debugging mit oc Tool
113 |
114 | Versuchen Sie eine Remote-Shell im Container zu öffnen:
115 |
116 | ```bash
117 | oc rsh dc/s3manager
118 | ```
119 |
120 | Fehlermeldung:
121 |
122 | ```bash
123 | ERRO[0000] exec failed: container_linux.go:349: starting container process caused "exec: \"/bin/sh\": stat /bin/sh: no such file or directory"
124 | exec failed: container_linux.go:349: starting container process caused "exec: \"/bin/sh\": stat /bin/sh: no such file or directory"
125 | command terminated with exit code 1
126 | ```
127 |
128 | Das hat nicht funktioniert, weil im Container keine Shell vorhanden ist.
129 |
130 | Können wir wenigstens das Environment ausgeben?
131 |
132 | ```bash
133 | oc exec dc/s3manager -- env
134 | ```
135 |
136 | Fehlermeldung:
137 |
138 | ```bash
139 | time="2020-04-27T06:25:13Z" level=error msg="exec failed: container_linux.go:349: starting container process caused \"exec: \\\"env\\\": executable file not found in $PATH\""
140 | exec failed: container_linux.go:349: starting container process caused "exec: \"env\": executable file not found in $PATH"
141 | command terminated with exit code 1
142 | ```
143 |
144 | Auch das geht nicht, der env Befehl steht nicht zur Verfügung.
145 |
146 | Auch wenn wir versuchen das Terminal in der Web Console zu öffnen, bekommen wir einen Fehler.
147 |
148 | Mit den Bordmitteln von OpenShift können wir diesen Container nicht debuggen. Dafür gibt es die [k8s-debugbox](https://github.com/puzzle/k8s-debugbox).
149 |
150 | ### Debugbox installieren
151 |
152 | Installieren Sie die [k8s-debugbox](https://github.com/puzzle/k8s-debugbox) anhand der Anleitung: .
153 |
154 | ### Debugbox anwenden
155 |
156 | Über den Hilfeparameter die Möglichkeiten anzeigen lassen.
157 |
158 | Befehl mit Ausgabe:
159 |
160 | ```bash
161 | $ k8s-debugbox -h
162 | Debug pods based on minimal images.
163 |
164 | Examples:
165 | # Open debugging shell for the first container of the specified pod,
166 | # install debugging tools into the container if they aren't installed yet.
167 | k8s-debugbox pod hello-42-dmj88
168 |
169 | ...
170 |
171 | Options:
172 | -n, --namespace='': Namespace which contains the pod to debug, defaults to the namespace of the current kubectl context
173 | -c, --container='': Container name to open shell for, defaults to first container in pod
174 | -i, --image='puzzle/k8s-debugbox': Docker image for installation of debugging via controller. Must be built from 'puzzle/k8s-debugbox' repository.
175 | -h, --help: Show this help message
176 | --add: Install debugging tools into specified resource
177 | --remove: Remove debugging tools from specified resource
178 |
179 | Usage:
180 | k8s-debugbox TYPE NAME [options]
181 | ```
182 |
183 | Wir wenden die Debugbox am s3manager Pod an:
184 |
185 | Tipp für Pod Suche
oc get pods
186 |
187 | ```bash
188 | $ k8s-debugbox pod s3manager-1-jw4sl
189 | Uploading debugging tools into pod s3manager-1-hnb6x
190 | time="2020-04-27T06:26:44Z" level=error msg="exec failed: container_linux.go:349: starting container process caused \"exec: \\\"tar\\\": executable file not found in $PATH\""
191 | exec failed: container_linux.go:349: starting container process caused "exec: \"tar\": executable file not found in $PATH"
192 | command terminated with exit code 1
193 |
194 | Couldn't upload debugging tools!
195 | Instead you can patch the controller (deployment, deploymentconfig, daemonset, ...) to use an init container with debugging tools, this requires a new deployment though!
196 | ```
197 |
198 | Auch dieser Versuch schlägt fehl, da die Tools ohne tar nicht in den Container kopiert werden können. Wir haben jedoch von der Debugbox die Information herhalten, dass wir die Installation über das Deployment machen sollen. Dabei wird die DeploymentConfiguration mit einem Init-Container erweitert. Der Init-Container kopiert die Tools in ein Volume, welches danach vom s3manager Container verwendet werden kann.
199 |
200 | Patching der DeploymentConfiguration:
201 |
202 | ```bash
203 | k8s-debugbox dc s3manager
204 | ```
205 |
206 | Hier der Init-Container Auszug aus der gepatchten DeploymentConfiguration:
207 |
208 | ```yaml
209 | spec:
210 | template:
211 | spec:
212 | initContainers:
213 | - image: puzzle/k8s-debugbox
214 | name: k8s-debugbox
215 | volumeMounts:
216 | - mountPath: /tmp/box
217 | name: k8s-debugbox
218 | ```
219 |
220 | Nach einem erneuten Deployment des Pods befinden wir uns in einer Shell im Container. Darin stehen uns eine Vielzahl von Tools zur Verfügung. Jetzt können wir das Debugging durchführen.
221 |
222 | Wo befinden sich die Debugging Tools?
223 |
224 | Lösung
/tmp/box/bin/
225 |
226 | **Tipp** Mit der Eingabe von `exit` beenden wir die Debugbox.
227 |
228 | Wie können wir die Änderungen an der DeploymentConfiguration rückgängig machen?
229 |
230 | Lösung
k8s-debugbox dc s3manager --remove
231 |
--------------------------------------------------------------------------------
/dev-labs/README.md:
--------------------------------------------------------------------------------
1 | # OpenShift Developer Techlab
2 |
3 | ## Agenda
4 |
5 | ### 1. Tag
6 |
7 | - [Mit der Umgebung vertraut machen](01_using_oc_cli.md)
8 | - [Builds](02_builds.md)
9 | - [Applikationen entwickeln](03_develop.md)
10 |
11 | ### 2. Tag
12 |
13 | - [Troubleshooting / Autoscale](04_troubleshooting_autoscale.md)
14 |
15 | ### Anforderungen an die Dev-Labs
16 |
17 | #### Zugriff auf Plattform
18 |
19 | Zugriff auf die Techlab OpenShift Plattform testen. Wenn folgende Tests erfolgreich sind, sollte die Durchführung des Techlabs möglich sein.
20 |
21 | 1. Zugriff mit Browser
22 | * URL: https://techlab.openshift.ch/
23 | * Log in with... "APPUiO Techlab Generic Login"
24 | * "+ Create Project" Button rechts oben
25 | 2. Zugriff mit dem `oc` CLI-Tool
26 | * Download Binary (unten bei Assets): https://github.com/openshift/origin/releases/tag/v3.11.0
27 | * Authentisieren: `oc login https://techlab.openshift.ch/`
28 | * Projekt anlegen: `oc new-project user30-test`
29 | * Applikation erstellen: `oc new-app https://github.com/appuio/example-php-sti-helloworld.git --name=s2i`
30 |
31 | #### Lab 01
32 |
33 | - techlab Benutzergruppe
34 | - openshift-web-console Projekt: view-Rechte für die techlab-Benutzergruppe
35 | - oc Tool
36 |
37 | #### Lab 02
38 |
39 | - Repo: dieses techlab Repo ([Zip](https://github.com/appuio/techlab/archive/lab-3.11.zip))
40 | - Repo:
41 | - War-File:
42 | - OpenShift ImageStream: openshift/php:7.1
43 | - Docker Hub Image: "openshift/wildfly-160-centos7"
44 | - Docker Hub Image: "centos/httpd-24-centos7"
45 |
46 | #### Lab 03
47 |
48 | - Repo: dieses techlab Repo ([Zip](https://github.com/appuio/techlab/archive/lab-3.11.zip))
49 | - Docker Hub Image: "appuio/example-spring-boot"
50 | - OpenShift Template: openshift/mysql-persistent
51 |
52 | Zusatzübung:
53 |
54 | - Repo: / ([Zip](https://github.com/appuio/example-spring-boot-helloworld/archive/master.zip))
55 | - JDK 11
56 | - optional: Docker
57 |
58 | #### Lab 04
59 |
60 | - OpenShift Projekt aus Lab 03: [USERNAME]-dockerimage
61 | - Repo:
62 | - OpenShift ImageStream: "openshift/ruby:2.5"
63 | - OpenShift metrics server:
64 | - Test: `oc get project | grep openshift-metrics-server`
65 | - optional: Docker
66 |
--------------------------------------------------------------------------------
/dev-labs/data/02_httpd/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM httpd:2.4
2 |
3 | COPY ./public-html/ /var/www/html/
4 |
--------------------------------------------------------------------------------
/dev-labs/data/02_httpd/easter-egg.txt:
--------------------------------------------------------------------------------
1 | (__)
2 | (oo)
3 | /------\/
4 | / | ||
5 | * /\---/\
6 | ~~ ~~
7 | ..."Have you mooed today?"...
8 |
--------------------------------------------------------------------------------
/dev-labs/data/02_httpd/public-html/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | OpenShift is great!
4 |
5 |
--------------------------------------------------------------------------------
/images/jenkins_oauth2_login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/jenkins_oauth2_login.png
--------------------------------------------------------------------------------
/images/jenkins_oauth2_permissions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/jenkins_oauth2_permissions.png
--------------------------------------------------------------------------------
/images/kibana1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/kibana1.png
--------------------------------------------------------------------------------
/images/kibana2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/kibana2.png
--------------------------------------------------------------------------------
/images/lab_02_cli.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/lab_02_cli.png
--------------------------------------------------------------------------------
/images/lab_03_login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/lab_03_login.png
--------------------------------------------------------------------------------
/images/lab_08_mariadb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/lab_08_mariadb.png
--------------------------------------------------------------------------------
/images/lab_09_codechange1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/lab_09_codechange1.png
--------------------------------------------------------------------------------
/images/lab_09_edit_on_github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/lab_09_edit_on_github.png
--------------------------------------------------------------------------------
/images/lab_09_fork_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/lab_09_fork_example.png
--------------------------------------------------------------------------------
/images/lab_09_webhook_github1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/lab_09_webhook_github1.png
--------------------------------------------------------------------------------
/images/lab_09_webhook_github2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/lab_09_webhook_github2.png
--------------------------------------------------------------------------------
/images/lab_09_webhook_github3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/lab_09_webhook_github3.png
--------------------------------------------------------------------------------
/images/lab_09_webhook_github4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/lab_09_webhook_github4.png
--------------------------------------------------------------------------------
/images/lab_09_webhook_ocp4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/lab_09_webhook_ocp4.png
--------------------------------------------------------------------------------
/images/openshift-pipeline-jenkins-view-run.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/openshift-pipeline-jenkins-view-run.png
--------------------------------------------------------------------------------
/images/openshift-pipeline-rollout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/openshift-pipeline-rollout.png
--------------------------------------------------------------------------------
/images/openshift-pipeline-run.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/openshift-pipeline-run.png
--------------------------------------------------------------------------------
/images/openshift-pipeline-start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/openshift-pipeline-start.png
--------------------------------------------------------------------------------
/images/pipeline-jenkins-custom-podtemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/pipeline-jenkins-custom-podtemplate.png
--------------------------------------------------------------------------------
/images/pipeline-jenkins-overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appuio/techlab/ef30104c85d86b8d23516235b46b767da0ebbe61/images/pipeline-jenkins-overview.png
--------------------------------------------------------------------------------
/labs/01_quicktour.md:
--------------------------------------------------------------------------------
1 | # Lab 1: Quicktour durch OpenShift
2 |
3 | In diesem Lab werden die Grundkonzepte von OpenShift vorgestellt. Des Weiteren zeigen wir auf, wie man sich in der Web Console einloggt und stellen die einzelnen Bereiche kurz vor.
4 |
5 | Die hier aufgeführten Begriffe und Ressourcen sind ein Auszug [dieses Red Hat Blogposts](https://developers.redhat.com/blog/2018/02/22/container-terminology-practical-introduction/), dem auch weiterführende Informationen zu Begriffen rund um Container entnommen werden können.
6 |
7 |
8 | ## Grundkonzepte
9 |
10 | OpenShift basiert auf modernen Konzepten wie CRI-O oder Kubernetes und bietet damit eine Plattform, mit der Software in Containern gebaut, deployt und betrieben werden kann.
11 |
12 |
13 | ### Container Engine
14 |
15 | [cri-o](https://cri-o.io/) ist eine leichtgewichtige Container Engine, welche Container Images in einen laufenden Prozess umwandelt, also in einen Container. Dies geschieht anhand der [Container Runtime Specification](https://github.com/opencontainers/runtime-spec) der [Open Container Initiative](https://www.opencontainers.org/), welche auch die [Image Specification](https://github.com/opencontainers/image-spec) festgelegt hat. Sämtliche OCI-konformen Images können so mit OCI-konformen Engines ausgeführt werden.
16 |
17 |
18 | ### Kubernetes
19 |
20 | [Kubernetes](http://kubernetes.io/) ist ein Container Orchestration Tool, welches das Verwalten von Containern wesentlich vereinfacht. Der Orchestrator terminiert dynamisch den Container Workload innerhalb eines Clusters.
21 |
22 |
23 | ### Container und Container Images
24 |
25 | Die Basiselemente von OpenShift Applikationen sind Container. Ein Container ist ein isolierter Prozess auf einem Linuxsystem mit eingeschränkten Ressourcen, der nur mit definierten Prozessen interagieren kann.
26 |
27 | Container basieren auf Container Images. Ein Container wird gestartet, indem die Container Engine die Dateien und Metadaten des Container Images entpackt und dem Linux Kernel übergibt.
28 |
29 | Container Images werden bspw. anhand von Dockerfiles (textueller Beschrieb, wie das Container Image Schritt für Schritt aufgebaut ist) gebaut. Grundsätzlich sind Container Images hierarchisch angewendete Filesystem Snapshots.
30 |
31 | Beispiel Tomcat:
32 |
33 | - Base Image (z.B. [UBI](https://www.redhat.com/en/blog/introducing-red-hat-universal-base-image))
34 | - \+ Java
35 | - \+ Tomcat
36 | - \+ App
37 |
38 | Gebaute Container Images werden in einer Image Registry (analog einem Repository für bspw. RPM-Pakete) versioniert abgelegt und können von da bezogen werden, um sie auf einer Container Plattform zu deployen.
39 | Container Images können auch auf OpenShift selbst gebaut werden, von wo aus sie in die OpenShift-interne Registry gepusht und für das Deployment wieder gepullt werden.
40 |
41 |
42 | ## OpenShift-Konzepte
43 | ### Projekte
44 |
45 | In OpenShift werden Ressourcen (Container und Container Images, Pods, Services, Routen, Konfiguration, Quotas und Limiten etc.) in Projekten strukturiert. Aus technischer Sicht entspricht ein Projekt einem Kubernetes Namespace und erweitert diesen um gewisse Konzepte.
46 |
47 | Innerhalb eines Projekts können berechtigte User ihre Ressourcen selber verwalten und organisieren.
48 |
49 | Die Ressourcen innerhalb eines Projektes sind über ein transparentes [SDN](https://de.wikipedia.org/wiki/Software-defined_networking) bzw. Overlay-Netzwerk verbunden. So können die einzelnen Komponenten eines Projektes in einem Multi-Node Setup auf verschiedene Nodes deployed werden. Dabei sind sie über das SDN untereinander sicht- und zugreifbar.
50 |
51 |
52 | ### Pods
53 |
54 | OpenShift übernimmt das Konzept der Pods von Kubernetes.
55 |
56 | Ein Pod ist ein oder mehrere Container, die zusammen auf den gleichen Host deployed werden. Ein Pod ist die kleinste verwaltbare Einheit in OpenShift.
57 |
58 | Ein Pod ist innerhalb eines OpenShift Projekts u.a. über den entsprechenden Service verfügbar.
59 |
60 |
61 | ### Services
62 |
63 | Ein Service repräsentiert einen internen Loadbalancer auf die dahinterliegenden Pods (Replicas vom gleichen Typ). Der Service dient als Proxy zu den Pods und leitet Anfragen an diese weiter. So können Pods willkürlich einem Service hinzugefügt und entfernt werden, während der Service verfügbar bleibt.
64 |
65 | Einem Service ist innerhalb eines Projektes eine IP und ein Port zugewiesen.
66 |
67 |
68 | ### Routes
69 |
70 | Mit einer Route definiert man in OpenShift, wie ein Service von ausserhalb von OpenShift von externen Clients erreicht werden kann.
71 |
72 | Diese Routes werden im integrierten Routing Layer eingetragen und erlauben dann der Plattform über ein Hostname-Mapping die Requests an den entsprechenden Service weiterzuleiten.
73 |
74 | Sind mehr als ein Pod für einen Service deployt, verteilt der Routing Layer die Requests auf die deployten Pods.
75 |
76 | Aktuell werden folgende Protokolle unterstützt:
77 |
78 | - HTTP
79 | - HTTPS ([SNI](https://en.wikipedia.org/wiki/Server_Name_Indication))
80 | - WebSockets
81 | - TLS-verschlüsselte Protokolle mit [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication)
82 |
83 |
84 | ### Templates
85 |
86 | Ein Template beschreibt textuell eine Liste von Ressourcen, die auf OpenShift ausgeführt und entsprechend in OpenShift erstellt werden können.
87 |
88 | So hat man die Möglichkeit ganze Infrastrukturen zu beschreiben:
89 |
90 | - Java Application Service (3 Replicas, Rolling Upgrade)
91 | - Datenbank Service
92 | - Im Internet über Route java.app.appuio-beta.ch erreichbar
93 | - ...
94 |
95 | ---
96 |
97 | __Ende Lab 1__
98 |
99 | OpenShift CLI installieren →
100 |
101 | [← zurück zur Übersicht](../README.md)
102 |
--------------------------------------------------------------------------------
/labs/02_cli.md:
--------------------------------------------------------------------------------
1 | # Lab 2: OpenShift CLI installieren
2 |
3 | In diesem Lab werden wir gemeinsam das CLI-Tool `odo` installieren und konfigurieren, damit wir danach die ersten Schritte auf der OpenShift Techlab Plattform durchführen können.
4 |
5 | ## `oc`
6 |
7 | Der __oc client__ stellt ein Interface zu OpenShift bereit.
8 |
9 | ### Installation
10 |
11 | Gemäss [offizieller Dokumentation](https://docs.openshift.com/container-platform/latest/cli_reference/openshift_cli/getting-started-cli.html#cli-installing-cli_cli-developer-commands) kann der __oc client__ von der __Infrastructure Provider__ Seite heruntergeladen werden, oder einfacher gleich direkt von folgender URL:
12 |
13 | __Tipp__:
14 | Alternativ kann die Binary auch mittels folgenden Befehlen im Terminal installiert werden:
15 |
16 | ```bash
17 | curl -fsSL https://mirror.openshift.com/pub/openshift-v4/clients/oc/latest/linux/oc.tar.gz | sudo tar xfz - -C /usr/bin
18 | ```
19 |
20 | ### bash Command Completion (optional)
21 |
22 | Dieser Schritt ist optional und funktioniert nicht auf Windows. Damit Command Completion auf macOS funktioniert, muss bspw. via `brew` das Paket `bash-completion` installiert werden.
23 |
24 | `oc` bietet eine Command Completion, die gem. [Dokumention](https://docs.openshift.com/container-platform/latest/cli_reference/openshift_cli/configuring-cli.html#cli-enabling-tab-completion_cli-configuring-cli) eingerichtet werden kann.
25 |
26 | __Tipp__:
27 | Alternativ kann die Bash Command Completion auch mittels folgenden Befehlen im Terminal installiert werden:
28 |
29 | ```bash
30 | oc completion bash | sudo tee /etc/bash_completion.d/oc_bash_completion
31 | ```
32 |
33 | __Ende Lab 2__
34 |
35 | Erste Schritte auf der Lab Plattform →
36 |
37 | [← zurück zur Übersicht](../README.md)
38 |
--------------------------------------------------------------------------------
/labs/03_first_steps.md:
--------------------------------------------------------------------------------
1 | # Lab 3: Erste Schritte auf der Lab Plattform
2 |
3 | In diesem Lab werden wir gemeinsam das erste Mal mit der Lab Plattform interagieren, dies sowohl über den `oc` Client wie auch über die Web Console.
4 |
5 |
6 | ## Login
7 |
8 | __Note__:
9 | Vergewissern Sie sich, dass Sie [Lab 2](02_cli.md) erfolgreich abgeschlossen haben, d.h. erfolgreich auf der Web Console einloggen sowie den `oc` Client installieren konnten.
10 |
11 | ### Befehl kopieren via Web Console
12 |
13 | Der Befehl für das Login mit `oc` kann komfortabel via Web Console geholt werden.
14 | Dazu oben rechts auf den eigenen Username und anschliessend auf _Copy Login Command_ klicken:
15 |
16 | 
17 |
18 | Nun kann der Befehl wie er unter "Log in with this token" dargestellt wird kopiert und in einem Terminal-Fenster eingefügt werden.
19 |
20 | ### Login direkt mit `oc`
21 |
22 | Als Alternative zum Kopieren des Befehls kann direkt mit `oc` eingeloggt werden:
23 |
24 | ```bash
25 | oc login FIXME: URL
26 | ```
27 |
28 |
29 | ## OpenShift Projekte
30 |
31 | Ein Projekt in OpenShift ist das Top-Level Konzept um Ihre Ressourcen wie Deployments, Builds, Container Images etc. zu organisieren.
32 | Für das Projekt berechtigte User können diese Ressourcen verwalten.
33 | Innerhalb eines OpenShift Clusters muss der Name eines Projektes eindeutig sein.
34 | Siehe auch [Lab 1](01_quicktour.md).
35 |
36 |
37 | ## Aufgabe 1: Neues Projekt erstellen
38 |
39 | Erstellen Sie auf der Lab Plattform ein neues Projekt mit Namen `[USERNAME]-example1`.
40 |
41 | Um herauszufinden, wie Sie ein neues Projekt mit `oc` erstellen, können Sie folgenden Befehl verwenden:
42 |
43 | ```bash
44 | oc help
45 | ```
46 |
47 | Tipp
oc new-project [USERNAME]-example1
48 |
49 |
50 | ## Web Console
51 |
52 | Die OpenShift Web Console erlaubt es den Benutzern gewisse Tasks direkt via Browser vorzunehmen.
53 |
54 |
55 | ## Aufgabe 2: Applikation erstellen
56 |
57 | 1. Gehen Sie in die Übersicht Ihres eben erstellten Projektes. Aktuell ist das Projekt noch leer.
58 |
59 | 1. Fügen Sie Ihre erste Applikation Ihrem Projekt hinzu. Als Beispielprojekt verwenden wir ein APPUiO Example:
60 |
61 | 1. Wechseln Sie zuerst von der Administrator- in die Developer-Ansicht oben links
62 |
63 | 1. Stellen Sie sicher, dass bei "Project" Ihr neu erstelltes Projekt selektiert ist.
64 |
65 | 1. Wählen Sie nun unten links unter "Developer Catalog" den Punkt "All services"
66 |
67 | 1. Schränken Sie die Auswahl über einen Klick auf _Languages_ und anschliessend _PHP_ ein
68 |
69 | 1. Wählen Sie nun das Feld "PHP" aus und klicken auf "Create Application"
70 |
71 | 1. Füllen Sie das Feld "Git Repo URL" mit folgender URL
72 |
73 | ```
74 | https://github.com/appuio/example-php-sti-helloworld.git
75 | ```
76 |
77 | 1. Belassen Sie die restlichen Felder leer oder auf deren Standardwert und klicken auf _Create_
78 |
79 | Sie haben soeben Ihre erste Applikation mittels sog. __[Source to Image](https://docs.openshift.com/container-platform/latest/cicd/builds/build-strategies.html#builds-strategy-s2i-build_build-strategies)__ Build auf OpenShift deployed.
80 |
81 | __Tipp__:
82 | Mit den folgenden Befehlen kann das obere Beispiel auf der Kommandozeile erstellt werden:
83 |
84 | ```bash
85 | oc new-app https://github.com/appuio/example-php-sti-helloworld.git
86 | oc expose svc example-php-sti-helloworld
87 | ```
88 |
89 | __Note__:
90 | Der `oc new-app`-Befehl benötigt `git`.
91 | Falls `git` nicht installiert ist, insb. auf Windows, kann das Tool [hier heruntergeladen](https://git-scm.com/download/win) und installiert werden.
92 |
93 | __Tipp__:
94 | Eine so erstellte Applikation mitsamt den zusätzlich angelegten Ressourcen kann mithilfe von Labels auf einen Schlag gelöscht werden, bspw. mit folgendem Befehl:
95 |
96 | ```bash
97 | oc delete all --selector app=example-php-sti-helloworld-git
98 | ```
99 |
100 | Um die Labels der verschiedenen Ressourcen anzuzeigen kann folgender Befehl verwendet werden:
101 |
102 | ```bash
103 | oc get all --show-labels
104 | ```
105 |
106 | ---
107 |
108 | __Ende Lab 3__
109 |
110 | Ein Container Image deployen →
111 |
112 | [← zurück zur Übersicht](../README.md)
113 |
--------------------------------------------------------------------------------
/labs/04_deploy_dockerimage.md:
--------------------------------------------------------------------------------
1 | # Lab 4: Ein Container Image deployen
2 |
3 | In diesem Lab werden wir gemeinsam das erste "pre-built" Container Image deployen und die OpenShift-Konzepte Pod, Service, DeploymentConfig und ImageStream etwas genauer anschauen.
4 |
5 | ## Aufgabe 1: Container Image deployen
6 |
7 | Nachdem wir im [Lab 3](03_first_steps.md) den Source-to-Image Workflow verwendet haben, um eine Applikation auf OpenShift zu deployen, wenden wir uns nun dem Deployment eines pre-built Container Image von Docker Hub (oder einer anderen Image Registry) zu.
8 |
9 | Erstellen Sie hierfür wieder ein neues Projekt mit dem Namen `[USERNAME]-dockerimage`.
10 |
11 | Tipp
oc new-project [USERNAME]-dockerimage
12 |
13 | `oc new-project` wechselt automatisch in das neu angelegte Projekt. Mit dem `oc project` Befehl kann das Projekt gewechselt werden.
14 |
15 | Verwenden Sie
16 |
17 | ```bash
18 | oc get projects
19 | ```
20 |
21 | um alle Projekte anzuzeigen, auf die Sie berechtigt sind.
22 |
23 | Sobald das neue Projekt erstellt wurde, können wir in OpenShift mit dem folgenden Befehl das Container Image deployen:
24 |
25 | ```bash
26 | oc new-app quay.io/appuio/example-spring-boot --as-deployment-config
27 | ```
28 |
29 | Für unser Lab verwenden wir ein APPUiO-Beispiel (Java Spring Boot Applikation):
30 |
31 | - GitHub (Source):
32 | - Quay.io:
33 |
34 | Beim Ausführen obigen Befehls legt OpenShift die nötigen Ressourcen an, lädt das Container Image (in diesem Fall von Docker Hub) herunter und deployt anschliessend den Pod.
35 |
36 | __Tipp__: Verwenden Sie `oc status` um sich einen Überblick über das Projekt zu verschaffen.
37 |
38 | Oder verwenden Sie den `oc get` Befehl mit dem `-w` Parameter, um fortlaufend Änderungen an den Ressourcen des Typs Pod anzuzeigen (abbrechen mit ctrl+c):
39 |
40 | ```bash
41 | oc get pods -w
42 | ```
43 |
44 | Je nach Internetverbindung oder abhängig davon, ob das Image auf Ihrem OpenShift Node bereits heruntergeladen wurde, kann das eine Weile dauern.
45 | In der Zwischenzeit können Sie sich in der Web Console den aktuellen Status des Deployments anschauen:
46 |
47 | 1. Loggen Sie sich in der Web Console ein
48 | 1. Wechseln Sie von der Administrator- in die Developer-Ansicht (oben links)
49 | 1. Wählen Sie Ihr Projekt `[USERNAME]-dockerimage` aus
50 | 1. Klicken Sie auf Topology
51 |
52 | __Tipp__:
53 | Um Ihre eigenen Container Images für OpenShift zu erstellen, sollten Sie die folgenden Best Practices befolgen:
54 |
55 |
56 | ## Betrachten der erstellten Ressourcen
57 |
58 | Als wir vorhin `oc new-app quay.io/appuio/example-spring-boot` ausführten, hat OpenShift im Hintergrund einige Ressourcen für uns angelegt.
59 | Diese werden dafür benötigt, das Container Image zu deployen:
60 |
61 | - Service
62 | - [ImageStream](https://docs.openshift.com/container-platform/latest/openshift_images/index.html#about-containers-images-and-image-streams)
63 | - [DeploymentConfig](https://docs.openshift.com/container-platform/latest/applications/deployments/what-deployments-are.html)
64 |
65 | ### Service
66 |
67 | Services dienen innerhalb OpenShift als Abstraktionslayer, Einstiegspunkt und Proxy/Loadbalancer auf die dahinterliegenden Pods.
68 | Der Service ermöglicht es, innerhalb OpenShift eine Gruppe von Pods des gleichen Typs zu finden und anzusprechen.
69 |
70 | Als Beispiel: Wenn eine Applikationsinstanz unseres Beispiels die Last nicht mehr alleine verarbeiten kann, können wir die Applikation bspw. auf drei Pods hochskalieren.
71 | OpenShift mapt diese als Endpoints automatisch zum Service.
72 | Sobald die Pods bereit sind, werden Requests automatisch auf alle drei Pods verteilt.
73 |
74 | __Note__: Die Applikation kann aktuell von aussen noch nicht erreicht werden, der Service ist ein OpenShift-internes Konzept.
75 | Im folgenden Lab werden wir die Applikation öffentlich verfügbar machen.
76 |
77 | Nun schauen wir uns unseren Service mal etwas genauer an:
78 |
79 | ```bash
80 | oc get services
81 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
82 | example-spring-boot ClusterIP 172.30.141.7 8080/TCP,8778/TCP,9779/TCP 3m
83 | ```
84 |
85 | Wie Sie am Output sehen, ist unser Service `example-spring-boot` über eine IP-Adresse und mehrere Ports erreichbar (z.B. 172.30.141.7:8080).
86 |
87 | __Note__:
88 | Ihre IP-Adresse wird mit grosser Wahrscheinlichkeit von der hier gezeigten abweichen.
89 | Diese IP-Adresse ist ausserdem OpenShift-intern und kann von ausserhalb nicht erreicht werden.
90 |
91 | __Note__: Service IPs bleiben während ihrer Lebensdauer immer gleich.
92 |
93 | Mit dem folgenden Befehl können Sie zusätzliche Informationen über den Service auslesen:
94 |
95 | ```bash
96 | oc get service example-spring-boot -o json
97 | {
98 | "apiVersion": "v1",
99 | "kind": "Service",
100 | "metadata": {
101 | "annotations": {
102 | "openshift.io/generated-by": "OpenShiftNewApp"
103 | },
104 | "creationTimestamp": "2020-01-09T08:21:13Z",
105 | "labels": {
106 | "app": "example-spring-boot"
107 | },
108 | "name": "example-spring-boot",
109 | "namespace": "techlab",
110 | "resourceVersion": "39162349",
111 | "selfLink": "/api/v1/namespaces/techlab/services/example-spring-boot",
112 | "uid": "ff9bc391-32b8-11ea-b825-fa163e286250"
113 | },
114 | "spec": {
115 | "clusterIP": "172.30.9.146",
116 | "ports": [
117 | {
118 | "name": "8080-tcp",
119 | "port": 8080,
120 | "protocol": "TCP",
121 | "targetPort": 8080
122 | },
123 | {
124 | "name": "8778-tcp",
125 | "port": 8778,
126 | "protocol": "TCP",
127 | "targetPort": 8778
128 | },
129 | {
130 | "name": "9000-tcp",
131 | "port": 9000,
132 | "protocol": "TCP",
133 | "targetPort": 9000
134 | },
135 | {
136 | "name": "9779-tcp",
137 | "port": 9779,
138 | "protocol": "TCP",
139 | "targetPort": 9779
140 | }
141 | ],
142 | "selector": {
143 | "app": "example-spring-boot",
144 | "deploymentconfig": "example-spring-boot"
145 | },
146 | "sessionAffinity": "None",
147 | "type": "ClusterIP"
148 | },
149 | "status": {
150 | "loadBalancer": {}
151 | }
152 | }
153 | ```
154 |
155 | __Tipp__:
156 | Der `-o` Parameter akzeptiert auch `yaml` als Angabe.
157 |
158 | Mit dem folgenden Befehl können Sie auch die Details zu einem Pod anzeigen:
159 |
160 | ```bash
161 | oc get pod example-spring-boot-3-nwzku -o json
162 | ```
163 |
164 | __Note__:
165 | Fragen Sie zuerst den Pod Namen aus Ihrem Projekt mit `oc get pods` ab und ersetzen ihn dann im obigen Befehl.
166 |
167 | Über den `selector` im Service wird definiert, welche Pods (`labels`) als Endpoints dienen.
168 | Dazu können die entsprechenden Konfigurationen von Service und Pod zusammen betrachtet werden.
169 |
170 | Service (`oc get service `):
171 |
172 | ```json
173 | ...
174 | "selector": {
175 | "app": "example-spring-boot",
176 | "deploymentconfig": "example-spring-boot"
177 | },
178 |
179 | ...
180 | ```
181 |
182 | Pod (`oc get pod `):
183 |
184 | ```json
185 | ...
186 | "labels": {
187 | "app": "example-spring-boot",
188 | "deployment": "example-spring-boot-1",
189 | "deploymentconfig": "example-spring-boot"
190 | },
191 | ...
192 | ```
193 |
194 | Diese Verknüpfung ist besser mittels `oc describe` Befehl zu sehen:
195 |
196 | ```bash
197 | $ oc describe service example-spring-boot
198 | Name: example-spring-boot
199 | Namespace: techlab
200 | Labels: app=example-spring-boot
201 | Annotations: openshift.io/generated-by=OpenShiftNewApp
202 | Selector: app=example-spring-boot,deploymentconfig=example-spring-boot
203 | Type: ClusterIP
204 | IP: 172.30.9.146
205 | Port: 8080-tcp 8080/TCP
206 | TargetPort: 8080/TCP
207 | Endpoints: 10.128.2.203:8080
208 | Port: 8778-tcp 8778/TCP
209 | TargetPort: 8778/TCP
210 | Endpoints: 10.128.2.203:8778
211 | Port: 9000-tcp 9000/TCP
212 | TargetPort: 9000/TCP
213 | Endpoints: 10.128.2.203:9000
214 | Port: 9779-tcp 9779/TCP
215 | TargetPort: 9779/TCP
216 | Endpoints: 10.128.2.203:9779
217 | Session Affinity: None
218 | Events:
219 | ```
220 |
221 | Unter Endpoints finden Sie nun den aktuell laufenden Pod.
222 |
223 |
224 | ### ImageStream
225 |
226 | [ImageStreams](https://docs.openshift.com/container-platform/latest/openshift_images/image-streams-manage.html) werden dafür verwendet, automatische Tasks auszuführen wie bspw. ein Deployment zu aktualisieren, wenn eine neue Version des Image verfügbar ist.
227 |
228 | Builds und Deployments können ImageStreams beobachten und auf Änderungen reagieren.
229 | In unserem Beispiel wird der Image Stream dafür verwendet, ein Deployment zu triggern, sobald etwas am Image geändert hat.
230 |
231 | Mit dem folgenden Befehl können Sie zusätzliche Informationen über den ImageStream auslesen:
232 |
233 | ```bash
234 | oc get imagestream example-spring-boot -o json
235 | ```
236 |
237 |
238 | ### DeploymentConfig
239 |
240 | In der [DeploymentConfig](https://docs.openshift.com/container-platform/latest/applications/deployments/what-deployments-are.html) werden folgende Punkte definiert:
241 |
242 | - Update Strategy: Wie werden Applikationsupdates ausgeführt, wie erfolgt das Austauschen der Container?
243 | - Triggers: Welche Ereignisse führen zu einem automatischen Deployment?
244 | - Container:
245 | - Welches Image soll verwendet werden?
246 | - Environment Configuration
247 | - ImagePullPolicy
248 | - Replicas: Anzahl der Pods, die deployt werden sollen
249 |
250 | Mit dem folgenden Befehl können zusätzliche Informationen zur DeploymentConfig ausgelesen werden:
251 |
252 | ```bash
253 | oc get deploymentConfig example-spring-boot -o json
254 | ```
255 |
256 | Im Gegensatz zur DeploymentConfig, mit welcher man OpenShift sagt, wie eine Applikation deployt werden soll, definiert man mit dem ReplicationController, wie die Applikation während der Laufzeit aussehen soll (bspw. dass immer 3 Replicas laufen sollen).
257 |
258 | __Tipp__:
259 | Für viele der Resource Types gibt es auch eine Kurzform. So können Sie bspw. anstelle von `oc get deploymentconfig` auch einfach `oc get dc` schreiben, oder `svc` anstelle von `service`.
260 |
261 | ---
262 |
263 | ## Zusatzaufgabe für Schnelle ;-)
264 |
265 | Schauen Sie sich die erstellten Ressourcen mit `oc get [ResourceType] [Name] -o json` und `oc describe [ResourceType] [Name]` aus dem ersten Projekt `[USERNAME]-example1` an. Alternativ kann das Projekt `openshift-web-console` verwendet werden.
266 |
267 | ---
268 |
269 | __Ende Lab 4__
270 |
271 | Routen erstellen →
272 |
273 | [← zurück zur Übersicht](../README.md)
274 |
--------------------------------------------------------------------------------
/labs/05_create_route.md:
--------------------------------------------------------------------------------
1 | # Lab 5: Routen erstellen
2 |
3 | In diesem Lab werden wir die Applikation aus [Lab 4](04_deploy_dockerimage.md) über das HTTP-Protokoll vom Internet her erreichbar machen.
4 |
5 |
6 | ## Routen
7 |
8 | Der `oc new-app` Befehl aus dem vorherigen [Lab](04_deploy_dockerimage.md) erstellt keine Route.
9 | Somit ist unser Service von _aussen_ her gar nicht erreichbar.
10 | Will man einen Service verfügbar machen, muss dafür eine Route eingerichtet werden.
11 | Der OpenShift Router erkennt aufgrund des Host Headers, auf welchen Service ein Request geleitet werden muss.
12 |
13 | Aktuell werden folgende Protokolle unterstützt:
14 |
15 | - HTTP
16 | - HTTPS mit [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication)
17 | - TLS mit [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication)
18 | - WebSockets
19 |
20 |
21 | ## Aufgabe 1: Route erstellen
22 |
23 | Vergewissern Sie sich, dass Sie sich im Projekt `[USERNAME]-dockerimage` befinden.
24 |
25 | Tipp
oc project [USERNAME]-dockerimage
26 |
27 | Erstellen Sie für den Service `example-spring-boot` eine Route und machen Sie ihn darüber öffentlich verfügbar.
28 |
29 | __Tipp__:
30 | Mittels `oc get routes` können Sie sich die Routen eines Projekts anzeigen lassen.
31 |
32 | ```bash
33 | oc get routes
34 | No resources found.
35 | ```
36 |
37 | Aktuell gibt es noch keine Route. Jetzt brauchen wir den Servicenamen:
38 |
39 | ```bash
40 | oc get services
41 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
42 | example-spring-boot ClusterIP 172.30.9.146 8080/TCP,8778/TCP,9000/TCP,9779/TCP 16m
43 | ```
44 |
45 | Und nun wollen wir diesen Service veröffentlichen bzw. exponieren:
46 |
47 | ```bash
48 | oc expose service example-spring-boot
49 | ```
50 |
51 | Mit diesem Befehl wird eine unverschlüsselte Route erstellt, also via HTTP erreichbar.
52 | Um eine verschlüsselte Route zu erstellen schreiben wir folgendes:
53 |
54 | ```bash
55 | oc create route edge example-spring-boot-secure --service=example-spring-boot
56 | ```
57 |
58 | Mittels `oc get routes` können wir überprüfen, ob die Routen angelegt wurden.
59 |
60 | ```bash
61 | oc get routes
62 | NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD
63 | example-spring-boot example-spring-boot-techlab.mycluster.com example-spring-boot 8080-tcp None
64 | example-spring-boot-secure example-spring-boot-secure-techlab.mycluster.com example-spring-boot 8080-tcp edge None
65 | ```
66 |
67 | Die Applikation ist nun vom Internet her über die angegebenen URLs erreichbar, Sie können also nun auf die Applikation zugreifen.
68 |
69 | __Tipp__:
70 | Wird mit `oc expose` oder `oc create route` kein expliziter Hostname angegeben, wird _servicename-project.applicationdomain_ verwendet.
71 |
72 | In der Übersicht der Web Console ist diese Route mit dem Hostname jetzt auch sichtbar (das Symbol oben rechts am blauen Ring).
73 |
74 | Öffnen Sie die Applikation im Browser und fügen ein paar "Say Hello" Einträge ein.
75 |
76 | ---
77 |
78 | __Ende Lab 5__
79 |
80 | Skalieren →
81 |
82 | [← zurück zur Übersicht](../README.md)
83 |
--------------------------------------------------------------------------------
/labs/06_scale.md:
--------------------------------------------------------------------------------
1 | # Lab 6: Pod Scaling, Readiness Probe und Self Healing
2 |
3 | In diesem Lab zeigen wir auf, wie man Applikationen in OpenShift skaliert.
4 | Des Weiteren zeigen wir, wie OpenShift dafür sorgt, dass jeweils die Anzahl erwarteter Pods gestartet wird und wie eine Applikation der Plattform zurückmelden kann, dass sie bereit für Requests ist.
5 |
6 | ## Aufgabe 1: Beispiel-Applikation hochskalieren
7 |
8 | Dafür erstellen wir ein neues Projekt mit dem Namen `[USERNAME]-scale`.
9 |
10 | Tipp
oc new-project [USERNAME]-scale
11 |
12 | Fügen Sie dem Projekt eine Applikation hinzu:
13 |
14 | ```bash
15 | oc new-app appuio/example-php-docker-helloworld --name=appuio-php-docker --as-deployment-config
16 | ```
17 |
18 | Und stellen den Service `appuio-php-docker` zur Verfügung (expose).
19 |
20 | Tipp
oc expose service appuio-php-docker
21 |
22 | Wenn wir unsere Beispiel-Applikation skalieren wollen, müssen wir unserem ReplicationController (rc) mitteilen, dass wir bspw. stets 3 Replicas des Image am laufen haben wollen.
23 |
24 | Schauen wir uns mal den ReplicationController (rc) etwas genauer an:
25 |
26 | ```bash
27 | oc get rc
28 | NAME DESIRED CURRENT AGE
29 | appuio-php-docker-1 1 1 33s
30 | ```
31 |
32 | Für mehr Details json- oder yaml-Output ausgeben lassen.
33 |
34 | Tipp
oc get rc appuio-php-docker-1 -o json
oc get rc appuio-php-docker-1 -o yaml
35 |
36 | Der rc sagt uns, wieviele Pods wir erwarten (spec) und wieviele aktuell deployt sind (status).
37 |
38 |
39 | ## Aufgabe 2: Skalieren unserer Beispiel Applikation
40 |
41 | Nun skalieren wir unsere Beispiel-Applikation auf 3 Replicas.
42 | Der soeben betrachtete ReplicationController wird über die DeploymentConfig (dc) gesteuert, weshalb wir diese skalieren müssen, damit die gewünschte Anzahl Repclias vom rc übernommen wird:
43 |
44 | ```bash
45 | oc scale --replicas=3 dc/appuio-php-docker
46 | ```
47 |
48 | Überprüfen wir die Anzahl Replicas auf dem ReplicationController:
49 |
50 | ```bash
51 | oc get rc
52 | NAME DESIRED CURRENT AGE
53 | appuio-php-docker-1 3 3 1m
54 | ```
55 |
56 | und zeigen die Pods an:
57 |
58 | ```bash
59 | oc get pods
60 | NAME READY STATUS RESTARTS AGE
61 | appuio-php-docker-1-2uc89 1/1 Running 0 21s
62 | appuio-php-docker-1-evcre 1/1 Running 0 21s
63 | appuio-php-docker-1-tolpx 1/1 Running 0 2m
64 | ```
65 |
66 | Zum Schluss schauen wir uns den Service an. Der sollte jetzt alle drei Endpoints referenzieren:
67 |
68 | ```bash
69 | $ oc describe svc appuio-php-docker
70 | Name: appuio-php-docker
71 | Namespace: techlab-scale
72 | Labels: app=appuio-php-docker
73 | Annotations: openshift.io/generated-by=OpenShiftNewApp
74 | Selector: app=appuio-php-docker,deploymentconfig=appuio-php-docker
75 | Type: ClusterIP
76 | IP: 172.30.152.213
77 | Port: 8080-tcp 8080/TCP
78 | TargetPort: 8080/TCP
79 | Endpoints: 10.128.2.204:8080,10.129.1.56:8080,10.131.0.141:8080
80 | Port: 8443-tcp 8443/TCP
81 | TargetPort: 8443/TCP
82 | Endpoints: 10.128.2.204:8443,10.129.1.56:8443,10.131.0.141:8443
83 | Session Affinity: None
84 | Events:
85 | ```
86 |
87 | Skalieren von Pods innerhalb eines Service ist sehr schnell, da OpenShift einfach eine neue Instanz des Container Images als Container startet.
88 |
89 | __Tipp__:
90 | OpenShift unterstützt auch [Autoscaling](https://docs.openshift.com/container-platform/latest/nodes/pods/nodes-pods-autoscaling.html).
91 |
92 |
93 | ## Aufgabe 3: Skalierte App in der Web Console
94 |
95 | Schauen Sie sich die skalierte Applikation auch in der Web Console an.
96 | Wie können Sie die Anzahl Replicas via Web Console steuern?
97 |
98 |
99 | ## Unterbruchsfreies Skalieren überprüfen
100 |
101 | Mit dem folgenden Befehl können Sie nun überprüfen, ob Ihr Service verfügbar ist, während Sie hoch- und herunterskalieren.
102 | Führen Sie folgenden Befehl in einem Terminal-Fenster aus und lassen ihn laufen, während Sie später skalieren.
103 |
104 | Ersetzen Sie `[HOSTNAME]` mit dem Hostname Ihrer definierten Route:
105 |
106 | __Tipp__:
107 | Um den entsprechenden Hostname anzuzeigen, kann folgender Befehl verwendet werden:
108 |
109 | `oc get route -o custom-columns=NAME:.metadata.name,HOSTNAME:.spec.host`
110 |
111 | ```bash
112 | while true; do sleep 1; ( { curl -fs http://[HOSTNAME]/health/; date "+ TIME: %H:%M:%S,%3N" ;} & ) 2>/dev/null; done
113 | ```
114 |
115 | oder in PowerShell (__Achtung__: erst ab PowerShell-Version 3.0!):
116 |
117 | ```bash
118 | while(1) {
119 | Start-Sleep -s 1
120 | Invoke-RestMethod http://[HOSTNAME]/pod/
121 | Get-Date -Uformat "+ TIME: %H:%M:%S,%3N"
122 | }
123 | ```
124 |
125 | Der Output zeigt jeweils den Pod an, der den Request beantwortet hatte:
126 |
127 | ```bash
128 | POD: appuio-php-docker-6-9w9t4 TIME: 16:40:04,991
129 | POD: appuio-php-docker-6-9w9t4 TIME: 16:40:06,053
130 | POD: appuio-php-docker-6-6xg2b TIME: 16:40:07,091
131 | POD: appuio-php-docker-6-6xg2b TIME: 16:40:08,128
132 | POD: appuio-php-docker-6-ctbrs TIME: 16:40:09,175
133 | POD: appuio-php-docker-6-ctbrs TIME: 16:40:10,212
134 | POD: appuio-php-docker-6-9w9t4 TIME: 16:40:11,279
135 | POD: appuio-php-docker-6-9w9t4 TIME: 16:40:12,332
136 | POD: appuio-php-docker-6-6xg2b TIME: 16:40:13,369
137 | POD: appuio-php-docker-6-6xg2b TIME: 16:40:14,407
138 | POD: appuio-php-docker-6-6xg2b TIME: 16:40:15,441
139 | POD: appuio-php-docker-6-6xg2b TIME: 16:40:16,493
140 | POD: appuio-php-docker-6-6xg2b TIME: 16:40:17,543
141 | POD: appuio-php-docker-6-6xg2b TIME: 16:40:18,591
142 | ```
143 |
144 | Skalieren Sie nun von __3__ Replicas auf __1__ währenddem die While-Schleife läuft.
145 |
146 | Die Requests werden an die unterschiedlichen Pods aufgeteilt.
147 | Sobald die Pods herunterskaliert wurden, gibt nur noch einer Antwort.
148 |
149 | Was passiert nun, wenn wir während der noch immer laufenden While-Schleife ein neues Deployment starten?
150 | Testen wir es:
151 |
152 | ```bash
153 | oc rollout latest appuio-php-docker
154 | ```
155 |
156 | Wie der Timestamp am Ende der Ausgabe zeigt, gibt während einer kurzen Zeit die öffentliche Route keine Antwort:
157 |
158 | ```bash
159 | POD: appuio-php-docker-6-6xg2b TIME: 16:42:17,743
160 | POD: appuio-php-docker-6-6xg2b TIME: 16:42:18,776
161 | POD: appuio-php-docker-6-6xg2b TIME: 16:42:19,813
162 | POD: appuio-php-docker-6-6xg2b TIME: 16:42:20,853
163 | POD: appuio-php-docker-6-6xg2b TIME: 16:42:21,891
164 | POD: appuio-php-docker-6-6xg2b TIME: 16:42:22,943
165 | POD: appuio-php-docker-6-6xg2b TIME: 16:42:23,980
166 | #
167 | # keine Antwort
168 | #
169 | POD: appuio-php-docker-7-pxnr3 TIME: 16:42:42,134
170 | POD: appuio-php-docker-7-pxnr3 TIME: 16:42:43,181
171 | POD: appuio-php-docker-7-pxnr3 TIME: 16:42:44,226
172 | POD: appuio-php-docker-7-pxnr3 TIME: 16:42:45,259
173 | POD: appuio-php-docker-7-pxnr3 TIME: 16:42:46,297
174 | POD: appuio-php-docker-7-pxnr3 TIME: 16:42:47,571
175 | POD: appuio-php-docker-7-pxnr3 TIME: 16:42:48,606
176 | POD: appuio-php-docker-7-pxnr3 TIME: 16:42:49,645
177 | POD: appuio-php-docker-7-pxnr3 TIME: 16:42:50,684
178 | ```
179 |
180 | In unserem Beispiel verwenden wir einen sehr leichtgewichtigen Pod.
181 | Der Ausfall wäre ausgeprägter, wenn der Container länger bräuchte, bis er Requests abarbeiten kann, bspw. die Java Applikation von LAB 4 (__Startup: 30 Sekunden__).
182 |
183 | Es kann sogar passieren, dass der Service gar nicht mehr online ist und der Routing Layer als Response einen __503 Error__ zurück gibt.
184 |
185 | Im folgenden Kapitel wird beschrieben, wie Sie Ihre Services konfigurieren können, damit unterbruchsfreie Deployments möglich werden.
186 |
187 |
188 | ## Unterbruchsfreies Deployment dank Health Checks und Rolling Update
189 |
190 | Die "[Rolling Strategy](https://docs.openshift.com/container-platform/latest/applications/deployments/deployment-strategies.html#deployments-rolling-strategy_deployment-strategies)" ermöglicht unterbruchsfreie Deployments.
191 | Damit wird die neue Version der Applikation gestartet, sobald die Applikation bereit ist, werden Requests auf den neuen Pod geleitet und die alte Version entfernt.
192 |
193 | Zusätzlich kann mittels [Container Health Checks](https://docs.openshift.com/container-platform/latest/applications/application-health.html#application-health-configuring_application-health) die deployte Applikation der Plattform detailliertes Feedback über ihr aktuelles Befinden übermitteln.
194 |
195 | Grundsätzlich gibt es zwei Arten von Health Checks, die implementiert werden können:
196 |
197 | - Liveness Probe: Sagt aus, ob ein laufender Container immer noch sauber läuft
198 | - Readiness Probe: Gibt Feedback darüber, ob eine Applikation bereit ist, Requests zu empfangen
199 |
200 | Diese beiden Checks können als HTTP Check, Container Execution Check (Befehl oder z.B. Shell Script im Container) oder als TCP Socket Check implementiert werden.
201 |
202 | In unserem Beispiel soll die Applikation der Plattform sagen, ob sie bereit für Requests ist.
203 | Dafür verwenden wir die Readiness Probe. Unsere Beispielapplikation gibt unter dem Pfad `/health` einen Status Code 200 zurück, sobald die Applikation bereit ist.
204 |
205 | ```bash
206 | http://[route]/health/
207 | ```
208 |
209 |
210 | ## Aufgabe 4: Readiness Probe
211 |
212 | Fügen Sie die Readiness Probe mit folgendem Befehl in der DeploymentConfig (dc) hinzu:
213 |
214 | ```bash
215 | oc set probe dc/appuio-php-docker --readiness --get-url=http://:8080/health --initial-delay-seconds=10
216 | ```
217 |
218 | Ein Blick in die DeploymentConfig zeigt, dass nun folgender Eintrag unter `.spec.template.spec.containers` eingefügt wurde:
219 |
220 | ```yaml
221 | readinessProbe:
222 | failureThreshold: 3
223 | httpGet:
224 | path: /health
225 | port: 8080
226 | scheme: HTTP
227 | initialDelaySeconds: 10
228 | periodSeconds: 10
229 | successThreshold: 1
230 | timeoutSeconds: 1
231 | ```
232 |
233 | Verifizieren Sie während eines Deployments der Applikation, dass nun auch ein Update der Applikation unterbruchsfrei verläuft, indem Sie die bereits verwendete While-Schlaufe während des folgenden Update-Befehls beobachten:
234 |
235 | ```bash
236 | oc rollout latest appuio-php-docker
237 | ```
238 |
239 | Jetzt sollten die Antworten ohne Unterbruch vom neuen Pod kommen.
240 |
241 |
242 | ## Self Healing
243 |
244 | Über den Replication Controller haben wir nun der Plattform mitgeteilt, dass jeweils __n__ Replicas laufen sollen. Was passiert nun, wenn wir einen Pod löschen?
245 |
246 | Suchen Sie mittels `oc get pods` einen Pod im Status "running" aus, den Sie _killen_ können.
247 |
248 | Starten sie in einem eigenen Terminal den folgenden Befehl (anzeige der Änderungen an Pods)
249 |
250 | ```bash
251 | oc get pods -w
252 | ```
253 |
254 | Löschen Sie im anderen Terminal Pods mit folgendem Befehl:
255 |
256 | ```bash
257 | oc delete pods -l deploymentconfig=appuio-php-docker
258 | ```
259 |
260 | OpenShift sorgt dafür, dass wieder __n__ Replicas des genannten Pods laufen.
261 |
262 | In der Web Console ist gut zu beobachten, wie der Pod zuerst hellblau ist, bis die Readiness Probe meldet, dass die Applikation nun bereit ist.
263 |
264 | ---
265 |
266 | __Ende Lab 6__
267 |
268 | Operators →
269 |
270 | [← zurück zur Übersicht](../README.md)
271 |
--------------------------------------------------------------------------------
/labs/07_operators.md:
--------------------------------------------------------------------------------
1 | # Lab 7: Operators
2 |
3 | Operators sind eine Art und Weise wie man Kubernetes-native Applikationen paketieren, deployen und verwalten kann. Kubernetes-native Applikationen sind Applikationen, die einerseits in Kubernetes/OpenShift deployed sind und andererseits auch über das Kubernetes/OpenShift-API (kubectl/oc) verwaltet werden. Seit OpenShift 4 verwendet auch OpenShift selber eine Reihe von Operators um den OpenShift-Cluster, also sich selber, zu verwalten.
4 |
5 |
6 | ## Einführung / Begriffe
7 |
8 | Um zu verstehen, was ein Operator ist und wie er funktioniert, schauen wir zunächst den sogenannten Controller an, da Operators auf dessen Konzept basieren.
9 |
10 |
11 | ### Controller
12 |
13 | Ein Controller besteht aus einem Loop, in welchem immer wieder der gewünschte Zustand (_desired state_) und der aktuelle Zustand (_actual state/obseved state_) des Clusters gelesen werden. Wenn der aktuelle Zustand nicht dem gewünschten Zustand entspricht, versucht der Controller den gewünschten Zustand herzustellen. Der gewünschte Zustand wird mit Ressourcen (Deployments, ReplicaSets, Pods, Services, etc.) beschrieben.
14 |
15 | Die ganze Funktionsweise von OpenShift/Kubernetes basiert auf diesem Muster. Auf dem Master (controller-manager) laufen eine Vielzahl von Controllern, welche aufgrund von Ressourcen (ReplicaSets, Pods, Services, etc.) den gewünschten Zustand herstellen. Erstellt man z.B. ein ReplicaSet, sieht dies der ReplicaSet-Controller und erstellt als Folge die entsprechende Anzahl von Pods.
16 |
17 | __Optional__: Der Artikel [The Mechanics of Kubernetes](https://medium.com/@dominik.tornow/the-mechanics-of-kubernetes-ac8112eaa302) gibt einen tiefen Einblick in die Funktionsweise von Kubernetes. In der Grafik im Abschnitt _Cascading Commands_ wird schön aufgezeigt, dass vom Erstellen eines Deployments bis zum effektiven Starten der Pods vier verschiedene Controller involviert sind.
18 |
19 |
20 | ### Operator
21 |
22 | Ein Operator ist ein Controller, welcher dafür zuständig ist, eine Applikation zu installieren und zu verwalten. Ein Operator hat also applikations-spezifisches Wissen. Dies ist insbesondere bei komplexeren Applikationen nützlich, welche aus verschiedenen Komponenten bestehen oder zusätzlichen Administrationsaufwand erfordern (z.B. neu gestartete Pods müssen zu einem Applikations-Cluster hinzugefügt werden, etc.).
23 |
24 | Auch für den Operator muss der gewünschte Zustand durch eine Ressource abgebildet werden. Dazu gibt es sogenannte Custom Resource Definitions (CRD). Mit CRDs kann man in OpenShift/Kubernetes beliebige neue Ressourcen definieren. Der Operator schaut dann konstant (_watch_), ob Custom Resources verändert werden, für welche der Operator zuständig ist und führt entsprechend der Zielvorgabge in der Custom Resource Aktionen aus.
25 |
26 | Operators erleichtern es also komplexere Applikationen zu betreiben, da das Management vom Operator übernommen wird. Allfällige komplexe Konfigurationen werden durch Custom Resources abstrahiert und Betriebsaufgaben wie Backups oder das Rotieren von Zertifikaten etc. können auch vom Operator ausgeführt werden.
27 |
28 |
29 | ## Installation eines Operators
30 |
31 | Ein Operator läuft wie eine normale Applikation als Pod im Cluster. Zur Installation eines Operators gehören in der Regel die folgenden Ressourcen:
32 |
33 | * ***Custom Resource Definition***: Damit die neuen Custom Resources angelegt werden können, welche der Operator behandelt, müssen die entsprechenden CRDs installiert werden.
34 | * ***Service Account***: Ein Service Account mit welchem der Operator läuft.
35 | * ***Role und RoleBinding***: Mit einer Role definiert man alle Rechte, welche der Operator braucht. Dazu gehören mindestens Rechte auf die eigene Custom Resource. Mit einem RoleBinding wird die neue Role dem Service Account des Operators zugewiesen.
36 | * ***Deployment***: Ein Deployment um den eigentlichen Operator laufen zu lassen. Der Operator läuft meistens nur einmal (Replicas auf 1 eingestellt), da sich sonst die verschiedenen Operator-Instanzen gegenseitig in die Quere kommen würden.
37 |
38 | Auf OpenShift 4 ist standardmässig der Operator Lifecycle Manager (OLM) installiert. OLM vereinfacht die Installation von Operators. Der OLM erlaubt es uns, aus einem Katalog einen Operator auszuwählen (_subscriben_), welcher dann automatisch installiert und je nach Einstellung auch automatisch upgedated wird.
39 |
40 | Als Beispiel installieren wir in den nächsten Schritten den ETCD-Operator. Normalerweise ist das Aufsetzen eines ETCD-Clusters ein Prozess mit einigen Schritten und man muss viele Optionen zum Starten der einzelnen Cluster-Member kennen. Der ETCD-Operator erlaubt es uns mit der EtcdCluster-Custom-Resource ganz einfach einen ETCD-Cluster aufzusetzen. Dabei brauchen wir kein detailliertes Wissen über ETCD, welches normalerweise für das Setup notwendig wäre, da dies alles vom Operator übernommen wird.
41 | Wie für ETCD gibt es auch für viele andere Applikationen vorgefertigte Operators, welche einem den Betrieb von diesen massiv vereinfachen.
42 |
43 |
44 | ### Aufgabe 1: ETCD-Operator installieren
45 |
46 | Zunächst legen wir ein neues Projekt an:
47 |
48 | ```
49 | oc new-project [USERNAME]-operator-test
50 | ```
51 |
52 | Wir schauen nun als erstes, welche Operators verfügbar sind. Unter den verfügbaren Operators finden wir den Operator `etcd` im Katalog Community Operators:
53 |
54 | ```
55 | oc -n openshift-marketplace get packagemanifests.packages.operators.coreos.com | grep etcd
56 | ```
57 |
58 | ***Hinweis***: Als Cluster-Administrator kann man dies über die WebConsole machen (Operators -> OperatorHub).
59 |
60 | Den ETCD-Operator können wir nun installieren, in dem wir eine Subscription anlegen. Mit vorhandenem `cat`-Binary kann dies mit folgendem Befehl gemacht werden, alternativ kann der Inhalt in ein File geschrieben und mit `oc create -f ` erstellt werden.
61 |
62 | ```
63 | oc create -f - <Troubleshooting →
226 |
227 | [← zurück zur Übersicht](../README.md)
228 |
--------------------------------------------------------------------------------
/labs/08_troubleshooting_ops.md:
--------------------------------------------------------------------------------
1 | # Lab 8: Troubleshooting
2 |
3 | In diesem Lab wird aufgezeigt, wie man im Fehlerfall vorgehen kann und welche Tools einem dabei zur Verfügung stehen.
4 |
5 | ## In Container einloggen
6 |
7 | Wir verwenden dafür das Projekt aus [Lab 4](04_deploy_dockerimage.md) `[USERNAME]-dockerimage`.
8 |
9 | Tipp
oc project [USERNAME]-dockerimage
10 |
11 | Laufende Container werden als unveränderbare Infrastruktur behandelt und sollen generell nicht modifiziert werden.
12 | Dennoch gibt es Usecases, bei denen man sich in die Container einloggen muss.
13 | Zum Beispiel für Debugging und Analysen.
14 |
15 | ## Aufgabe 1: Remote Shells
16 |
17 | Mit OpenShift können Remote Shells in die Pods geöffnet werden, ohne dass man darin vorgängig SSH installieren müsste.
18 | Dafür steht einem der Befehl `oc rsh` zur Verfügung.
19 |
20 | Wählen Sie einen Pod aus und öffnen Sie die Remote Shell.
21 |
22 | Tipp
oc get pods
oc rsh [POD]
23 |
24 | __Tipp__:
25 | Falls `oc rsh` nicht funktioniert, öffnen Sie in der Web Console ein Terminal (Applications -> Pods -> [Pod-Name] -> Terminal).
26 |
27 | Sie können nun über diese Shell Analysen im Container ausführen:
28 |
29 | ```bash
30 | bash-4.2$ ls -la
31 | total 16
32 | drwxr-xr-x. 7 default root 99 May 16 13:35 .
33 | drwxr-xr-x. 4 default root 54 May 16 13:36 ..
34 | drwxr-xr-x. 6 default root 57 May 16 13:35 .gradle
35 | drwxr-xr-x. 3 default root 18 May 16 12:26 .pki
36 | drwxr-xr-x. 9 default root 4096 May 16 13:35 build
37 | -rw-r--r--. 1 root root 1145 May 16 13:33 build.gradle
38 | drwxr-xr-x. 3 root root 20 May 16 13:34 gradle
39 | -rwxr-xr-x. 1 root root 4971 May 16 13:33 gradlew
40 | drwxr-xr-x. 4 root root 28 May 16 13:34 src
41 | ```
42 |
43 | Mit `exit` bzw. `ctrl`+`d` kann wieder aus dem Pod bzw. der Shell ausgeloggt werden.
44 |
45 |
46 | ## Aufgabe 2: Befehle ausführen im Container
47 |
48 | Einzelne Befehle innerhalb des Containers können über `oc exec` ausgeführt werden:
49 |
50 | ```bash
51 | oc exec [POD] -- env
52 | ```
53 |
54 | Zum Beispiel:
55 |
56 | ```bash
57 | $ oc exec example-spring-boot-4-8mbwe -- env
58 | PATH=/opt/app-root/src/bin:/opt/app-root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
59 | HOSTNAME=example-spring-boot-4-8mbwe
60 | KUBERNETES_SERVICE_PORT_DNS_TCP=53
61 | KUBERNETES_PORT_443_TCP_PROTO=tcp
62 | KUBERNETES_PORT_443_TCP_ADDR=172.30.0.1
63 | KUBERNETES_PORT_53_UDP_PROTO=udp
64 | KUBERNETES_PORT_53_TCP=tcp://172.30.0.1:53
65 | ...
66 | ```
67 |
68 |
69 | ## Logfiles betrachten
70 |
71 | Die Logfiles zu einem Pod können sowohl in der Web Console als auch auch im CLI angezeigt werden:
72 |
73 | ```bash
74 | oc logs [POD]
75 | ```
76 |
77 | Der Parameter `-f` bewirkt dasselbe Verhalten wie `tail -f`, also "follow".
78 |
79 | Befindet sich ein Pod im Status __CrashLoopBackOff__ bedeutet dies, dass er auch nach wiederholtem Neustarten nicht erfolgreich gestartet werden konnte.
80 | Die Logfiles können auch wenn der Pod nicht läuft mit dem folgenden Befehl angezeigt werden:
81 |
82 | ```bash
83 | oc logs -p [POD]
84 | ```
85 |
86 | Der Parameter `-p` steht dabei für "previous", bezieht sich also auf einen Pod derselben DeploymentConfig, der zuvor noch lief, nun aber nicht mehr.
87 | Entsprechend funktioniert dieser Befehl nur, wenn es tatsächlich einen Pod zuvor gab.
88 |
89 | Mit OpenShift wird ein EFK-Stack (Elasticsearch, Fluentd, Kibana) mitgeliefert, der sämtliche Logfiles sammelt, rotiert und aggregiert.
90 | Kibana erlaubt es Logs zu durchsuchen, zu filtern und grafisch aufzubereiten.
91 |
92 |
93 | ## Metriken
94 |
95 | Die OpenShift Platform stellt auch ein Grundset an Metriken zur Verfügung, welche einerseits in der Web Console integriert sind und andererseits dazu genutzt werden können, Pods automatisch zu skalieren.
96 |
97 | Sie können mit Hilfe eines direkten Logins auf einen Pod nun den Ressourcenverbrauch dieses Pods beeinflussen und die Auswirkungen dazu in der Web Console beobachten.
98 |
99 |
100 | ## Aufgabe 3: Port Forwarding
101 |
102 | OpenShift erlaubt es, beliebige Ports von der Entwicklungs-Workstation auf einen Pod weiterzuleiten.
103 | Dies ist z.B. nützlich, um auf Administrationskonsolen, Datenbanken, usw. zuzugreifen, die nicht gegen das Internet exponiert werden und auch sonst nicht erreichbar sind.
104 | Die Portweiterleitungen werden über dieselbe HTTPS-Verbindung getunnelt, die der OpenShift Client (oc) auch sonst benutzt.
105 | Dies erlaubt es auch dann auf Pods zu verbinden, wenn sich restriktive Firewalls und/oder Proxies zwischen Workstation und OpenShift befinden.
106 |
107 | Übung: Auf die Spring Boot Metrics aus [Lab 4](04_deploy_dockerimage.md) zugreifen.
108 |
109 | ```bash
110 | oc get pod --namespace="[USERNAME]-dockerimage"
111 | oc port-forward [POD] 9000:9000 --namespace="[USERNAME]-dockerimage"
112 | ```
113 |
114 | Nicht vergessen den Pod Namen an die eigene Installation anzupassen.
115 | Falls installiert kann dafür Autocompletion verwendet werden.
116 |
117 | Die Metrics können nun unter folgender URL abgerufen werden: [http://localhost:9000/metrics/](http://localhost:9000/metrics/).
118 |
119 | Die Metrics werden Ihnen als JSON angezeigt.
120 | Mit demselben Konzept können Sie nun bspw. mit Ihrem lokalen SQL Client auf eine Datenbank verbinden.
121 |
122 | In der [Dokumentation](https://docs.openshift.com/container-platform/latest/nodes/containers/nodes-containers-port-forwarding.html) sind weiterführende Informationen zu Port Forwarding zu finden.
123 |
124 | __Note__:
125 | Der `oc port-forward`-Prozess wird solange weiterlaufen, bis er vom User abgebrochen wird.
126 | Sobald das Port-Forwarding also nicht mehr benötigt wird, kann er mit ctrl+c gestoppt werden.
127 |
128 | ---
129 |
130 | __Ende Lab 8__
131 |
132 | Datenbank deployen und anbinden →
133 |
134 | [← zurück zur Übersicht](../README.md)
135 |
--------------------------------------------------------------------------------
/labs/09_database.md:
--------------------------------------------------------------------------------
1 | # Lab 9: Datenbank anbinden
2 |
3 | Die meisten Applikationen sind in irgend einer Art stateful (sie haben also einen eigenen Zustand) und speichern Daten persistent ab.
4 | Sei dies in einer Datenbank oder als Files auf einem Filesystem oder Objectstore.
5 | In diesem Lab werden wir in unserem Projekt einen MariaDB-Service anlegen und an unsere Applikation anbinden, sodass mehrere Applikationspods auf die gleiche Datenbank zugreifen können.
6 |
7 | Für dieses Beispiel verwenden wir das Spring Boot-Beispiel aus [Lab 4](04_deploy_dockerimage.md), `[USERNAME]-dockerimage`.
8 |
9 | Tipp
oc project [USERNAME]-dockerimage
10 |
11 |
12 | ## Aufgabe 1: MariaDB Service anlegen
13 |
14 | Für unser Beispiel verwenden wir in diesem Lab ein OpenShift Template, welches eine MariaDB Datenbank mit EmptyDir Data Storage anlegt.
15 | Dies ist nur für Testumgebungen zu verwenden, da beim Restart des MariaDB Pod alle Daten verloren gehen.
16 | In einem späteren Lab werden wir aufzeigen, wie wir ein Persistent Volume (mariadb-persistent) an die MariaDB Datenbank anhängen.
17 | Damit bleiben die Daten auch bei Restarts bestehen, womit der Setup auch für den produktiven Betrieb geeignet ist.
18 |
19 | Den MariaDB Service können wir sowohl über die Web Console als auch über das CLI anlegen.
20 |
21 | Um dasselbe Ergebnis zu erhalten müssen lediglich Datenbankname, Username, Password und DatabaseServiceName gleich gesetzt werden, egal welche Variante verwendet wird:
22 |
23 | - `MYSQL_USER: appuio`
24 | - `MYSQL_PASSWORD: appuio`
25 | - `MYSQL_DATABASE: appuio`
26 | - `DATABASE_SERVICE_NAME: mariadb`
27 |
28 |
29 | ### CLI
30 |
31 | Über das CLI kann der MariaDB Service wie folgt angelegt werden.
32 |
33 | __Note__:
34 | Die Backslashes (`\`) dienen dazu, einen langen Befehl übersichtlicher auf mehreren Zeilen abzubilden.
35 | __Auf Windows__ ist der sog. Multiline Delimiter aber nicht der Backslash, sondern in cmd das Caret (`^`) und in PowerShell der Backtick (`` ` ``).
36 |
37 | ```bash
38 | oc new-app mariadb-ephemeral \
39 | -pMYSQL_USER=appuio \
40 | -pMYSQL_PASSWORD=appuio \
41 | -pMYSQL_DATABASE=appuio
42 | ```
43 |
44 | Diese Ressourcen werden angelegt:
45 |
46 | ```bash
47 | secret/mariadb created
48 | service/mariadb created
49 | deploymentconfig.apps.openshift.io/mariadb created
50 | ```
51 |
52 |
53 | ### Web Console
54 |
55 | In der Web Console kann der MariaDB (Ephemeral) Service via Catalog in der Developer-Ansicht dem Projekt hinzugefügt werden:
56 |
57 | - Zuerst sicherstellen, dass oben links von der Administrator- auf die Developer-Ansicht gewechselt wurde
58 | - Auf "\+Add" klicken (links oben)
59 | - "From Catalog" wählen
60 | - Auswahl mit Klick auf "Databases", "MariaDB" einschränken
61 | - Das Feld "MariaDB (Ephemeral)" und anschliessend "Instantiate Template" auswählen
62 | - Die Formularfelder "MariaDB Connection Username", "MariaDB Connection Password" sowie "MariaDB Database Name" abfüllen
63 | - Die restlichen Formularfelder leer oder auf deren Standardwert belassen und mit "Create" erstellen lassen
64 |
65 | 
66 |
67 |
68 | ### Passwort und Username als Plaintext?
69 |
70 | Beim Deployen der Datenbank via CLI wie auch via Web Console haben wir mittels Parameter Werte für User, Passwort und Datenbank angegeben.
71 | In diesem Kapitel wollen wir uns nun anschauen, wo diese sensitiven Daten effektiv gelandet sind.
72 |
73 | Schauen wir uns als erstes die DeploymentConfig der Datenbank an:
74 |
75 | ```bash
76 | oc get dc mariadb -o yaml
77 | ```
78 |
79 | Konkret geht es um die Konfiguration der Container mittels Umgebungsvariablen (`MYSQL_USER`, `MYSQL_PASSWORD`, `MYSQL_ROOT_PASSWORD`, `MYSQL_DATABASE`) in der DeploymentConfig unter `spec.templates.spec.containers`:
80 |
81 | ```yaml
82 | spec:
83 | containers:
84 | - env:
85 | - name: MYSQL_USER
86 | valueFrom:
87 | secretKeyRef:
88 | key: database-user
89 | name: mariadb
90 | - name: MYSQL_PASSWORD
91 | valueFrom:
92 | secretKeyRef:
93 | key: database-password
94 | name: mariadb
95 | - name: MYSQL_ROOT_PASSWORD
96 | valueFrom:
97 | secretKeyRef:
98 | key: database-root-password
99 | name: mariadb
100 | - name: MYSQL_DATABASE
101 | valueFrom:
102 | secretKeyRef:
103 | key: database-name
104 | name: mariadb
105 | ```
106 |
107 | Die Werte für die einzelnen Umgebungsvariablen kommen also aus einem sogenannten Secret, in unserem Fall hier aus dem Secret mit Namen `mariadb`.
108 | In diesem Secret sind die vier Werte unter den passenden Keys (`database-user`, `database-password`, `database-root-password`, `database-name`) abgelegt und können so referenziert werden.
109 |
110 | Schauen wir uns nun die neue Ressource Secret mit dem Namen `mariadb` an:
111 |
112 | ```bash
113 | oc get secret mariadb -o yaml
114 | ```
115 |
116 | Die Key-Value Pairs sind unter `data` ersichtlich:
117 |
118 | ```yaml
119 | apiVersion: v1
120 | data:
121 | database-name: YXBwdWlv
122 | database-password: YXBwdWlv
123 | database-root-password: dDB3ZDFLRFhsVjhKMGFHQw==
124 | database-user: YXBwdWlv
125 | kind: Secret
126 | metadata:
127 | annotations:
128 | openshift.io/generated-by: OpenShiftNewApp
129 | template.openshift.io/expose-database_name: '{.data[''database-name'']}'
130 | template.openshift.io/expose-password: '{.data[''database-password'']}'
131 | template.openshift.io/expose-root_password: '{.data[''database-root-password'']}'
132 | template.openshift.io/expose-username: '{.data[''database-user'']}'
133 | creationTimestamp: 2018-12-04T10:33:43Z
134 | labels:
135 | app: mariadb-ephemeral
136 | template: mariadb-ephemeral-template
137 | name: mariadb
138 | ...
139 | type: Opaque
140 | ```
141 |
142 | Die konkreten Werte sind base64-kodiert.
143 | Unter Linux oder in der Git Bash kann man sich den Wert einfach mittels:
144 |
145 | ```bash
146 | echo "YXBwdWlv" | base64 -d
147 | appuio
148 | ```
149 |
150 | anzeigen lassen.
151 | In unserem Fall wird `YXBwdWlv` in `appuio` dekodiert.
152 |
153 | Alternativ kann mit dem Befehl `oc extract secret/mariadb` der Inhalt jedes einzelnen Keys in ein eigenes File geschrieben werden.
154 | Mit dem Parameter `--to=[DIRECTORY]` kann das Verzeichnis definiert werden, in welches die Werte geschrieben werden soll.
155 | Ohne Angabe dieses Parameters wird das aktuelle Verzeichnis verwendet.
156 |
157 | Mit Secrets können wir also sensitive Informationen (Credentials, Zertifikate, Schlüssel, dockercfg, ...) ablegen und so von den Pods entkoppeln.
158 | Gleichzeitig haben wir damit die Möglichkeit, dieselben Secrets in mehreren Containern zu verwenden und so Redundanzen zu vermeiden.
159 |
160 | Secrets können entweder, wie oben bei der MariaDB-Datenbank, in Umgebungsvariablen gemappt oder direkt als Files via Volumes in einen Container gemountet werden.
161 |
162 | Weitere Informationen zu Secrets können in der [offiziellen Dokumentation](https://docs.openshift.com/container-platform/latest/nodes/pods/nodes-pods-secrets.html) gefunden werden.
163 |
164 | ## Aufgabe: LAB8.2: Applikation an die Datenbank anbinden
165 |
166 | Standardmässig wird bei unserer example-spring-boot Applikation eine H2 Memory Datenbank verwendet.
167 | Dies kann über das Setzen der folgenden Umgebungsvariablen entsprechend auf unseren neuen MariaDB Service umgestellt werden:
168 |
169 | - `SPRING_DATASOURCE_USERNAME: appuio`
170 | - `SPRING_DATASOURCE_PASSWORD: appuio`
171 | - `SPRING_DATASOURCE_DRIVER_CLASS_NAME: com.mysql.cj.jdbc.Driver`
172 | - `SPRING_DATASOURCE_URL: jdbc:mysql://[Adresse des MariaDB Service]/appuio?autoReconnect=true`
173 |
174 | Für die Adresse des MariaDB Service können wir entweder dessen Cluster IP (`oc get service`) oder aber dessen DNS-Namen (``) verwenden.
175 | Alle Services und Pods innerhalb eines Projektes können über DNS aufgelöst werden.
176 |
177 | So lautet der Wert für die Variable `SPRING_DATASOURCE_URL` bspw.:
178 |
179 | ```
180 | Name des Service: mariadb
181 |
182 | jdbc:mysql://mariadb/appuio?autoReconnect=true
183 | ```
184 |
185 | Diese Umgebungsvariablen können wir nun in der DeploymentConfig example-spring-boot setzen.
186 | Nach dem __ConfigChange__ wird die Applikation automatisch neu deployed (ConfigChange ist in der DeploymentConfig als Trigger registriert).
187 | Aufgrund der neuen Umgebungsvariablen verbindet die Applikation an die MariaDB DB und [Liquibase](http://www.liquibase.org/) kreiert das Schema und importiert die Testdaten.
188 |
189 | __Note__:
190 | Liquibase ist Open Source.
191 | Es ist eine datenbank-unabhängige Library, um Datenbankänderungen zu verwalten und anzuwenden.
192 | Liquibase erkennt beim Startup der Applikation, ob DB Changes auf der Datenbank angewendet werden müssen oder nicht.
193 | Siehe Logs.
194 |
195 | ```bash
196 | SPRING_DATASOURCE_URL=jdbc:mysql://mariadb/appuio?autoReconnect=true
197 | ```
198 |
199 | __Note__:
200 | MariaDB löst innerhalb Ihres Projektes via DNS-Abfrage auf die Cluster IP des MariaDB Service auf.
201 | Die MariaDB Datenbank ist nur innerhalb des Projektes erreichbar.
202 | Der Service ist ebenfalls über den folgenden Namen erreichbar:
203 |
204 | ```
205 | Projektname = techlab-dockerimage
206 |
207 | mariadb.techlab-dockerimage.svc.cluster.local
208 | ```
209 |
210 | Über das CLI kann der MariaDB Service wie folgt angebunden werden:
211 |
212 | __Note__:
213 | Die Backslashes (`\`) dienen dazu, den langen Befehl übersichtlicher auf mehreren Zeilen abzubilden.
214 | __Auf Windows__ ist der sog. Multiline Delimiter aber nicht der Backslash, sondern in cmd das Caret (`^`) und in PowerShell der Backtick (`` ` ``).
215 |
216 | ```bash
217 | oc set env dc example-spring-boot \
218 | -e SPRING_DATASOURCE_URL="jdbc:mysql://mariadb/appuio?autoReconnect=true" \
219 | -e SPRING_DATASOURCE_USERNAME=appuio \
220 | -e SPRING_DATASOURCE_PASSWORD=appuio \
221 | -e SPRING_DATASOURCE_DRIVER_CLASS_NAME=com.mysql.cj.jdbc.Driver
222 | ```
223 |
224 | Durch die Änderung des Environments wird automatisch ein Deployment der example-spring-boot Applikation angestossen.
225 | Dabei wir der Pod bzw. Container mit der neuen Umgebung gestartet.
226 |
227 | Über den folgenden Befehl können Sie sich die DeploymentConfig in json anschauen.
228 | Neu enthält die Config auch die gesetzten Umgebungsvariablen:
229 |
230 | ```bash
231 | oc get dc example-spring-boot -o json
232 | ```
233 |
234 | ```json
235 | ...
236 | "env": [
237 | {
238 | "name": "SPRING_DATASOURCE_URL",
239 | "value": "jdbc:mysql://mariadb/appuio?autoReconnect=true&useSSL=false"
240 | },
241 | {
242 | "name": "SPRING_DATASOURCE_USERNAME",
243 | "value": "appuio"
244 | },
245 | {
246 | "name": "SPRING_DATASOURCE_PASSWORD",
247 | "value": "appuio"
248 | },
249 | {
250 | "name": "SPRING_DATASOURCE_DRIVER_CLASS_NAME",
251 | "value": "com.mysql.cj.jdbc.Driver"
252 | }
253 | ],
254 | ...
255 | ```
256 |
257 | Die Konfiguration kann auch in der Web Console angeschaut und verändert werden:
258 |
259 | - Stellen Sie sicher, dass Sie sich in der Developer-Ansicht (Auswahl oben links) befinden
260 | - Klicken Sie auf Topology
261 | - Wählen Sie die example-spring-boot DC aus, indem Sie auf das OpenShift-Symbol klicken
262 | - Im neu geöffneten Seitenfenster wählen Sie oben rechts unter "Actions" die Option "Edit DeploymentConfig"
263 |
264 |
265 | ### Spring Boot Applikation
266 |
267 | Öffnen Sie die Applikation im Browser.
268 |
269 | Sind die "Say Hello" Einträge von früher noch da?
270 |
271 | - Wenn ja, wieso?
272 | - Wenn nein, wieso?
273 |
274 | Fügen Sie ein paar neue "Say Hello" Einträge ein.
275 |
276 |
277 | ## Aufgabe 2: Secret referenzieren
278 |
279 | Weiter oben haben wir gesehen, wie OpenShift mittels Secrets sensitive Informationen von der eigentlichen Konfiguration entkoppelt und uns dabei hilft, Redundanzen zu vermeiden.
280 | Unsere Springboot Applikation aus dem vorherigen Lab haben wir zwar korrekt konfiguriert, allerings aber die Werte redundant und Plaintext in der DeploymentConfig abgelegt.
281 |
282 | Passen wir nun die DeploymentConfig example-spring-boot so an, dass die Werte aus den Secrets verwendet werden.
283 | Zu beachten gibt es die Konfiguration der Container unter `spec.template.spec.containers`.
284 |
285 | Mittels `oc edit dc example-spring-boot -o json` kann die DeploymentConfig im JSON-Format wie folgt bearbeitet werden.
286 |
287 | ```json
288 | ...
289 | "env": [
290 | {
291 | "name": "SPRING_DATASOURCE_USERNAME",
292 | "valueFrom": {
293 | "secretKeyRef": {
294 | "key": "database-user",
295 | "name": "mariadb"
296 | }
297 | }
298 | },
299 | {
300 | "name": "SPRING_DATASOURCE_PASSWORD",
301 | "valueFrom": {
302 | "secretKeyRef": {
303 | "key": "database-password",
304 | "name": "mariadb"
305 | }
306 | }
307 | },
308 | {
309 | "name": "SPRING_DATASOURCE_DRIVER_CLASS_NAME",
310 | "value": "com.mysql.cj.jdbc.Driver"
311 | },
312 | {
313 | "name": "SPRING_DATASOURCE_URL",
314 | "value": "jdbc:mysql://mariadb/appuio?autoReconnect=true"
315 | }
316 | ],
317 | ...
318 | ```
319 |
320 | Nun werden die Werte für Username und Passwort sowohl beim MariaDB-Pod wie auch beim Springboot-Pod aus dem selben Secret gelesen.
321 |
322 |
323 | ### Spring Boot Applikation
324 |
325 | Öffnen Sie die Applikation im Browser.
326 |
327 | Sind die "Say Hello" Einträge von früher noch da?
328 |
329 | - Wenn ja, wieso?
330 | - Wenn nein, wieso?
331 |
332 | Fügen Sie ein paar neue "Say Hello" Einträge ein.
333 |
334 |
335 | ## Aufgabe 3: Auf DB verbinden
336 |
337 | Wie im Lab [07](07_troubleshooting_ops.md) beschrieben kann mittels `oc rsh [POD]` in einen Pod eingeloggt werden:
338 |
339 | ```bash
340 | $ oc get pods
341 | NAME READY STATUS RESTARTS AGE
342 | example-spring-boot-8-wkros 1/1 Running 0 10m
343 | mariadb-1-diccy 1/1 Running 0 50m
344 | ```
345 |
346 | Danach in den MariaDB Pod einloggen:
347 |
348 | ```bash
349 | oc rsh mariadb-1-diccy
350 | ```
351 |
352 | Einfacher ist, es den Pod über die DeploymentConfig zu referenzieren.
353 |
354 | ```bash
355 | oc rsh dc/mariadb
356 | ```
357 |
358 | __Tipp__:
359 | Falls `oc rsh` nicht funktioniert, öffnen Sie in der Web Console ein Terminal (Applications -> Pods -> mysql-1-diccy -> Terminal).
360 |
361 | Nun können Sie mittels mysql-Tool auf die Datenbank verbinden:
362 |
363 | ```bash
364 | mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -h$MARIADB_SERVICE_HOST $MYSQL_DATABASE
365 | ```
366 |
367 | Und mit:
368 |
369 | ```sql
370 | show tables;
371 | ```
372 |
373 | alle Tabellen anzeigen.
374 |
375 | Was enthält die hello-Tabelle?
376 |
377 | Tipp
select * from hello;
378 |
379 |
380 | ## Aufgabe 4: Dump einspielen
381 |
382 | Die Aufgabe ist es, in den MariaDB Pod den [Dump](https://raw.githubusercontent.com/appuio/techlab/lab-4/labs/data/08_dump/dump.sql) einzuspielen.
383 |
384 | __Tipp__:
385 | Mit `oc rsync` oder `oc cp` können Sie lokale Dateien in einen Pod kopieren.
386 | Alternativ kann auch curl im MariaDB-Container verwendet werden.
387 |
388 | __Achtung__:
389 | Beachten Sie, dass dabei der rsync-Befehl des Betriebssystems verwendet wird.
390 | Auf UNIX-Systemen kann rsync mit dem Paketmanager, auf Windows kann bspw. [cwRsync](https://www.itefix.net/cwrsync) installiert werden.
391 | Ist eine Installation von rsync nicht möglich, kann stattdessen bspw. in den Pod eingeloggt und via `curl -O ` der Dump heruntergeladen werden.
392 |
393 | __Tipp__:
394 | Verwenden Sie das Tool mysql um den Dump einzuspielen.
395 |
396 | __Tipp__:
397 | Die bestehende Datenbank muss vorgängig leer sein.
398 | Sie kann auch gelöscht und neu angelegt werden.
399 |
400 |
401 | ### Spring Boot Applikation
402 |
403 | Öffnen Sie die Applikation im Browser.
404 |
405 | Sind die "Say Hello" Einträge von früher noch da?
406 |
407 | - Wenn ja, wieso?
408 | - Wenn nein, wieso?
409 |
410 | ---
411 |
412 |
413 | ## Lösung Aufgabe 4
414 |
415 | Ein ganzes Verzeichnis (dump) syncen.
416 | Darin enthalten ist das File `dump.sql`.
417 | Beachten Sie zum rsync-Befehl auch obenstehenden Tipp sowie den fehlenden "trailing slash".
418 |
419 | ```bash
420 | oc rsync ./labs/data/08_dump mariadb-1-diccy:/tmp/
421 | ```
422 |
423 | __Tipp__:
424 | Falls `oc rsync` nicht funktioniert, `oc cp ./labs/data/08_dump mariadb-1-diccy:/tmp/` verwenden.
425 |
426 | In den MariaDB-Pod einloggen:
427 |
428 | ```bash
429 | oc rsh dc/mariadb
430 | ```
431 |
432 | Bestehende Datenbank löschen:
433 |
434 | ```bash
435 | mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -h$MARIADB_SERVICE_HOST $MYSQL_DATABASE
436 | ...
437 | mysql> drop database appuio;
438 | mysql> create database appuio;
439 | mysql> exit
440 | ```
441 |
442 | Dump einspielen:
443 |
444 | ```bash
445 | mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -h$MARIADB_SERVICE_HOST $MYSQL_DATABASE < /tmp/08_dump/dump.sql
446 | ```
447 |
448 | Was enthält die hello Tabelle jetzt?
449 |
450 | Tipp
mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -h$MARIADB_SERVICE_HOST $MYSQL_DATABASE
mysql> select * from hello;
451 |
452 | __Note__:
453 | Den Dump kann man wie folgt erstellen:
454 |
455 | ```bash
456 | mysqldump -u$MYSQL_USER -p$MYSQL_PASSWORD -h$MARIADB_SERVICE_HOST $MYSQL_DATABASE > /tmp/dump.sql
457 | ```
458 |
459 | ---
460 |
461 | __Ende Lab 9__
462 |
463 | Persistent Storage anbinden und verwenden für Datenbank →
464 |
465 | [← zurück zur Übersicht](../README.md)
466 |
--------------------------------------------------------------------------------
/labs/10_persistent_storage.md:
--------------------------------------------------------------------------------
1 | # Lab 10: Persistent Storage anbinden und verwenden für Datenbank
2 |
3 | Per se sind Daten in einem Pod nicht persistent, was u.a. auch in unserem Beispiel der Fall ist.
4 | Verschwindet also unser MariaDB-Pod bspw. aufgrund einer Änderung des Image, sind die bis zuvor noch vorhandenen Daten im neuen Pod nicht mehr vorhanden.
5 | Um genau dies zu verhindern hängen wir nun Persistent Storage an unseren MariaDB-Pod an.
6 |
7 | ## Aufgabe 1: Persistent Storage anbinden
8 |
9 | ### Storage anfordern
10 |
11 | Das Anhängen von Persistent Storage geschieht eigentlich in zwei Schritten.
12 | Der erste Schritt beinhaltet als erstes das Erstellen eines sog. PersistentVolumeClaim für unser Projekt.
13 | Im Claim definieren wir u.a. dessen Namen sowie Grösse, also wie viel persistenten Speicher wir überhaupt haben wollen.
14 |
15 | Der PersistentVolumeClaim stellt allerdings erst den Request dar, nicht aber die Ressource selbst.
16 | Er wird deshalb automatisch durch OpenShift mit einem zur Verfügung stehenden Persistent Volume verbunden, und zwar mit einem mit mindestens der angeforderten Grösse.
17 | Sind nur noch grössere Persistent Volumes vorhanden, wird eines dieser Volumes verwendet und die Grösse des Claim angepasst.
18 | Sind nur noch kleinere Persistent Volumes vorhanden, kann der Claim nicht erfüllt werden und bleibt solange offen, bis ein Volume der passenden Grösse (oder eben grösser) auftaucht.
19 |
20 |
21 | ### Volume in Pod einbinden
22 |
23 | Im zweiten Schritt wird der zuvor erstellte PVC im richtigen Pod eingebunden.
24 | In [Lab 6](06_scale.md) bearbeiteten wir die DeploymentConfig, um die Readiness Probe einzufügen.
25 | Dasselbe tun wir nun für das Persistent Volume.
26 | Im Unterschied zu [Lab 6](06_scale.md) können wir aber mit `oc set volume` die DeploymentConfig automatisch erweitern.
27 |
28 | Wir verwenden dafür das Projekt aus [Lab 9](09_database.md) [USERNAME]-dockerimage.
29 |
30 | Tipp
oc project [USERNAME]-dockerimage
31 |
32 | Der folgende Befehl führt beide beschriebenen Schritte zugleich aus, er erstellt also zuerst den Claim und bindet ihn anschliessend auch als Volume im Pod ein:
33 |
34 | ```bash
35 | oc set volume dc/mariadb --add --name=mariadb-data --type pvc \
36 | --claim-name=mariadbpvc --claim-size=256Mi --overwrite
37 | ```
38 |
39 | __Note__:
40 | Durch die veränderte DeploymentConfig deployt OpenShift automatisch einen neuen Pod.
41 | D.h. leider auch, dass das vorher erstellte DB-Schema und bereits eingefügte Daten verloren gegangen sind.
42 |
43 | Unsere Applikation erstellt beim Starten das DB Schema eigenständig.
44 |
45 | __Tipp__:
46 | Redeployen Sie den Applikations-Pod mit:
47 |
48 | ```bash
49 | oc rollout latest example-spring-boot
50 | ```
51 |
52 | Mit dem Befehl `oc get persistentvolumeclaim`, oder etwas einfacher `oc get pvc`, können wir uns nun den im Projekt frisch erstellten PersistentVolumeClaim anzeigen lassen:
53 |
54 | ```
55 | oc get pvc
56 | NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
57 | mariadbpvc Bound pv34 1Gi RWO,RWX 14s
58 | ```
59 |
60 | Die beiden Attribute Status und Volume zeigen uns an, dass unser Claim mit dem Persistent Volume pv34 verbunden wurde.
61 |
62 | Mit dem folgenden Befehl können wir auch noch überprüfen, ob das Einbinden des Volume in die DeploymentConfig geklappt hat:
63 |
64 | ```bash
65 | oc set volume dc/mariadb --all
66 | deploymentconfigs/mariadb
67 | pvc/mariadbpvc (allocated 1GiB) as mariadb-data
68 | mounted at /var/lib/mysql/data
69 | ```
70 |
71 |
72 | ## Aufgabe 2: Persistenz-Test
73 |
74 | ### Daten wiederherstellen
75 |
76 | Wiederholen Sie [Lab-Aufgabe 9.4](09_database.md#l%C3%B6sung-lab84).
77 |
78 |
79 | ### Test
80 |
81 | Skalieren Sie nun den MariaDB-Pod auf 0 und anschliessend wieder auf 1. Beobachten Sie, dass der neue Pod die Daten nicht mehr verliert.
82 |
83 | ---
84 |
85 | __Ende Lab 10__
86 |
87 | Code Änderungen via Webhook direkt integrieren →
88 |
89 | [← zurück zur Übersicht](../README.md)
90 |
--------------------------------------------------------------------------------
/labs/11_dockerbuild_webhook.md:
--------------------------------------------------------------------------------
1 | # Lab 11: Code Changes durch Webhook triggern Rebuild auf OpenShift
2 |
3 | In diesem Lab zeigen wir den Docker Build Workflow anhand eines Beispiels auf und Sie lernen, wie Sie mit einem Push in das Git Repository automatisch einen Build und ein Deployment der Applikation auf OpenShift starten.
4 |
5 |
6 | ## Aufgabe 1: Vorbereitung Github Account und Fork
7 |
8 | ### Github Account
9 |
10 | Damit Sie Änderungen am Source Code unserer Beispielapplikation vornehmen können, benötigen Sie einen eigenen GitHub Account.
11 | Richten Sie sich einen Account unter ein, falls Sie nicht bereits über einen verfügen.
12 |
13 |
14 | ### Beispiel-Projekt forken
15 |
16 | __Beispiel-Projekt__:
17 |
18 | Gehen Sie auf die [GitHub Projekt-Seite](https://github.com/appuio/example-php-docker-helloworld) und [forken](https://help.github.com/articles/fork-a-repo/) Sie das Projekt.
19 |
20 | 
21 |
22 | Sie haben nun unter `https://github.com/[YourGitHubUser]/example-php-docker-helloworld` einen Fork des Example Projektes, den Sie so erweitern können wie Sie wollen.
23 |
24 |
25 | ## Deployen des eigenen Forks
26 |
27 | Erstellen Sie ein neues Projekt mit Namen `[USERNAME]-example4`.
28 |
29 | Tipp
oc new-project [USERNAME]-example4
30 |
31 | Erstellen Sie für Ihren Fork eine neue App mit folgender Konfiguration:
32 |
33 | * Name: `appuio-php-docker-ex`
34 | * Build Strategie: `docker`
35 | * Git Repository: `https://github.com/[YourGithubUser]/example-php-docker-helloworld.git`
36 |
37 | __Note__:
38 | Ersetzen Sie `[YourGithubUser]` mit dem Namen Ihres GitHub Accounts.
39 |
40 |
41 | Applikation Erstellen Befehl
42 | oc new-app --as-deployment-config https://github.com/[YourGithubUser]/example-php-docker-helloworld.git --strategy=docker --name=appuio-php-docker-ex
43 |
44 |
45 | Mittels Parameter `--strategy=docker` sagen wir dem `oc new-app` Befehl nun explizit, er soll im angegebenen Git Repository nach einem Dockerfile suchen und dieses für den Build verwenden.
46 |
47 | Nun exponieren Sie den Service der Applikation.
48 |
49 | Route Erstellen Befehl
oc create route edge --service=appuio-php-docker-ex
50 |
51 |
52 | ## Aufgabe 2: Webhook auf GitHub einrichten
53 |
54 | Beim Erstellen der App wurden in der BuildConfig (bc) direkt Webhooks definiert.
55 | Diese Webhooks können Sie von der Web Console kopieren.
56 | Gehen Sie dafür via Menüpunkt "Builds" auf den "appuio-php-docker-ex" Build.
57 | Sie sehen nun die Webhooks auf der Seite unten.
58 |
59 | 
60 |
61 | Kopieren Sie die [GitHub Webhook URL](https://developer.github.com/webhooks/) mit einem Klick rechts auf "Copy URL with Secret".
62 |
63 | Klicken Sie in Ihrem GitHub-Projekt auf Settings:
64 | 
65 |
66 | Klicken Sie auf Webhooks:
67 | 
68 |
69 | Fügen Sie einen Webhook hinzu:
70 | 
71 |
72 | Fügen Sie nun die kopierte GitHub Webhook URL ein:
73 | 
74 |
75 | Ab jetzt triggern alle Pushes auf Ihrem GitHub Repository einen Build und deployen anschliessend die Code-Änderungen direkt auf die OpenShift-Plattform.
76 |
77 |
78 | ## Aufgabe 3: Code anpassen
79 |
80 | Klonen Sie Ihr Git Repository und wechseln Sie in das Code Verzeichnis:
81 |
82 | ```bash
83 | git clone https://github.com/[YourGithubUser]/example-php-docker-helloworld.git
84 | cd example-php-docker-helloworld
85 | ```
86 |
87 | Passen Sie das File `./app/index.php` bspw. auf Zeile 56 an:
88 |
89 | ```bash
90 | vim app/index.php
91 | ```
92 |
93 | 
94 |
95 | ```html
96 |
97 |
98 |
99 |
Hallo
100 |
APPUiO Example Dockerfile PHP
101 |
102 |
103 |
104 | ```
105 |
106 | Pushen Sie Ihren Change:
107 |
108 | ```bash
109 | git add .
110 | git commit -m "Update hello message"
111 | git push
112 | ```
113 |
114 | Als Alternative können Sie das File auch direkt auf GitHub editieren:
115 | 
116 |
117 | Sobald Sie die Änderungen gepushed haben, startet OpenShift einen Build des neuen Source Code.
118 |
119 | ```bash
120 | oc get builds
121 | ```
122 |
123 | und deployed anschliessend die Änderungen.
124 |
125 | ## Aufgabe 4: Rollback
126 |
127 | Mit OpenShift lassen sich unterschiedliche Software-Stände aktivieren und deaktivieren, indem einfach eine andere Version des Image gestartet wird.
128 |
129 | Dafür werden die Befehle `oc rollback` und `oc rollout` verwendet.
130 |
131 | Um ein Rollback auszuführen, brauchen Sie den Namen der DeploymentConfig:
132 |
133 | ```bash
134 | oc get dc
135 |
136 | NAME REVISION DESIRED CURRENT TRIGGERED BY
137 | appuio-php-docker-ex 4 1 1 config,image(appuio-php-docker-ex:latest)
138 | ```
139 |
140 | Mit dem folgenden Befehl können Sie nun ein Rollback auf die Vorgänger-Version ausführen:
141 |
142 | ```bash
143 | oc rollback appuio-php-docker-ex
144 | #3 rolled back to appuio-php-docker-ex-1
145 | Warning: the following images triggers were disabled: appuio-php-docker-ex:latest
146 | You can re-enable them with: oc set triggers dc/appuio-php-docker-ex --auto
147 | ```
148 |
149 | Sobald das Deployment der alten Version erfolgt ist, können Sie über Ihren Browser überprüfen, ob wieder die ursprüngliche Überschrift __Hello APPUiO__ angezeigt wird.
150 |
151 | __Tipp__:
152 | Automatische Deployments neuer Versionen sind nun für diese Applikation deaktiviert, um ungewollte Änderungen nach dem Rollback zu verhindern. Um das automatische Deployment wieder zu aktivieren, führen Sie den folgenden Befehl aus:
153 |
154 | ```bash
155 | oc set triggers dc/appuio-php-docker-ex --auto
156 | ```
157 |
158 | ---
159 |
160 | __Ende Lab 11__
161 |
162 | Applikationstemplates →
163 |
164 | [← zurück zur Übersicht](../README.md)
165 |
--------------------------------------------------------------------------------
/labs/12_template.md:
--------------------------------------------------------------------------------
1 | # Lab 12: Applikationstemplates
2 |
3 | In diesem Lab zeigen wir auf, wie Templates ganze Infrastrukturen beschreiben und entsprechend mit einem Befehl instanziert werden können.
4 |
5 |
6 | ## Templates
7 |
8 | Wie Sie in den vorangegangenen Labs gesehen haben, können einfach über die Eingabe unterschiedlicher Befehle Applikationen, Datenbanken, Services und deren Konfiguration erstellt und deployt werden.
9 |
10 | Dies ist fehleranfällig und eignet sich schlecht zum Automatisieren.
11 |
12 | OpenShift bietet dafür das Konzept von Templates, in welchen man eine Liste von Ressourcen beschreiben kann, die parametrisiert werden können.
13 | Sie sind also quasi ein Rezept für eine ganze Infrastruktur (bspw. 3 ApplikationsContainer, eine Datenbank mit Persistent Storage).
14 |
15 | __Note__:
16 | Der Cluster Administrator kann globale Templates erstellen, welche allen Benutzern zur Verfügung stehen.
17 |
18 | Alle vorhandenen Templates anzeigen:
19 |
20 | ```bash
21 | oc get template -n openshift
22 | ```
23 |
24 | Über die Web Console kann dies mit dem "Developer Catalog" gemacht werden. Stellen Sie dafür sicher, dass Sie sich in der Developer-Ansicht befinden, klicken Sie auf "\+Add" und filtern Sie nach Type Template.
25 |
26 | Diese Templates können im JSON- oder YAML-Format sowohl im Git Repository neben Ihrem Source Code abgelegt werden als auch über eine URL aufgerufen oder gar lokal im Filesystem abgelegt sein.
27 |
28 |
29 | ## Aufgabe 1: Template instanzieren
30 |
31 | Die einzelnen Schritte die wir in den vorherigen Labs manuell vorgenommen haben, können nun mittels Template in einem "Rutsch" durchgeführt werden.
32 |
33 | Erstellen Sie ein neues Projekt mit Namen `[USERNAME]-template`.
34 |
35 | Tipp
oc new-project [USERNAME]-template
36 |
37 | Template erstellen:
38 |
39 | ```bash
40 | oc create -f https://raw.githubusercontent.com/appuio/example-spring-boot-helloworld/master/example-spring-boot-template.json
41 | ```
42 |
43 | Template instanzieren:
44 |
45 | ```bash
46 | oc new-app example-spring-boot
47 |
48 | --> Deploying template example-spring-boot for "example-spring-boot"
49 | With parameters:
50 | APPLICATION_DOMAIN=
51 | MYSQL_DATABASE_NAME=appuio
52 | MYSQL_USER=appuio
53 | MYSQL_PASSWORD=appuio
54 | MYSQL_DATASOURCE=jdbc:mysql://mysql/appuio?autoReconnect=true
55 | MYSQL_DRIVER=com.mysql.jdbc.Driver
56 | --> Creating resources ...
57 | imagestream "example-spring-boot" created
58 | deploymentconfig "example-spring-boot" created
59 | deploymentconfig "mysql" created
60 | route "example-spring-boot" created
61 | service "example-spring-boot" created
62 | service "mysql" created
63 | --> Success
64 | Run 'oc status' to view your app.
65 |
66 | ```
67 |
68 | Mittels folgendem Befehl wird das image importiert und das Deployment gestartet:
69 |
70 | ```bash
71 | oc import-image example-spring-boot
72 | ```
73 |
74 | Mit diesem Befehl wird die Datenbank ausgerollt:
75 |
76 | ```bash
77 | oc rollout latest mysql
78 | ```
79 |
80 | __Tipp__:
81 | Sie könnten Templates auch direkt verarbeiten indem Sie ein Template mit `oc new-app -f template.json -p param=value` ausführen.
82 |
83 | Als Abschluss dieses Labs können Sie sich noch das [Template](https://github.com/appuio/example-spring-boot-helloworld/blob/master/example-spring-boot-template.json) genauer anschauen.
84 |
85 | __Note__:
86 | Bestehende Ressourcen können als Template exportiert werden
87 | Verwenden Sie dafür den Befehl `oc get -o json` bzw `oc get -o yaml`.
88 |
89 | Bspw.:
90 |
91 | ```bash
92 | oc get is,bc,dc,route,service -o json > example-spring-boot-template.json
93 | ```
94 |
95 | Wichtig ist, dass die ImageStreams zuoberst im Template File definiert sind.
96 | Ansonsten wird der erste Build nicht funktionieren.
97 |
98 | ---
99 |
100 | __Ende Lab 12__
101 |
102 | Eigene Templates erstellen →
103 |
104 | [← zurück zur Übersicht](../README.md)
105 |
--------------------------------------------------------------------------------
/labs/13_template_creation.md:
--------------------------------------------------------------------------------
1 | # Lab 13: Eigene Templates erstellen
2 |
3 | Im Unterschied zu [Lab 12](12_template.md) schreiben wir hier unsere eigenen Templates bevor wir damit Applikationen erstellen.
4 |
5 |
6 | ## Hilfreiche `oc`-Befehle
7 |
8 | Auflisten aller Befehle:
9 |
10 | ```bash
11 | oc help
12 | ```
13 |
14 | Übersicht (fast) aller Ressourcen:
15 |
16 | ```bash
17 | oc get all
18 | ```
19 |
20 | Infos zu einer Ressource:
21 |
22 | ```bash
23 | oc get
24 | oc describe
25 | ```
26 |
27 |
28 | ## Generierung
29 |
30 | Über `oc new-app` oder "\+Add" in der Web Console werden die Ressourcen automatisch angelegt.
31 | In der Web Console kann die Erstellung einfach konfiguriert werden.
32 |
33 | Für den produktiven Einsatz reicht das meistens nicht aus.
34 | Da braucht es mehr Kontrolle über die Konfiguration.
35 | Eigene Templates sind hierfür die Lösung.
36 | Sie müssen jedoch nicht von Hand geschrieben sondern können als Vorlage generiert werden.
37 |
38 |
39 | ### Generierung vor Erstellung
40 |
41 | Mit `oc new-app` parst OpenShift die gegebenen Images, Templates, Source Code Repositories usw. und erstellt die Definition der verschiedenen Ressourcen.
42 | Mit der Option `-o` erhält man die Definition, ohne dass die Ressourcen angelegt werden.
43 |
44 | So sieht die Definition vom hello-world Image aus:
45 |
46 | ```bash
47 | oc new-app hello-world -o json
48 | ```
49 |
50 | Spannend ist auch zu beobachten, was OpenShift aus einem eigenen Projekt macht.
51 | Hierfür kann ein Git Repository oder ein lokaler Pfad des Rechners angeben werden.
52 |
53 | Beispiel-Befehl, wenn man sich im Root-Verzeichnis des Projekts befindet:
54 |
55 | ```bash
56 | oc new-app . -o json
57 | ```
58 |
59 | Wenn verschiedene ImageStreams in Frage kommen oder keiner gefunden wurde, muss er spezifiziert werden:
60 |
61 | ```bash
62 | oc new-app . --image-stream=wildfly:latest -o json
63 | ```
64 |
65 | `oc new-app` erstellt immer eine Liste von Ressourcen.
66 | Bei Bedarf kann eine solche mit [jq](https://stedolan.github.io/jq/) in ein Template konvertiert werden:
67 |
68 | ```bash
69 | oc new-app . --image-stream=wildfly:latest -o json | \
70 | jq '{ kind: "Template", apiVersion: .apiVersion, metadata: {name: "mytemplate" }, objects: .items }'
71 | ```
72 |
73 |
74 | ### Generierung nach Erstellung
75 |
76 | Bestehende Ressourcen werden mit `oc get -o json` bzw `oc get -o yaml` exportiert.
77 |
78 | ```bash
79 | oc get route my-route -o json
80 | ```
81 |
82 | Welche Ressourcen braucht es?
83 |
84 | Für ein vollständiges Template sind folgende Ressourcen notwendig:
85 |
86 | - ImageStreams
87 | - BuildConfigurations
88 | - DeploymentConfigurations
89 | - PersistentVolumeClaims
90 | - Routes
91 | - Services
92 |
93 | Beispiel-Befehl um einen Export der wichtigsten Ressourcen als Template zu generieren:
94 |
95 | ```bash
96 | oc get is,bc,pvc,dc,route,service -o json > my-template.json
97 | ```
98 |
99 | Attribute mit Wert `null` sowie die Annotation `openshift.io/generated-by` dürfen aus dem Template entfernt werden.
100 |
101 |
102 | ### Vorhandene Templates exportieren
103 |
104 | Es können auch bestehende Templates der Plattform abgeholt werden um eigene Templates zu erstellen.
105 |
106 | Verfügbare Templates sind im Projekt `openshift` hinterlegt.
107 | Diese können wie folgt aufgelistet werden:
108 |
109 | ```bash
110 | oc get templates -n openshift
111 | ```
112 |
113 | So erhalten wir eine Kopie vom eap70-mysql-persistent-s2i Template:
114 |
115 | ```bash
116 | oc get template eap72-mysql-persistent-s2i -o json -n openshift > eap72-mysql-persistent-s2i.json
117 | ```
118 |
119 |
120 | ## Parameter
121 |
122 | Damit die Applikationen für die eigenen Bedürfnisse angepasst werden können, gibt es Parameter.
123 | Generierte oder exportierte Templates sollten fixe Werte wie Hostnamen oder Passwörter durch Parameter ersetzen.
124 |
125 |
126 | ### Parameter von Templates anzeigen
127 |
128 | Mit `oc process --parameters` werden die Parameter eines Templates angezeigt. Hier wollen wir sehen, welche Paramter im CakePHP MySQL Template definiert sind:
129 |
130 | ```bash
131 | oc process --parameters cakephp-mysql-example -n openshift
132 | NAME DESCRIPTION GENERATOR VALUE
133 | NAME The name assigned to all of the frontend objects defined in this template. cakephp-mysql-example
134 | NAMESPACE The OpenShift Namespace where the ImageStream resides. openshift
135 | MEMORY_LIMIT Maximum amount of memory the CakePHP container can use. 512Mi
136 | MEMORY_MYSQL_LIMIT Maximum amount of memory the MySQL container can use. 512Mi
137 | ...
138 | ```
139 |
140 |
141 | ### Parameter von Templates mit Werten ersetzen
142 |
143 | Für die Erzeugung der Applikationen können gewünschte Parameter mit Werten ersetzt werden.
144 | Dazu verwenden wir `oc process`:
145 |
146 | ```bash
147 | oc process -f eap70-mysql-persistent-s2i.json \
148 | -v PARAM1=value1,PARAM2=value2 > processed-template.json
149 | ```
150 |
151 | So werden Parameter vom Template mit den gegebenen Werten ersetzt und in eine neue Datei geschrieben. Diese Datei wird eine Liste von Resources/Items sein, welche mit `oc create` erstellt werden können:
152 |
153 | ```bash
154 | oc create -f processed-template.json
155 | ```
156 |
157 | Dies kann auch in einem Schritt erledigt werden:
158 |
159 | ```bash
160 | oc process -f eap72-mysql-persistent-s2i.json \
161 | -v PARAM1=value1,PARAM2=value2 \
162 | | oc create -f -
163 | ```
164 |
165 |
166 | ## Templates schreiben
167 |
168 | OpenShift Dokumentation:
169 |
170 | Applikationen sollten so gebaut werden, dass sich pro Umgebung nur ein paar Konfigurationen unterscheiden.
171 | Diese Werte werden im Template als Parameter definiert.
172 | Somit ist der erste Schritt nach dem Generieren einer Template-Definition das Definieren von Parametern.
173 | Das Template wird mit Variablen erweitert, welche dann mit den Parameterwerten ersetzt werden.
174 | So wird bspw. die Variable `${DB_PASSWORD}` durch den Parameter mit Namen `DB_PASSWORD` ersetzt.
175 |
176 |
177 | ### Generierte Parameter
178 |
179 | Oft werden Passwörter automatisch generiert, da der Wert nur im OpenShift Projekt verwendet wird.
180 | Dies kann mit einer "generate"-Definition erreicht werden.
181 |
182 | ```
183 | parameters:
184 | - name: DB_PASSWORD
185 | description: "DB connection password"
186 | generate: expression
187 | from: "[a-zA-Z0-9]{13}"
188 | ```
189 |
190 | Diese Definition würde ein zufälliges, 13 Zeichen langes Passwort mit Klein- und Grossbuchstaben sowie Zahlen generieren.
191 |
192 | Auch wenn ein Parameter mit "generate"-Definition konfiguriert ist, kann er bei der Erzeugung überschrieben werden.
193 |
194 |
195 | ### Template Merge
196 |
197 | Wenn z.B eine App mit einer Datenbank zusammen verwendet wird, können die zwei Templates zusammengelegt werden.
198 | Dabei ist es wichtig, die Template Parameter zu konsolidieren.
199 | Dies sind meistens Werte für die Anbindung der Datenbank.
200 | Dabei einfach in beiden Templates die gleiche Variable vom gemeinsamen Parameter verwenden.
201 |
202 |
203 | ## Anwenden vom Templates
204 |
205 | Templates können mit `oc new-app -f | -p =,=...` instanziert werden.
206 | Wenn die Parameter des Templates bereits mit `oc process` gesetzt wurden, braucht es die Angabe der Parameter nicht mehr.
207 |
208 | ---
209 |
210 | __Ende Lab 13__
211 |
212 | [← zurück zur Übersicht](../README.md)
213 |
--------------------------------------------------------------------------------
/labs/data/08_dump/dump.sql:
--------------------------------------------------------------------------------
1 | -- MySQL dump 10.13 Distrib 5.6.26, for Linux (x86_64)
2 | --
3 | -- Host: 172.30.251.42 Database: appuio
4 | -- ------------------------------------------------------
5 | -- Server version 5.6.26
6 |
7 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
8 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
9 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
10 | /*!40101 SET NAMES utf8 */;
11 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
12 | /*!40103 SET TIME_ZONE='+00:00' */;
13 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
14 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
15 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
16 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
17 |
18 | --
19 | -- Table structure for table `DATABASECHANGELOG`
20 | --
21 |
22 | DROP TABLE IF EXISTS `DATABASECHANGELOG`;
23 | /*!40101 SET @saved_cs_client = @@character_set_client */;
24 | /*!40101 SET character_set_client = utf8 */;
25 | CREATE TABLE `DATABASECHANGELOG` (
26 | `ID` varchar(255) NOT NULL,
27 | `AUTHOR` varchar(255) NOT NULL,
28 | `FILENAME` varchar(255) NOT NULL,
29 | `DATEEXECUTED` datetime NOT NULL,
30 | `ORDEREXECUTED` int(11) NOT NULL,
31 | `EXECTYPE` varchar(10) NOT NULL,
32 | `MD5SUM` varchar(35) DEFAULT NULL,
33 | `DESCRIPTION` varchar(255) DEFAULT NULL,
34 | `COMMENTS` varchar(255) DEFAULT NULL,
35 | `TAG` varchar(255) DEFAULT NULL,
36 | `LIQUIBASE` varchar(20) DEFAULT NULL,
37 | `CONTEXTS` varchar(255) DEFAULT NULL,
38 | `LABELS` varchar(255) DEFAULT NULL
39 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
40 | /*!40101 SET character_set_client = @saved_cs_client */;
41 |
42 | --
43 | -- Dumping data for table `DATABASECHANGELOG`
44 | --
45 |
46 | LOCK TABLES `DATABASECHANGELOG` WRITE;
47 | /*!40000 ALTER TABLE `DATABASECHANGELOG` DISABLE KEYS */;
48 | INSERT INTO `DATABASECHANGELOG` VALUES ('1-createTableHello','appuio','classpath:/db/changelog/db.changelog-master.xml','2016-05-16 16:09:53',1,'EXECUTED','7:8c8aeb9c1a4d95f689e5d7294e59c1bd','createTable','',NULL,'3.4.2',NULL,NULL),('2-initialdata','appuio','db/changelog/initialdata/initialdata.xml','2016-05-16 16:09:53',2,'EXECUTED','7:9fce892573b2cd006863ec69301865db','insert','',NULL,'3.4.2',NULL,NULL);
49 | /*!40000 ALTER TABLE `DATABASECHANGELOG` ENABLE KEYS */;
50 | UNLOCK TABLES;
51 |
52 | --
53 | -- Table structure for table `DATABASECHANGELOGLOCK`
54 | --
55 |
56 | DROP TABLE IF EXISTS `DATABASECHANGELOGLOCK`;
57 | /*!40101 SET @saved_cs_client = @@character_set_client */;
58 | /*!40101 SET character_set_client = utf8 */;
59 | CREATE TABLE `DATABASECHANGELOGLOCK` (
60 | `ID` int(11) NOT NULL,
61 | `LOCKED` bit(1) NOT NULL,
62 | `LOCKGRANTED` datetime DEFAULT NULL,
63 | `LOCKEDBY` varchar(255) DEFAULT NULL,
64 | PRIMARY KEY (`ID`)
65 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
66 | /*!40101 SET character_set_client = @saved_cs_client */;
67 |
68 | --
69 | -- Dumping data for table `DATABASECHANGELOGLOCK`
70 | --
71 |
72 | LOCK TABLES `DATABASECHANGELOGLOCK` WRITE;
73 | /*!40000 ALTER TABLE `DATABASECHANGELOGLOCK` DISABLE KEYS */;
74 | INSERT INTO `DATABASECHANGELOGLOCK` VALUES (1,'\0',NULL,NULL);
75 | /*!40000 ALTER TABLE `DATABASECHANGELOGLOCK` ENABLE KEYS */;
76 | UNLOCK TABLES;
77 |
78 | --
79 | -- Table structure for table `hello`
80 | --
81 |
82 | DROP TABLE IF EXISTS `hello`;
83 | /*!40101 SET @saved_cs_client = @@character_set_client */;
84 | /*!40101 SET character_set_client = utf8 */;
85 | CREATE TABLE `hello` (
86 | `id` bigint(20) NOT NULL AUTO_INCREMENT,
87 | `name` varchar(255) NOT NULL,
88 | `frontend` varchar(50) DEFAULT NULL,
89 | `created` timestamp NULL DEFAULT NULL,
90 | PRIMARY KEY (`id`)
91 | ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1 COMMENT='A String';
92 | /*!40101 SET character_set_client = @saved_cs_client */;
93 |
94 | --
95 | -- Dumping data for table `hello`
96 | --
97 |
98 | LOCK TABLES `hello` WRITE;
99 | /*!40000 ALTER TABLE `hello` DISABLE KEYS */;
100 | INSERT INTO `hello` VALUES (1,'Test',NULL,NULL),(2,'APPUiO','example-spring-boot-2-f2jsi','2016-05-17 00:10:46'),(3,'Puzzle','example-spring-boot-2-f2jsi','2016-05-17 00:10:52'),(4,'Bern','example-spring-boot-2-f2jsi','2016-05-17 00:10:58'),(5,'Zürich','example-spring-boot-2-f2jsi','2016-05-17 00:11:02'),(6,'CH','example-spring-boot-2-f2jsi','2016-05-17 00:11:06'),(7,'APPUiO','example-spring-boot-2-f2jsi','2016-05-17 00:11:38'),(8,'Puzzle','example-spring-boot-2-f2jsi','2016-05-17 00:12:00');
101 | /*!40000 ALTER TABLE `hello` ENABLE KEYS */;
102 | UNLOCK TABLES;
103 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
104 |
105 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
106 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
107 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
108 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
109 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
110 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
111 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
112 |
113 | -- Dump completed on 2016-05-16 16:17:42
114 |
--------------------------------------------------------------------------------