├── .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 |
Tippoc 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 |
Tippoc 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 |
Tippoc 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 | ![Jenkins OAuth2 Login](../images/jenkins_oauth2_login.png "Jenkins OAuth2 Login") 41 | 42 | Danach wird ein Berechtigungs-Bildschirm angezeigt, in dem Sie nach Autorisierungs-Berechtigungen gefragt werden. 43 | Siehe das Bild unten. 44 | 45 | ![Jenkins OAuth2 permissions](../images/jenkins_oauth2_permissions.png "Jenkins OAuth2 permissions") 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 | ![Jenkins welcome](../images/pipeline-jenkins-overview.png "Jenkins welcome") 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 | ![Start Pipeline](../images/openshift-pipeline-start.png) 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 | ![Run Pipeline](../images/openshift-pipeline-run.png) 69 | 70 | Die gleichen Informationen sind auch im Jenkins GUI zu sehen. 71 | 72 | ![Run Pipeline Jenkins](../images/openshift-pipeline-jenkins-view-run.png) 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 |
TippAdministrator 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 | ![CustomSlave Pipeline Jenkins](../images/pipeline-jenkins-custom-podtemplate.png) 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 | ![Run Pipeline Jenkins](../images/openshift-pipeline-rollout.png) 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ösungoc 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 |
Befehloc 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 Befehloc describe [RESOURCE_TYPE] [RESOURCE_NAME] -n openshift-web-console
113 |
Befehl zum Überprüfen eines Serviceoc 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 |
Befehloc 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 Projektsoc 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 Appoc 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 |
Projektstatusbefehloc 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 Projektsoc 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 erstellenoc 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 |
Tippoc 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 Befehlgit 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 |
Tippoc 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 |
Tippoc new-app spring-boot -l app=spring-boot

114 | 115 | ### Route erstellen 116 | 117 | Den Service der Applikation als Route exposen. 118 | 119 |
Tippoc 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 |
Tippoc 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 |
Tippoc 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 abfragenoc 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 Projektsoc 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 Applikationoc 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 Sucheoc 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ösungk8s-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 | ![oc-login](../images/lab_03_login.png) 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 |
Tippoc 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 |
Tippoc 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 |
Tippoc 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 |
Tippoc 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 |
Tippoc 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 |
Tippoc 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 |
Tippoc 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 |
Tippoc 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 |
Tippoc 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 | ![MariaDBService](../images/lab_08_mariadb.png) 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 |
Tippselect * 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 |
Tippmysql -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 |
Tippoc 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 | ![Fork](../images/lab_09_fork_example.png) 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 |
Tippoc 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 Befehloc 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 | ![Webhook](../images/lab_09_webhook_ocp4.png) 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 | ![Github Webhook](../images/lab_09_webhook_github1.png) 65 | 66 | Klicken Sie auf Webhooks: 67 | ![Github Webhook](../images/lab_09_webhook_github2.png) 68 | 69 | Fügen Sie einen Webhook hinzu: 70 | ![Github Webhook](../images/lab_09_webhook_github3.png) 71 | 72 | Fügen Sie nun die kopierte GitHub Webhook URL ein: 73 | ![Github Webhook](../images/lab_09_webhook_github4.png) 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 | ![Github Webhook](../images/lab_09_codechange1.png) 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 | ![Github Webhook](../images/lab_09_edit_on_github.png) 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 |
Tippoc 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 | --------------------------------------------------------------------------------