├── lab ├── generate-html.sh ├── images │ ├── build.png │ ├── pod.png │ ├── k8slogo.png │ ├── openshift.png │ ├── app-diagram.png │ ├── app-screenshot.png │ ├── helloworldmsa.png │ ├── rolling-update.png │ └── vagrant-windows-git.png ├── pull-images.sh ├── includes │ └── tip.adoc ├── feedback.adoc ├── docker-image-minishift.adoc ├── configuring-application.adoc ├── app-application-source.adoc ├── references.adoc ├── app-frontend-service.adoc ├── graceful-shutdown.adoc ├── configuring-envvars.adoc ├── troubleshooting.adoc ├── app-deploy-mysql-and-service.adoc ├── configuring-argument.adoc ├── rolling-update.adoc ├── setup-environment.adoc ├── autoscaling.adoc ├── readme.adoc ├── preface.adoc ├── scaling.adoc ├── app-frontend-deployment.adoc ├── health-checks.adoc ├── app-deploy-microservices-networking.adoc ├── external-access.adoc ├── app-deploy-microservices.adoc ├── configuring-configmap.adoc ├── managing-credentials.adoc ├── extra.adoc └── openshift.adoc ├── helloworld-service ├── config.json ├── builddocker.sh ├── Readme.md ├── Dockerfile ├── src │ └── main │ │ └── java │ │ └── com │ │ └── redhat │ │ └── developers │ │ └── helloworld │ │ ├── HelloworldVerticle.java │ │ └── ApplicationConfiguration.java └── pom.xml ├── frontend ├── builddocker.sh ├── package.json ├── Dockerfile ├── scripts │ └── page.js ├── frontend.js └── index.html ├── guestbook-service ├── builddocker.sh ├── src │ └── main │ │ ├── resources │ │ ├── META-INF │ │ │ ├── apache-deltaspike.properties │ │ │ ├── beans.xml │ │ │ └── persistence.xml │ │ ├── modules │ │ │ └── com │ │ │ │ └── mysql │ │ │ │ └── main │ │ │ │ └── module.xml │ │ └── import.sql │ │ └── java │ │ └── com │ │ └── redhat │ │ └── developers │ │ └── guestbook │ │ ├── rest │ │ ├── CorsFilter.java │ │ ├── JaxRsActivator.java │ │ ├── MessageResource.java │ │ └── BadwordFilter.java │ │ ├── data │ │ ├── MessageRepository.java │ │ └── Message.java │ │ ├── Resources.java │ │ └── Main.java ├── Readme.md ├── Dockerfile └── pom.xml ├── openshift └── setup-pv.sh ├── README.md ├── kubernetes ├── mysql-pv.yaml ├── mysql-pvc.yaml ├── guestbookservice-service.yaml ├── helloworldservice-service.yaml ├── frontend-service.yaml ├── mysql-service.yaml ├── frontend-deployment.yaml ├── guestbookservice-deployment.yaml ├── helloworldservice-deployment.yaml └── mysql-deployment.yaml └── LICENSE /lab/generate-html.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | asciidoctor readme.adoc 4 | open readme.html -------------------------------------------------------------------------------- /helloworld-service/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "GREETING": "Hello {name} from {hostname} from ConfigMap" 3 | } 4 | -------------------------------------------------------------------------------- /lab/images/build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer-demos/kubernetes-lab/HEAD/lab/images/build.png -------------------------------------------------------------------------------- /lab/images/pod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer-demos/kubernetes-lab/HEAD/lab/images/pod.png -------------------------------------------------------------------------------- /lab/images/k8slogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer-demos/kubernetes-lab/HEAD/lab/images/k8slogo.png -------------------------------------------------------------------------------- /lab/images/openshift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer-demos/kubernetes-lab/HEAD/lab/images/openshift.png -------------------------------------------------------------------------------- /lab/images/app-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer-demos/kubernetes-lab/HEAD/lab/images/app-diagram.png -------------------------------------------------------------------------------- /lab/images/app-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer-demos/kubernetes-lab/HEAD/lab/images/app-screenshot.png -------------------------------------------------------------------------------- /lab/images/helloworldmsa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer-demos/kubernetes-lab/HEAD/lab/images/helloworldmsa.png -------------------------------------------------------------------------------- /lab/images/rolling-update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer-demos/kubernetes-lab/HEAD/lab/images/rolling-update.png -------------------------------------------------------------------------------- /frontend/builddocker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | name='rafabene/microservices-frontend:1.0' 3 | docker build -t $name . 4 | echo "Image $name built" -------------------------------------------------------------------------------- /lab/images/vagrant-windows-git.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer-demos/kubernetes-lab/HEAD/lab/images/vagrant-windows-git.png -------------------------------------------------------------------------------- /guestbook-service/builddocker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | name='rafabene/microservices-guestbook:1.0' 3 | mvn clean package; docker build -t $name . 4 | echo "Image $name built" -------------------------------------------------------------------------------- /helloworld-service/builddocker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | name='rafabene/microservices-helloworld-vertx:1.0' 3 | mvn clean package; docker build -t $name . 4 | echo "Image $name built" -------------------------------------------------------------------------------- /guestbook-service/src/main/resources/META-INF/apache-deltaspike.properties: -------------------------------------------------------------------------------- 1 | globalAlternatives.org.apache.deltaspike.jpa.spi.transaction.TransactionStrategy=org.apache.deltaspike.jpa.impl.transaction.BeanManagedUserTransactionStrategy 2 | -------------------------------------------------------------------------------- /lab/pull-images.sh: -------------------------------------------------------------------------------- 1 | docker pull rafabene/microservices-frontend:1.0 2 | docker pull rafabene/microservices-helloworld-vertx:1.0 3 | docker pull rafabene/microservices-guestbook:1.0 4 | docker pull openshift3/nodejs-010-rhel7 5 | docker pull openshift/mysql-56-centos7 6 | docker pull openshift/nodejs-010-centos7 7 | docker pull openshift/origin-sti-builder:v1.4.1 8 | -------------------------------------------------------------------------------- /helloworld-service/Readme.md: -------------------------------------------------------------------------------- 1 | # Helloworld-service 2 | 3 | Build and Deploy helloworld-service locally 4 | ------------------------------------------ 5 | 6 | 1. Open a command prompt and navigate to the root directory of this microservice. 7 | 2. Type this command to build and execute the service: 8 | 9 | mvn clean compile exec:java 10 | 11 | 3. The application will be running at the following URL: -------------------------------------------------------------------------------- /openshift/setup-pv.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | for i in {1..1}; do 3 | echo "Creating Google disk $i"; 4 | gcloud compute disks create pd-disk-$i --size 1GB --type=pd-ssd; 5 | cat < -------------------------------------------------------------------------------- /guestbook-service/src/main/resources/modules/com/mysql/main/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /guestbook-service/src/main/java/com/redhat/developers/guestbook/rest/CorsFilter.java: -------------------------------------------------------------------------------- 1 | package com.redhat.developers.guestbook.rest; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.ws.rs.container.ContainerRequestContext; 6 | import javax.ws.rs.container.ContainerResponseContext; 7 | import javax.ws.rs.container.ContainerResponseFilter; 8 | import javax.ws.rs.ext.Provider; 9 | 10 | @Provider 11 | public class CorsFilter implements ContainerResponseFilter { 12 | 13 | @Override 14 | public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException { 15 | responseContext.getHeaders().add("Access-Control-Allow-Origin", "*"); 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "1.0.0", 4 | "description": "Frontend for Greeting and Helloworld microservices", 5 | "main": "frontend.js", 6 | "scripts": { 7 | "start": "node frontend.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/redhat-developer-demos/kubernetes-lab.git" 12 | }, 13 | "author": "Red Hat Developers", 14 | "license": "Apache-2.0", 15 | "bugs": { 16 | "url": "https://github.com/redhat-developer-demos/kubernetes-lab/issues" 17 | }, 18 | "homepage": "https://github.com/redhat-developer-demos/kubernetes-lab#readme", 19 | "dependencies": { 20 | "body-parser": "^1.15.1", 21 | "bootstrap": "~3.3.5", 22 | "express": "^4.13.4", 23 | "jquery": "~3.0.0", 24 | "patternfly": "^3.3.3", 25 | "request": "^2.72.0" 26 | }, 27 | "optionalDependencies": { 28 | "phantomjs": "~1.9" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lab/includes/tip.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | [TIP] 17 | ==== 18 | HINT 1: Type *'i'* to enter in edit mode 19 | 20 | HINT 2: Type *':wq'* to exit from vi 21 | ==== -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kubernetes Lab 2 | 3 | This lab is inspired in [Google's Kubernetes lab](http://bit.ly/k8s-lab) by [Ray Tsang](https://twitter.com/saturnism). However, this version uses [Red Hat's CDK](http://developers.redhat.com/products/cdk/overview/) - Container Development Kit, allowing users to try the lab localy, and also try the same lab in [OpenShift](https://www.openshift.com/). 4 | 5 | Furthermore, the microservices use: [WildFly Swarm](http://wildfly-swarm.io/) - A Java [microprofile](http://microprofile.io/) server, and [Vert.x](http://vertx.io/) - A a tool-kit for building reactive applications on the JVM. 6 | 7 | - [Lab Sources](lab/) 8 | - [Frontend source code](frontend/) 9 | - [Helloworld Microservice - implemented using Vert.x](helloworld-service/) 10 | - [Guestbook Microservice - implemented using WildFly Swarm](guestbook-service/) 11 | - [Kubernetes files](kubernetes/) 12 | 13 | The latest HTML version of this Lab is available [here](http://bit.ly/kubernetes-lab) 14 | 15 | -------------------------------------------------------------------------------- /frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | # JBoss, Home of Professional Open Source 2 | # Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | # contributors by the @authors tag. See the copyright.txt in the 4 | # distribution for a full listing of individual contributors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | FROM bucharestgold/centos7-s2i-nodejs:10.x 17 | 18 | ADD . /opt/app-root/src/ 19 | 20 | WORKDIR /opt/app-root/src 21 | 22 | RUN ["/bin/bash", "-c", "npm install"] 23 | 24 | EXPOSE 8080 25 | 26 | CMD /bin/bash -c 'npm start' -------------------------------------------------------------------------------- /guestbook-service/Dockerfile: -------------------------------------------------------------------------------- 1 | # JBoss, Home of Professional Open Source 2 | # Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | # contributors by the @authors tag. See the copyright.txt in the 4 | # distribution for a full listing of individual contributors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | FROM fabric8/java-jboss-openjdk8-jdk:1.1.7 17 | 18 | ENV JAVA_APP_JAR guestbook-service-swarm.jar 19 | ENV AB_OFF true 20 | ENV JAVA_OPTIONS -Xmx512m 21 | 22 | EXPOSE 8080 23 | 24 | ADD target/guestbook-service-swarm.jar /app/ -------------------------------------------------------------------------------- /kubernetes/mysql-pv.yaml: -------------------------------------------------------------------------------- 1 | # JBoss, Home of Professional Open Source 2 | # Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | # contributors by the @authors tag. See the copyright.txt in the 4 | # distribution for a full listing of individual contributors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | apiVersion: v1 16 | kind: PersistentVolume 17 | metadata: 18 | name: pv001 19 | spec: 20 | capacity: 21 | storage: 1Gi 22 | accessModes: 23 | - ReadWriteOnce 24 | persistentVolumeReclaimPolicy: Recycle 25 | hostPath: 26 | path: /data/pv001 -------------------------------------------------------------------------------- /guestbook-service/src/main/resources/import.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- JBoss, Home of Professional Open Source 3 | -- Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 4 | -- contributors by the @authors tag. See the copyright.txt in the 5 | -- distribution for a full listing of individual contributors. 6 | -- 7 | -- Licensed under the Apache License, Version 2.0 (the "License"); 8 | -- you may not use this file except in compliance with the License. 9 | -- You may obtain a copy of the License at 10 | -- http://www.apache.org/licenses/LICENSE-2.0 11 | -- Unless required by applicable law or agreed to in writing, software 12 | -- distributed under the License is distributed on an "AS IS" BASIS, 13 | -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | -- See the License for the specific language governing permissions and 15 | -- limitations under the License. 16 | -- 17 | 18 | -- You can use this file to load seed data into the database using SQL statements 19 | insert into Message (id, username, message, timestamp) values (99999, 'Benevides', 'Hello World', '2015-06-10 22:10:00'); -------------------------------------------------------------------------------- /kubernetes/mysql-pvc.yaml: -------------------------------------------------------------------------------- 1 | # JBoss, Home of Professional Open Source 2 | # Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | # contributors by the @authors tag. See the copyright.txt in the 4 | # distribution for a full listing of individual contributors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | kind: PersistentVolumeClaim 17 | apiVersion: v1 18 | metadata: 19 | name: mysql-pvc 20 | labels: 21 | app: mysql 22 | lab: kubernetes-lab 23 | spec: 24 | accessModes: 25 | - ReadWriteOnce 26 | resources: 27 | requests: 28 | storage: 1Gi -------------------------------------------------------------------------------- /kubernetes/guestbookservice-service.yaml: -------------------------------------------------------------------------------- 1 | # JBoss, Home of Professional Open Source 2 | # Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | # contributors by the @authors tag. See the copyright.txt in the 4 | # distribution for a full listing of individual contributors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | kind: Service 17 | apiVersion: v1 18 | metadata: 19 | name: guestbook-service 20 | labels: 21 | app: guestbook-service 22 | lab: kubernetes-lab 23 | spec: 24 | ports: 25 | - port: 8080 26 | targetPort: 8080 27 | selector: 28 | app: guestbook-service -------------------------------------------------------------------------------- /kubernetes/helloworldservice-service.yaml: -------------------------------------------------------------------------------- 1 | # JBoss, Home of Professional Open Source 2 | # Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | # contributors by the @authors tag. See the copyright.txt in the 4 | # distribution for a full listing of individual contributors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | kind: Service 17 | apiVersion: v1 18 | metadata: 19 | name: helloworld-service-vertx 20 | labels: 21 | app: helloworld-service-vertx 22 | lab: kubernetes-lab 23 | spec: 24 | ports: 25 | - port: 8080 26 | targetPort: 8080 27 | selector: 28 | app: helloworld-service-vertx -------------------------------------------------------------------------------- /kubernetes/frontend-service.yaml: -------------------------------------------------------------------------------- 1 | # JBoss, Home of Professional Open Source 2 | # Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | # contributors by the @authors tag. See the copyright.txt in the 4 | # distribution for a full listing of individual contributors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | kind: Service 17 | apiVersion: v1 18 | metadata: 19 | name: frontend-ui 20 | labels: 21 | app: frontend-ui 22 | lab: kubernetes-lab 23 | spec: 24 | type: LoadBalancer 25 | ports: 26 | - port: 80 27 | name: http-80 28 | targetPort: http 29 | selector: 30 | app: frontend-ui -------------------------------------------------------------------------------- /kubernetes/mysql-service.yaml: -------------------------------------------------------------------------------- 1 | # JBoss, Home of Professional Open Source 2 | # Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | # contributors by the @authors tag. See the copyright.txt in the 4 | # distribution for a full listing of individual contributors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | apiVersion: v1 17 | kind: Service 18 | metadata: 19 | name: mysql 20 | labels: 21 | app: mysql 22 | lab: kubernetes-lab 23 | spec: 24 | ports: 25 | # the port that this service should serve on 26 | - port: 3306 27 | # label keys and values that must match in order to receive traffic for this service 28 | selector: 29 | app: mysql -------------------------------------------------------------------------------- /helloworld-service/Dockerfile: -------------------------------------------------------------------------------- 1 | # JBoss, Home of Professional Open Source 2 | # Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | # contributors by the @authors tag. See the copyright.txt in the 4 | # distribution for a full listing of individual contributors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | FROM fabric8/java-jboss-openjdk8-jdk:1.1.7 17 | 18 | ENV JAVA_APP_JAR helloworld-service-fat.jar 19 | ENV AB_OFF true 20 | 21 | ADD target/helloworld-service-fat.jar /app/ 22 | ADD config.json /app/ 23 | 24 | EXPOSE 8080 25 | CMD [] 26 | 27 | ENTRYPOINT ["java", "-Dvertx.disableFileCPResolving=true", "-Xmx256m", "-jar", "/app/helloworld-service-fat.jar"] 28 | 29 | -------------------------------------------------------------------------------- /lab/feedback.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | ## Codelab feedback 17 | 18 | **** 19 | - The codelab was easy and useful 20 | - The codelab was too complicated 21 | - The codelab didn’t go far enough 22 | - I had some technical difficulties 23 | **** 24 | 25 | If you find any issues, report it in the link:https://github.com/redhat-developer-demos/kubernetes-lab/issues[Github repository]. You're also welcome to send any link:https://help.github.com/articles/using-pull-requests/[pull requests] and contributions. -------------------------------------------------------------------------------- /lab/docker-image-minishift.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | Minishift allows the developer to have access to the internal docker daemon and registry. With the access to the internal docker daemon, you can build a new version of the image and make it available in the internal registry. 17 | 18 | To access the internal docker daemon run the following command: 19 | 20 | [source,bash, subs="normal,attributes"] 21 | ---- 22 | $ eval $(minishift docker-env) 23 | ---- 24 | 25 | Now you can buid the docker image and it will be automatically avaible in the docker registry of minishift. -------------------------------------------------------------------------------- /guestbook-service/src/main/java/com/redhat/developers/guestbook/data/MessageRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JBoss, Home of Professional Open Source 3 | * Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 4 | * contributors by the @authors tag. See the copyright.txt in the 5 | * distribution for a full listing of individual contributors. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.redhat.developers.guestbook.data; 18 | 19 | import java.util.List; 20 | 21 | import org.apache.deltaspike.data.api.EntityRepository; 22 | import org.apache.deltaspike.data.api.Query; 23 | import org.apache.deltaspike.data.api.Repository; 24 | 25 | @Repository 26 | public interface MessageRepository extends EntityRepository { 27 | 28 | @Query("SELECT m FROM Message m ORDER BY m.timestamp DESC") 29 | List findAllOrdered(); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /kubernetes/frontend-deployment.yaml: -------------------------------------------------------------------------------- 1 | # JBoss, Home of Professional Open Source 2 | # Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | # contributors by the @authors tag. See the copyright.txt in the 4 | # distribution for a full listing of individual contributors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | apiVersion: extensions/v1beta1 17 | kind: Deployment 18 | metadata: 19 | name: frontend-ui 20 | labels: 21 | app: frontend-ui 22 | lab: kubernetes-lab 23 | spec: 24 | replicas: 2 25 | selector: 26 | matchLabels: 27 | app: frontend-ui 28 | template: 29 | metadata: 30 | labels: 31 | app: frontend-ui 32 | lab: kubernetes-lab 33 | spec: 34 | containers: 35 | - name: frontend-ui 36 | image: rafabene/microservices-frontend:1.0 37 | ports: 38 | - name: http 39 | containerPort: 8080 -------------------------------------------------------------------------------- /lab/configuring-application.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | ### Configuring Your Application 17 | Duration: 20:00 18 | 19 | The Helloworld Service is configured to return a message that uses the following template: 20 | [source,subs="normal,attributes"] 21 | ---- 22 | Hello {name} from {hostname} with {version} 23 | ---- 24 | 25 | There are several ways to update this configuration. We'll go through a couple of them, including: 26 | 27 | * Environment variable 28 | * Command line argument 29 | * And, ConfigMap 30 | 31 | include::configuring-envvars.adoc[] 32 | 33 | // include::configuring-argument.adoc[] 34 | 35 | include::configuring-configmap.adoc[] 36 | 37 | -------------------------------------------------------------------------------- /kubernetes/guestbookservice-deployment.yaml: -------------------------------------------------------------------------------- 1 | # JBoss, Home of Professional Open Source 2 | # Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | # contributors by the @authors tag. See the copyright.txt in the 4 | # distribution for a full listing of individual contributors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | apiVersion: extensions/v1beta1 17 | kind: Deployment 18 | metadata: 19 | name: guestbook-service 20 | labels: 21 | app: guestbook-service 22 | lab: kubernetes-lab 23 | spec: 24 | replicas: 1 25 | selector: 26 | matchLabels: 27 | app: guestbook-service 28 | template: 29 | metadata: 30 | labels: 31 | app: guestbook-service 32 | lab: kubernetes-lab 33 | spec: 34 | containers: 35 | - name: guestbook-service 36 | image: rafabene/microservices-guestbook:1.0 37 | ports: 38 | - name: http 39 | containerPort: 8080 40 | -------------------------------------------------------------------------------- /kubernetes/helloworldservice-deployment.yaml: -------------------------------------------------------------------------------- 1 | # JBoss, Home of Professional Open Source 2 | # Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | # contributors by the @authors tag. See the copyright.txt in the 4 | # distribution for a full listing of individual contributors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | apiVersion: extensions/v1beta1 17 | kind: Deployment 18 | metadata: 19 | name: helloworld-service-vertx 20 | labels: 21 | app: helloworld-service-vertx 22 | lab: kubernetes-lab 23 | spec: 24 | replicas: 2 25 | selector: 26 | matchLabels: 27 | app: helloworld-service-vertx 28 | template: 29 | metadata: 30 | labels: 31 | app: helloworld-service-vertx 32 | lab: kubernetes-lab 33 | spec: 34 | containers: 35 | - name: helloworld-service-vertx 36 | image: rafabene/microservices-helloworld-vertx:1.0 37 | ports: 38 | - name: http 39 | containerPort: 8080 40 | -------------------------------------------------------------------------------- /guestbook-service/src/main/java/com/redhat/developers/guestbook/rest/JaxRsActivator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JBoss, Home of Professional Open Source 3 | * Copyright 2015, Red Hat, Inc. and/or its affiliates, and individual 4 | * contributors by the @authors tag. See the copyright.txt in the 5 | * distribution for a full listing of individual contributors. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.redhat.developers.guestbook.rest; 18 | 19 | import javax.ws.rs.ApplicationPath; 20 | import javax.ws.rs.core.Application; 21 | 22 | /** 23 | * A class extending {@link Application} and annotated with @ApplicationPath is 24 | * the Java EE 7 "no XML" approach to activating JAX-RS. 25 | * 26 | *

27 | * Resources are served relative to the servlet path specified in the 28 | * {@link ApplicationPath} annotation. 29 | *

30 | */ 31 | @ApplicationPath("/api") 32 | public class JaxRsActivator extends Application { 33 | /* class body intentionally left blank */ 34 | } -------------------------------------------------------------------------------- /guestbook-service/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 21 | 26 | 27 | org.apache.deltaspike.jpa.impl.transaction.BeanManagedUserTransactionStrategy 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /guestbook-service/src/main/resources/META-INF/persistence.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 17 | 18 | java:jboss/datasources/MySQLDS 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /lab/app-application-source.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | ### Get the Guestbook source 17 | Duration: 3:00 18 | 19 | Start by cloning the github repository for the Guestbook application and move into the kubernetes examples directory. 20 | 21 | [source, bash, subs="normal,attributes"] 22 | ---- 23 | $ *git clone https://github.com/redhat-developer-demos/kubernetes-lab* 24 | $ *cd kubernetes-lab/kubernetes* 25 | ---- 26 | 27 | Kubernetes resources can be specified using link:http://yaml.org/[yaml] or link:http://www.json.org/[json] formats. 28 | We will be using the yaml files in this directory to decribe and deploy the Kubernetes objects in our development environment. You are definitely encouraged to read them and see how pods, services, and others are declared. We’ll walk through a couple of these files in detail. 29 | 30 | -------------------------------------------------------------------------------- /lab/references.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | ## References 17 | 18 | - link:http://bit.ly/k8s-lab[Google's Kubernetes lab] by link:https://twitter.com/saturnism[Ray Tsang] 19 | - link:https://github.com/redhat-developer-demos/docker-java[docker for Java Developers] by link:https://twitter.com/rhdevelopers[Red Hat Developers] 20 | - link:https://docs.openshift.com/enterprise/3.2/welcome/index.html[OpenShift] docs 21 | - link:http://kubernetes.io/docs/[Kubernetes] docs 22 | - link:http://vertx.io/[Vert.X] - a tool-kit for building reactive applications on the JVM 23 | - link:http://wildfly-swarm.io/[WildFly Swarm] - A link:http://microprofile.io/[Microprofile] application server 24 | - Red Hat's link:http://developers.redhat.com/products/cdk/[CDK] - Container Development Kit 25 | - link:https://github.com/redhat-helloworld-msa/helloworld-msa[Helloworld-MSA] - Your microservices sandbox in CDK. -------------------------------------------------------------------------------- /lab/app-frontend-service.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | ### Deploy a frontend Service 17 | Duration 3:00 18 | 19 | Each Pod has a unique IP address - but the address is ephemeral. The Pod IP addresses are not stable and it can change when Pods start and/or restart. A service provides a single access point to a set of pods matching some constraints. A Service IP address is stable. 20 | 21 | Create the frontend service: 22 | 23 | [source, bash, subs="normal,attributes"] 24 | ---- 25 | $ *kubectl create -f frontend-service.yaml* 26 | service/frontend-ui created 27 | ---- 28 | 29 | And check it: 30 | 31 | [source, bash, subs="normal,attributes"] 32 | ---- 33 | $ *kubectl get services* 34 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 35 | frontend-ui LoadBalancer 172.30.58.95 172.29.26.18,172.29.26.18 80:31391/TCP 8s 36 | ---- 37 | 38 | -------------------------------------------------------------------------------- /lab/graceful-shutdown.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | ### Graceful Shutdown 17 | Duration: 5:00 18 | 19 | When a pod needs to be deleted (such as reducing the number of replicas), Kubernetes will send the SIGTERM signal to the process. The process should perform all the cleanups. However, we cannot wait forever for the process to exit. By default, Kubernetes waits 30 seconds before sending the final SIGKILL signal to kill the process. If your process needs more or less time, you can configure this through termination grace periods configuration (see link:http://kubernetes.io/docs/user-guide/pods/#termination-of-pods[guide]). 20 | 21 | Optionally, you can also ask Kubernetes to execute a shutdown command via the pre-stop lifecycle hook. Read through the link:http://kubernetes.io/docs/user-guide/pods/#termination-of-pods[documentation] the learn more - we won't implement this during the lab. 22 | -------------------------------------------------------------------------------- /guestbook-service/src/main/java/com/redhat/developers/guestbook/Resources.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JBoss, Home of Professional Open Source 3 | * Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 4 | * contributors by the @authors tag. See the copyright.txt in the 5 | * distribution for a full listing of individual contributors. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.redhat.developers.guestbook; 18 | 19 | import javax.enterprise.context.RequestScoped; 20 | import javax.enterprise.inject.Disposes; 21 | import javax.enterprise.inject.Produces; 22 | import javax.persistence.EntityManager; 23 | import javax.persistence.EntityManagerFactory; 24 | import javax.persistence.PersistenceUnit; 25 | 26 | /** 27 | * This class uses CDI to alias Java EE resources, such as the persistence 28 | * context, to CDI beans 29 | * 30 | *

31 | * Example injection on a managed bean field: 32 | *

33 | * 34 | *
35 |  * @Inject
36 |  * private EntityManager em;
37 |  * 
38 | */ 39 | public class Resources { 40 | 41 | @PersistenceUnit 42 | private EntityManagerFactory emf; 43 | 44 | @Produces 45 | @RequestScoped 46 | public EntityManager create() { 47 | return emf.createEntityManager(); 48 | } 49 | 50 | public void close(@Disposes EntityManager em) { 51 | if (em.isOpen()) { 52 | em.close(); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /lab/configuring-envvars.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | #### Environmental Variable 17 | 18 | http://vertx.io/[Vert.X] can read the override configuration directly from an environment variable. In this case, the environment variable is defaulted to _greeting_. You can specify the environmental variable directly using the _oc_ command: 19 | 20 | [source, bash, subs="normal,attributes"] 21 | ---- 22 | $ *oc set env deployment helloworld-service-vertx GREETING='Hello {name} from envvar!'* 23 | deployment "helloworld-service-vertx" updated 24 | ---- 25 | 26 | Again, through the use of *Kubernetes Deployment*, it'll rolling update all the replicas with the new configuration! If you were to refresh the application, you'll notice that there are no intermittent errors because we also have health checks and readiness checks in place. 27 | 28 | Check the application to see it is using the new Greeting string. 29 | 30 | Let's remove the defined variable: 31 | 32 | [source, bash, subs="normal,attributes"] 33 | ---- 34 | $ *oc set env deployment helloworld-service-vertx GREETING-* 35 | deployment "helloworld-service-vertx" updated 36 | ---- 37 | 38 | NOTE: The '-' means that we want to remove that environment var from the Deployment. -------------------------------------------------------------------------------- /kubernetes/mysql-deployment.yaml: -------------------------------------------------------------------------------- 1 | # JBoss, Home of Professional Open Source 2 | # Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | # contributors by the @authors tag. See the copyright.txt in the 4 | # distribution for a full listing of individual contributors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | apiVersion: extensions/v1beta1 17 | kind: Deployment 18 | metadata: 19 | name: mysql 20 | labels: 21 | app: mysql 22 | lab: kubernetes-lab 23 | spec: 24 | replicas: 1 25 | selector: 26 | matchLabels: 27 | app: mysql 28 | template: 29 | metadata: 30 | labels: 31 | app: mysql 32 | lab: kubernetes-lab 33 | spec: 34 | containers: 35 | - name: mysql 36 | image: openshift/mysql-56-centos7 37 | imagePullPolicy: IfNotPresent 38 | resources: 39 | limits : 40 | cpu: 0.5 41 | env: 42 | - name: MYSQL_USER 43 | value: myuser 44 | - name: MYSQL_PASSWORD 45 | value: mypassword 46 | - name: MYSQL_DATABASE 47 | value: guestbook 48 | ports: 49 | - containerPort: 3306 50 | name: mysql 51 | volumeMounts: 52 | # name must match the volume name below 53 | - name: mysql-persistent-volume 54 | # mount path within the container 55 | mountPath: /var/lib/mysql/data 56 | volumes: 57 | - name: mysql-persistent-volume 58 | persistentVolumeClaim: 59 | claimName: mysql-pvc 60 | -------------------------------------------------------------------------------- /frontend/scripts/page.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | fillMessages(); 3 | }); 4 | 5 | // Action on submit 6 | function submitForm(event) { 7 | var myForm = $('#myform'); 8 | if (myForm[0].checkValidity()) { 9 | // Prevent submission 10 | event.preventDefault(); 11 | // POST the form 12 | $.post('/api/messages', myForm.serialize(), function() { 13 | // Clear the message 14 | $('#inputMessage').val(''); 15 | // Get the hello 16 | getHelloworld(); 17 | // Fill the table 18 | fillMessages(); 19 | }).fail(function(data) { 20 | alert('Failed to post form. Please check the logs for more details.') 21 | console.log(data); 22 | }); 23 | } else { 24 | // simulate a submit to force HTML5 validation 25 | $('').hide().appendTo(myForm).click().remove(); 26 | } 27 | } 28 | 29 | // get the hello world message 30 | function getHelloworld() { 31 | $.ajax({ 32 | url : '/api/hello/' + $('#inputUsername').val(), 33 | success : function(result) { 34 | $('#message').text(result); 35 | $('#messageBox').removeClass('hidden'); 36 | }, 37 | error : function(request, status, error) { 38 | alert('Error getting the helloworld message. Please check the logs for more details.'); 39 | }, 40 | }); 41 | } 42 | 43 | // get the existing messages 44 | function fillMessages() { 45 | // wait at least 200ms before requesting the page 46 | setTimeout(function() { 47 | $.ajax({ 48 | url : '/api/messages', 49 | success : function(result) { 50 | var messages = JSON.parse(result); 51 | // Clear the table before feeling it again 52 | $('#mytable tbody').empty(); 53 | for ( var i in messages) { 54 | $('#mytable tbody').append( 55 | '' + messages[i].username + '' + messages[i].message + ''); 56 | } 57 | }, 58 | error : function(request, status, error) { 59 | alert('Error reading the messages. Please check the logs for more details.'); 60 | }, 61 | }); 62 | 63 | }, 200); 64 | } -------------------------------------------------------------------------------- /guestbook-service/src/main/java/com/redhat/developers/guestbook/rest/MessageResource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JBoss, Home of Professional Open Source 3 | * Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 4 | * contributors by the @authors tag. See the copyright.txt in the 5 | * distribution for a full listing of individual contributors. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.redhat.developers.guestbook.rest; 18 | 19 | import java.util.List; 20 | 21 | import javax.inject.Inject; 22 | import javax.ws.rs.FormParam; 23 | import javax.ws.rs.GET; 24 | import javax.ws.rs.POST; 25 | import javax.ws.rs.Path; 26 | import javax.ws.rs.Produces; 27 | import javax.ws.rs.core.Response; 28 | 29 | import com.redhat.developers.guestbook.data.Message; 30 | import com.redhat.developers.guestbook.data.MessageRepository; 31 | 32 | @Path("/messages") 33 | public class MessageResource { 34 | 35 | @Inject 36 | private MessageRepository messageRepository; 37 | 38 | @Inject 39 | private BadwordFilter badwordFilter; 40 | 41 | @POST 42 | public Response addMessage(@FormParam("username") String username, @FormParam("message") String text) { 43 | String input = badwordFilter.filterText(text); 44 | Message message = new Message(username, input); 45 | try { 46 | messageRepository.save(message); 47 | } catch (Exception e) { 48 | return Response.serverError().entity(e.getMessage()).build(); 49 | } 50 | return Response.ok().build(); 51 | } 52 | 53 | @GET 54 | @Produces("application/json") 55 | public List getAllMessages() { 56 | return messageRepository.findAllOrdered(); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /guestbook-service/src/main/java/com/redhat/developers/guestbook/Main.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JBoss, Home of Professional Open Source 3 | * Copyright 2015, Red Hat, Inc. and/or its affiliates, and individual 4 | * contributors by the @authors tag. See the copyright.txt in the 5 | * distribution for a full listing of individual contributors. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.redhat.developers.guestbook; 18 | 19 | import org.wildfly.swarm.container.Container; 20 | import org.wildfly.swarm.datasources.DatasourcesFraction; 21 | 22 | public class Main { 23 | 24 | public static void main(String[] args) throws Exception { 25 | Container container = new Container(); 26 | 27 | container.fraction(new DatasourcesFraction().jdbcDriver("com.mysql", (d) -> { 28 | d.driverClassName("com.mysql.jdbc.Driver"); 29 | d.xaDatasourceClass("com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"); 30 | d.driverModuleName("com.mysql"); 31 | }).dataSource("MySQLDS", (ds) -> { 32 | ds.driverName("com.mysql"); 33 | ds.connectionUrl(System.getenv().getOrDefault("JDBC_URL", "jdbc:mysql://mysql:3306/guestbook?useSSL=false&autoReconnect=true")); 34 | ds.userName(System.getenv().getOrDefault("DATASOURCE_USERNAME", "myuser")); 35 | ds.password(System.getenv().getOrDefault("DATASOURCE_PASSWORD", "mypassword")); 36 | ds.backgroundValidation(true); 37 | ds.validConnectionCheckerClassName("org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker"); 38 | ds.validateOnMatch(true); 39 | ds.checkValidConnectionSql("SELECT 1"); 40 | })); 41 | 42 | // Start the container and deploy the default war 43 | container.start().deploy(); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /guestbook-service/src/main/java/com/redhat/developers/guestbook/data/Message.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JBoss, Home of Professional Open Source 3 | * Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 4 | * contributors by the @authors tag. See the copyright.txt in the 5 | * distribution for a full listing of individual contributors. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.redhat.developers.guestbook.data; 18 | 19 | import java.io.Serializable; 20 | import java.util.Date; 21 | 22 | import javax.persistence.Entity; 23 | import javax.persistence.GeneratedValue; 24 | import javax.persistence.Id; 25 | import javax.validation.constraints.NotNull; 26 | import javax.validation.constraints.Size; 27 | 28 | @Entity 29 | public class Message implements Serializable { 30 | 31 | private static final long serialVersionUID = 1L; 32 | 33 | @Id 34 | @GeneratedValue 35 | private Long id; 36 | 37 | @NotNull 38 | @Size(min = 3, max = 20) 39 | private String username; 40 | 41 | @NotNull 42 | @Size(min = 5) 43 | private String message; 44 | 45 | private Date timestamp = new Date(); 46 | 47 | public Message() { 48 | 49 | } 50 | 51 | public Message(String username, String message) { 52 | this.username = username; 53 | this.message = message; 54 | } 55 | 56 | public String getUsername() { 57 | return username; 58 | } 59 | 60 | public void setUsername(String username) { 61 | this.username = username; 62 | } 63 | 64 | public String getMessage() { 65 | return message; 66 | } 67 | 68 | public void setMessage(String message) { 69 | this.message = message; 70 | } 71 | 72 | public Long getId() { 73 | return id; 74 | } 75 | 76 | public Date getTimestamp() { 77 | return timestamp; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /lab/troubleshooting.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | ## Troubleshooting 17 | 18 | ### Error from server: the server has asked for the client to provide credentials 19 | 20 | If any **kubectl** or **oc** command replies with 21 | 22 | ==== 23 | Error from server: the server has asked for the client to provide credentials 24 | ==== 25 | 26 | Execute: 27 | 28 | [source,bash,subs="normal,attributes"] 29 | ---- 30 | $ *oc login -u openshift-dev -p devel* 31 | ---- 32 | 33 | 34 | ### Windows vagrant plugin install 35 | 36 | When your Windows username contains a space, vagrant will give the following message: 37 | 38 | ==== 39 | The directory where plugins are installed (the Vagrant home directory) has a space in it. On Windows, there is a bug in Ruby when compiling plugins into directories with spaces. Please move your Vagrant home directory to a path without spaces and try again. 40 | ==== 41 | 42 | The workaround is set the vagrant home in other folder that doesn't contain spaces. You can do that with the following command: 43 | 44 | [source,bash,subs="normal,attributes"] 45 | ---- 46 | C:\> set VAGRANT_HOME=C:\ 47 | ---- 48 | 49 | 50 | ### Windows vagrant ssh 51 | 52 | If your Windows doesn't contain *ssh*, vagrant will complain about it. In that case, just install *git for Windows* and add the following values to the PATH environment variable to **C:\Program Files\Git\bin;C:\Program Files\Git\usr\bin** 53 | 54 | image::images/vagrant-windows-git.png[Logo,float="center",align="center"] -------------------------------------------------------------------------------- /lab/app-deploy-mysql-and-service.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | ### Deploy MySQL and Service 17 | Duration: 4:00 18 | 19 | MySQL uses persistent storage. Rather than writing the data directly into the container image itself, our example stores the MySQL in a Persistent Volume. Before you can deploy the pod, you need to claim a persistent volume that can be mounted inside of the MySQL container: 20 | 21 | [source, bash, subs="normal,attributes"] 22 | ---- 23 | $ *kubectl create -f mysql-pvc.yaml* 24 | persistentvolumeclaim/mysql-pvc created 25 | ---- 26 | 27 | CDK provides several *PersistentVolumes*, previously defined by the cluster administrator. These *PersistentVolumes* will be assigned based on the size claimed by the *PersistentVolumeClaim*. 28 | 29 | You can examine the *PersistentVolumeClaim* with the following command: 30 | 31 | [source, bash, subs="normal,attributes"] 32 | ---- 33 | $ *kubectl get pvc* 34 | NAME STATUS VOLUME CAPACITY ACCESSMODES STORAGECLASS AGE 35 | mysql-pvc Bound pv0044 100Gi RWO,ROX,RWX 27s 36 | ---- 37 | 38 | You can then deploy both the MySQL Pod and the Service with a single command: 39 | 40 | [source, bash, subs="normal,attributes"] 41 | ---- 42 | $ *kubectl create -f mysql-deployment.yaml -f mysql-service.yaml* 43 | deployment.extensions/mysql created 44 | service/mysql created 45 | ---- 46 | 47 | Lastly, you can see the pods and service status via the command line. Recall the command you can use to see the status (hint: _kubectl get ..._). Make sure the status is _Running_ before continuing. 48 | -------------------------------------------------------------------------------- /lab/configuring-argument.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | #### Command Line Argument 17 | 18 | Next, let's add a configuration via the command line arguments. You can also use _oc_ to edit the *DeploymentConfig*. 19 | 20 | [source, bash, subs="normal,attributes"] 21 | ---- 22 | $ *oc edit deployment helloworld-service-vertx* 23 | ---- 24 | include::includes/tip.adoc[] 25 | 26 | 27 | Now you can add the *args* that will be passed to the container command. 28 | 29 | [source, yaml, subs="normal,attributes"] 30 | ---- 31 | apiVersion: extensions/v1beta1 32 | kind: Deployment 33 | ... 34 | spec:. 35 | ... 36 | template: 37 | ... 38 | spec: 39 | ... 40 | containers: 41 | - image: rafabene/microservices-helloworld-vertx:1.0 42 | *args: 43 | - -DGREETING=Hello {name} from args* 44 | ... 45 | ---- 46 | 47 | [NOTE] 48 | ==== 49 | Yes, there are 2 dashes. The first dash is required by YAML to indicate that this is a list element, followed by a space and one more dash that is actually passed into the command line argument. 50 | 51 | When you save the file in *vi*, the new content is automatically submited to the cluster. This causes the *Kubernetes Deployment* to automatically perform a rolling update of all Pods to have the changes that you just specified. 52 | ==== 53 | 54 | Check the application and submit a name and message to see it is using the new greeting string. 55 | 56 | Let's rollback to the previous state again: 57 | 58 | [source, bash, subs="normal,attributes"] 59 | ---- 60 | $ *oc rollback helloworld-service-vertx* 61 | #? rolled back to helloworld-service-vertx-? 62 | ---- -------------------------------------------------------------------------------- /helloworld-service/src/main/java/com/redhat/developers/helloworld/HelloworldVerticle.java: -------------------------------------------------------------------------------- 1 | /** 2 | * JBoss, Home of Professional Open Source 3 | * Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 4 | * contributors by the @authors tag. See the copyright.txt in the 5 | * distribution for a full listing of individual contributors. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.redhat.developers.helloworld; 18 | 19 | import java.util.HashMap; 20 | import java.util.Map; 21 | 22 | import org.apache.commons.lang3.text.StrSubstitutor; 23 | 24 | import io.vertx.core.AbstractVerticle; 25 | import io.vertx.core.http.HttpMethod; 26 | import io.vertx.ext.web.Router; 27 | import io.vertx.ext.web.handler.CorsHandler; 28 | 29 | public class HelloworldVerticle extends AbstractVerticle { 30 | 31 | public static final String version = "1.0"; 32 | 33 | @Override 34 | public void start() throws Exception { 35 | Router router = Router.router(vertx); 36 | 37 | //Config CORS 38 | router.route().handler(CorsHandler.create("*") 39 | .allowedMethod(HttpMethod.GET) 40 | .allowedHeader("Content-Type")); 41 | 42 | // hello endpoint 43 | router.get("/api/hello/:name").handler(ctx -> { 44 | ctx.response().end(hello(ctx.request().getParam("name"))); 45 | }); 46 | vertx.createHttpServer().requestHandler(router::accept).listen(8080); 47 | } 48 | 49 | private String hello(String name) { 50 | String configGreeting = ApplicationConfiguration.load(config()).getString("GREETING"); 51 | String greeting = configGreeting == null ? "Hello {name} from {hostname} with {version}" : configGreeting; 52 | Map values = new HashMap(); 53 | values.put("name", name); 54 | values.put("hostname", System.getenv().getOrDefault("HOSTNAME", "unknown")); 55 | values.put("version", version); 56 | return new StrSubstitutor(values, "{", "}").replace(greeting); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /lab/rolling-update.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | ### Rolling Update 17 | Duration: 10:00 18 | 19 | It’s easy to update & rollback. 20 | 21 | In this lab, we'll switch to the _frontend/_ directory and make a minor change to the index.html (e.g., change the background color, title, etc.). After that, rebuild the container. 22 | 23 | 24 | [source, bash, subs="normal,attributes"] 25 | ---- 26 | $ *cd kubernetes-lab/frontend* 27 | $ *vi index.html* 28 | ---- 29 | [TIP] 30 | ==== 31 | HINT 1: Change the _

Say Hi

_ line, but feel free to change any HTML content that that you want 32 | 33 | HINT 2: Type *':51'* to go to that line 34 | 35 | HINT 3: Type *'i'* to enter in edit mode 36 | 37 | HINT 4: Type *':wq'* to exit from vi 38 | ==== 39 | 40 | Kubernetes needs to be aware of the new docker image with the changes that you introduced. 41 | 42 | // include::docker-image-minishift.adoc[] 43 | 44 | TIP: Replace rafabene/microservices-frontend:2.0 to /microservices-frontend:2.0 45 | 46 | [source, bash, subs="normal,attributes"] 47 | ---- 48 | $ *docker build -t /microservices-frontend:2.0 .* 49 | 50 | $ *docker push /microservices-frontend:2.0* 51 | ---- 52 | 53 | Now we will use the _kubectl rolling-update_ command to perform the rolling update. We create a new *ReplicationController* called frontend-ui-2 that contains the new image. 54 | 55 | [source,bash, subs="normal,attributes"] 56 | ---- 57 | $ *kubectl set image deployment/frontend-ui frontend-ui=rafabene/microservices-frontend:2.0* 58 | deployment.extensions/frontend-ui image updated 59 | ---- 60 | 61 | That's it! Kubernetes will performed a rolling update to update all the versions from 1.0 to 2.0. 62 | 63 | -------------------------------------------------------------------------------- /lab/setup-environment.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | ## Setup environment 17 | Duration: 15:00 18 | 19 | This section describes what, how, and where to install the software needed for this lab. This lab is designed for a BYOL (Bring Your Own Laptop) style hands-on-lab. 20 | 21 | ### Hardware 22 | 23 | - Operating System: Windows 7 (SP1), Mac OS X (10.8 or later), Fedora (21 or later) 24 | - Memory: At least 4 GB+, preferred 8 GB 25 | 26 | ### Software 27 | 28 | #### Development tools 29 | 30 | Make sure to have the following tools/packages installed: 31 | 32 | - GIT 33 | - Maven 34 | - Kubernetes binaries ( ) 35 | 36 | #### kubectl 37 | 38 | To install kubectl binary, follow the link:https://kubernetes.io/docs/tasks/tools/install-kubectl/[Install and Set Up kubectl] tutorial 39 | 40 | TIP: macOS users can install `kubectl` through homebrew using the following command `brew install kubectl` 41 | 42 | #### oc 43 | 44 | To install oc, Download it from https://github.com/openshift/origin/releases 45 | 46 | TIP: macOS users can isntall `oc` through homebrew using the following command: `brew install openshift-cli` 47 | 48 | ### Login in the cluster 49 | 50 | This lab uses link:https://www.openshift.org/[OpenShift], which is an Enterprise distribution of Kubernetes. Because of some Enterprise features like security, it's needed to authenticate against this cluster. 51 | 52 | To authenticate in the cluster, you need to access to the `oc` binary. You can add the oc binary to you path by running the following command: 53 | 54 | [source,bash,subs="normal,attributes"] 55 | ---- 56 | # Login in the cluster 57 | $ oc login {ocp-cluster} 58 | ---- 59 | 60 | The credentials are: userX / openshift. X is your assigned number 61 | 62 | Next, you will need to create a project for you: 63 | 64 | [source,bash,subs="normal,attributes"] 65 | ---- 66 | # Create a new project. X is your number 67 | $ oc new-project labX 68 | ---- 69 | -------------------------------------------------------------------------------- /lab/autoscaling.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | ### Autoscaling 17 | Duration: 5:00 18 | 19 | Kubernetes 1.2 has built-in Horizontal Pod Autoscaling based on CPU utilization (and custom metrics!). We will only cover autoscaling based on CPU utilization in this lab, since the custom metrics scaling is still in Alpha. 20 | 21 | To set up horizontal autoscaling is extremely simple: 22 | 23 | [source, bash, subs="normal,attributes"] 24 | ---- 25 | $ *oc autoscale deployment guestbook-service --min 1 --max 10 --cpu-percent=80* 26 | deployment "guestbook-service" autoscaled 27 | ---- 28 | 29 | [NOTE] 30 | ==== 31 | - Currently, the only metric supported is CPU Utilization. 32 | - The OpenShift administrator must first enable link:https://docs.openshift.com/enterprise/3.2/install_config/cluster_metrics.html[Cluster Metrics] before you can enable autoscaling. 33 | - The OpenShift administrator must also enable link:https://docs.openshift.com/enterprise/3.2/admin_guide/limits.html[Resource Limits] on the project. 34 | ==== 35 | 36 | Behind the scenes, Kubernetes will periodically (by default, every 30 seconds) collect CPU utilization and determine the number of pods needed. 37 | 38 | You can see the current status of the autoscaler by using the describe command: 39 | 40 | [source, bash, subs="normal,attributes"] 41 | ---- 42 | $ *oc describe hpa guestbook-service* 43 | Name: guestbook-service 44 | Namespace: myproject 45 | Labels: 46 | Annotations: 47 | CreationTimestamp: Thu, 04 Aug 2016 06:59:05 -0400 48 | Reference: Deployment/guestbook-service 49 | Target CPU utilization: 80% 50 | Current CPU utilization: 51 | Min replicas: 1 52 | Max replicas: 10 53 | ReplicationController pods: 1 current / 1 desired 54 | Events: 55 | .... 56 | ---- 57 | 58 | It's going to be a little difficult to enable the Cluster Metrics and generate the load needed to kick off the autoscaler. We won't do that during the lab. 59 | 60 | Learn more about Horizontal Pod Autoscaling (HPA) in the https://docs.openshift.com/enterprise/3.2/dev_guide/pod_autoscaling.html[guide] 61 | -------------------------------------------------------------------------------- /lab/readme.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | # Kubernetes Lab for Java Developers 17 | from Basics to OpenShift 18 | :toc: macro 19 | :toc-title: Table of Contents 20 | :toclevels: 5 21 | :icons: font 22 | :data-uri: 23 | :source-highlighter: highlightjs 24 | :numbered: 25 | :ocp-cluster: master.devx-5c72.openshiftworkshop.com 26 | :app-domain: apps.devx-5c72.openshiftworkshop.com 27 | 28 | Latest HTML: http://bit.ly/kubernetes-lab + 29 | Docs and Application Source code: https://github.com/redhat-developer-demos/kubernetes-lab 30 | 31 | If you find any issues, report it in the link:https://github.com/redhat-developer-demos/kubernetes-lab/issues[Github repository]. You're also welcome to send any link:https://help.github.com/articles/using-pull-requests/[pull requests] and contributions. 32 | 33 | toc::[] 34 | 35 | include::preface.adoc[] 36 | 37 | include::setup-environment.adoc[] 38 | 39 | ## Kubernetes - The Basics 40 | 41 | We’re going to work through this https://github.com/redhat-developer-demos/kubernetes-lab[Guestbook] example. This example has a frontend using HTML5 and Javascript (client-side and server-side), and two microservices built using link:http://wildfly-swarm.io[WildFly Swarm] and link:http://vertx.io/[VertX]. It requires MySQL to store guestbook entries. 42 | 43 | image::images/app-diagram.png[Logo,float="center",align="center"] 44 | 45 | include::app-application-source.adoc[] 46 | 47 | include::app-frontend-deployment.adoc[] 48 | 49 | include::app-frontend-service.adoc[] 50 | 51 | include::app-deploy-mysql-and-service.adoc[] 52 | 53 | include::app-deploy-microservices.adoc[] 54 | 55 | include::external-access.adoc[] 56 | 57 | include::scaling.adoc[] 58 | 59 | include::health-checks.adoc[] 60 | 61 | include::rolling-update.adoc[] 62 | 63 | include::graceful-shutdown.adoc[] 64 | 65 | ## Kubernetes - Going further 66 | 67 | include::openshift.adoc[] 68 | 69 | include::configuring-application.adoc[] 70 | 71 | include::managing-credentials.adoc[] 72 | 73 | include::autoscaling.adoc[] 74 | 75 | include::extra.adoc[] 76 | 77 | include::feedback.adoc[] 78 | 79 | include::troubleshooting.adoc[] 80 | 81 | include::references.adoc[] 82 | 83 | -------------------------------------------------------------------------------- /frontend/frontend.js: -------------------------------------------------------------------------------- 1 | /** 2 | * JBoss, Home of Professional Open Source Copyright 2016, Red Hat, Inc. and/or 3 | * its affiliates, and individual contributors by the 4 | * 5 | * @authors tag. See the copyright.txt in the distribution for a full listing of 6 | * individual contributors. 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 9 | * use this file except in compliance with the License. You may obtain a copy of 10 | * the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by 11 | * applicable law or agreed to in writing, software distributed under the 12 | * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 13 | * OF ANY KIND, either express or implied. See the License for the specific 14 | * language governing permissions and limitations under the License. 15 | */ 16 | 17 | var express = require('express') 18 | var request = require('request') 19 | var bodyParser = require('body-parser') 20 | var app = express() 21 | 22 | var guestbookendpoint = 'http://guestbook-service:8080/api/messages' 23 | var helloendpoint = 'http://helloworld-service-vertx:8080/api/hello/' 24 | 25 | // Creates a $request callback using $express objects 26 | var defaultHandling = function(res, next) { 27 | // Callback for $request 28 | return function(error, response, body) { 29 | if (!error && response.statusCode == 200) { 30 | res.send(body || ''); 31 | } else { 32 | next(error) 33 | } 34 | } 35 | } 36 | 37 | // for parsing application/x-www-form-urlencoded 38 | app.use(bodyParser.urlencoded({ 39 | extended : true 40 | })); 41 | 42 | // Static content routing 43 | app.use('/', express.static('.')) 44 | 45 | app.use('/api/health', function(req, res, next) { 46 | res.send('I am ok'); 47 | }); 48 | 49 | app.use('/api/version', function(req, res, next) { 50 | res.send('Version 1'); 51 | }); 52 | 53 | app.post('/api/messages', function(req, res, next) { 54 | console.log('POST content %s to %s', JSON.stringify(req.body), guestbookendpoint) 55 | // Make a POST to guestbook endpoint 56 | request.post({ 57 | 'url' : guestbookendpoint, 58 | 'form' : req.body, 59 | 'timeout' : 1500 60 | }, defaultHandling(res, next)) 61 | }); 62 | 63 | app.get('/api/messages', function(req, res, next) { 64 | console.log('redirecting GET request to ' + guestbookendpoint) 65 | // Get messages from guestbook endpoint 66 | request({ 67 | 'url' : guestbookendpoint, 68 | "timeout" : 1500 69 | }, defaultHandling(res, next)) 70 | }); 71 | 72 | app.get('/api/hello/:name', function(req, res, next) { 73 | var dest = helloendpoint + req.params.name 74 | console.log('redirecting GET request to ' + dest) 75 | // Get the hello world message from helloworld-vertx endpoint 76 | request({ 77 | 'url' : dest, 78 | 'timeout' : 1500 79 | }, defaultHandling(res, next)) 80 | }); 81 | 82 | var server = app.listen(8080, '0.0.0.0', function() { 83 | var host = server.address().address 84 | var port = server.address().port 85 | 86 | console.log("Frontend service running at http://%s:%s", host, port) 87 | }); -------------------------------------------------------------------------------- /lab/preface.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | ## Preface 17 | 18 | In the last 3 years, docker and linux containers have become the sensation of the IT industry. The promise of eliminating environment inconsistencies by packaging your software together with all its dependencies (files, libraries, environment variables, runtimes, etc) has driven Linux containers to emerge as a de-facto standard. 19 | 20 | Once your application is wrapped in a container, you don't need to lose time configuring a new environment. Running another "instance" of your application is easy and consumes less computational resources than typical Virtual Machines. 21 | 22 | Even though containers consume fewer computational resources, a single machine running a dozen containers is not an ideal scenario for a professional "production environment" --- running many containers on a single machine can lead to several issues. 23 | 24 | Just to mention a few: 25 | 26 | - The quantity of active containers are limited by the "size" of your hardware 27 | - Unlike a "cloud environment" you can't move the workloads to where you want 28 | - The one machine becomes the SPOF (Single Point of Failure) of your application. 29 | 30 | To achieve a serious "production environment", your Linux containers should be capable of running on more than one single machine, supporting your application's horizontal scaling. In this scenario, features like self-healing, autoscaling, load-balancing, service-discovery, and distributed storage volumes completes the professional touch of your environment. It sounds complicated, but fortunately you can get all of these features from a single technology - Kubernetes. 31 | 32 | link:http://kubernetes.io/[Kubernetes] is an open-source project developed by link:https://www.google.com/[Google], with link:https://developers.redhat.com/[Red Hat] at a close second in contributions. Google has over a decade of experience with Linux containers, deploying millions each day. It should be no surprise that Kubernetes' capabilities and maturity have led to its being used as the engine of link:https://www.openshift.com/[OpenShift Enterprise v3]. 33 | 34 | image::images/k8slogo.png[Logo,float="center",align="center"] 35 | 36 | This lab offers developers a hands-on session with Kubernetes, from the basics concepts, to adding Java based microservices, to service scaling, to perform rolling deployments. This is a BYOL (bring your own laptop) session, so bring your Windows, OSX, or Linux laptop and be ready to dig into a tool that promises to be at the forefront of our industry for some time to come. 37 | 38 | NOTE: Latest content of this lab is always at https://github.com/redhat-developer-demos/kubernetes-lab[] 39 | -------------------------------------------------------------------------------- /lab/scaling.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | ### Scaling 17 | Duration: 5:00 18 | 19 | We have seem that *Deployments* keep the same ammount of replicas running. Let's check the number of pods again. Execute: 20 | 21 | [source, bash, subs="normal,attributes"] 22 | ---- 23 | $ *kubectl get pods* 24 | NAME READY STATUS RESTARTS AGE 25 | frontend-ui-6jy22 1/1 Running 0 24m 26 | frontend-ui-7tcgx 1/1 Running 0 24m 27 | guestbook-service-gxjnx 1/1 Running 0 19m 28 | helloworld-service-vertx-edux9 1/1 Running 0 20m 29 | helloworld-service-vertx-lq1m0 1/1 Running 0 21m 30 | mysql-q9k7p 1/1 Running 0 21m 31 | ---- 32 | 33 | Scaling the number of replicas of our Hello World service is as simple as running : 34 | 35 | [source, bash, subs="normal,attributes"] 36 | ---- 37 | $ *kubectl scale deployment helloworld-service-vertx --replicas=6* 38 | deployment "helloworld-service-vertx" scaled 39 | ---- 40 | 41 | You can very quickly see that the replication controller has been updated: 42 | 43 | [source, bash, subs="normal,attributes"] 44 | ---- 45 | $ *kubectl get deployments* 46 | NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE 47 | frontend-ui 2 2 2 2 3h 48 | guestbook-service 1 1 1 1 2h 49 | helloworld-service-vertx 6 6 6 6 2h 50 | mysql 1 1 1 1 2h 51 | 52 | $ *kubectl get pods* 53 | NAME READY STATUS RESTARTS AGE 54 | frontend-ui-2676544744-3k1p6 1/1 Running 0 3h 55 | frontend-ui-2676544744-b88hg 1/1 Running 0 3h 56 | guestbook-service-114023015-8x9j8 1/1 Running 0 2h 57 | helloworld-service-vertx-3644252884-73cxk 1/1 Running 0 48s 58 | helloworld-service-vertx-3644252884-t364t 1/1 Running 0 2h 59 | helloworld-service-vertx-3644252884-v5t67 1/1 Running 0 48s 60 | helloworld-service-vertx-3644252884-wct43 1/1 Running 0 48s 61 | helloworld-service-vertx-3644252884-x7ggl 1/1 Running 0 48s 62 | helloworld-service-vertx-3644252884-xxvzh 1/1 Running 0 2h 63 | mysql-471477625-rnjt1 1/1 Running 0 2h 64 | ---- 65 | 66 | Reduce the number of replicas back to 2 so that we can free up resources for the later labs: 67 | 68 | [source, bash, subs="normal,attributes"] 69 | ---- 70 | $ *kubectl scale deployment helloworld-service-vertx --replicas=2* 71 | deployment "helloworld-service-vertx" scaled 72 | ---- 73 | -------------------------------------------------------------------------------- /frontend/index.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | Microservices Frontend 20 | 21 | 22 | 23 | 24 | 25 | 26 | 28 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 46 | 47 | 48 | 49 |
50 | 51 |

Say Hi - Version 2

52 |
53 |
54 | 56 |
57 | 60 |
61 |
62 |
63 | 64 |
65 | 68 |
69 |
70 |
71 |
72 | 74 |
75 |
76 |
77 | 82 |
83 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 |
NameMessage
94 | 95 |
96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /lab/app-frontend-deployment.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | ### Deploy frontend 17 | Duration: 5:00 18 | 19 | A Kubernetes pod is a group of containers, tied together for the purposes of administration and networking. It can contain one or more containers. All containers within a single pod will share the same networking interface, IP address, volumes, etc. All containers within the same pod instance will live and die together. It’s especially useful when you have, for example, a container that runs the application, and another container that periodically polls logs/metrics from the application container. 20 | 21 | You can start a single Pod in Kubernetes by creating a Pod resource. However, a Pod created this way would be known as a link:https://kubernetes.io/docs/concepts/configuration/overview/#naked-pods-vs-replication-controllers-and-jobs[Naked Pod]. However, if a Naked Pod dies/exits, it will not be restarted by Kubernetes. A better way to start a pod, is by using a higher-level construct such as Replication Controller, Replica Set, or a Deployment. 22 | 23 | A Replication Controller ensures that a specified number of pod "replicas" are running. If there are too many pods, it will kill some. If there are too few, the replication controller will start more. Unlike manually created pods, the pods maintained by a replication controller are automatically replaced if they fail, get deleted, or are terminated. 24 | 25 | A Deployment provides declarative updates for Pods and Replication Controllers. You only need to describe the desired state in a Deployment object, and the Deployment controller will change the actual state to the desired state at a controlled rate for you. You can use deployments to easily: 26 | - Create a Deployment to bring up a Replication Controller and Pods. 27 | - Check the status of a Deployment to see if it succeeds or not. 28 | - Later, update that Deployment to recreate the Pods (for example, to use a new image, or configuration). 29 | - Rollback to an earlier Deployment revision if the current Deployment isn’t stable. 30 | - Pause and resume a Deployment. 31 | 32 | In this lab, because we are working with Kubernetes 1.2+, we will be using Deployment extensively. 33 | 34 | First create a Deployment using kubectl, the Kubernetes CLI tool: 35 | 36 | [source, bash, subs="normal,attributes"] 37 | ---- 38 | $ *kubectl create -f frontend-deployment.yaml* 39 | deployment.extensions/frontend-ui created 40 | ---- 41 | 42 | You should see the frontend instances running: 43 | 44 | [source, bash, subs="normal,attributes"] 45 | ---- 46 | $ *kubectl get pods -w* 47 | NAME READY STATUS RESTARTS AGE 48 | frontend-ui-????? 0/1 ContainerCreating 0 2m 49 | frontend-ui-????? 1/1 Running 0 2m 50 | ---- 51 | 52 | Hit CTRL+C to exit back to the shell prompt at any moment. 53 | 54 | NOTE: The _ContainerCreating_ status means that Kubernetes still downloading the image from the registry before creating the containers. 55 | 56 | -------------------------------------------------------------------------------- /lab/health-checks.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | ### Health Checks 17 | Duration: 10:00 18 | 19 | During rolling update, a pod is removed as soon as a newer version of pod is up and ready to serve. By default, without health checks, Kubernetes will route traffic to the new pod as soon as the pods starts. But, it's most likely that your application will take sometime to start, and if you route traffic to the application that isn't ready to serve, your users (and/or consuming services) will see errors. To avoid this, Kubernetes comes with two types of checks: Liveness Probe, and Readiness Probe. 20 | 21 | After a container starts, it is not marked as Healthy until the Liveness Probe succeeds. However, if the number of Liveness Probe failures exceeds a configurable failure threshold, Kubernetes will mark the pod unhealthy and attempt to restart the pod. 22 | 23 | When a pod is Healthy doesn't mean it's ready to serve. You may want to warm up requests/cache, and/or transfer state from other instances. You can further mark when the pod is Ready to serve by using a Readiness Probe. 24 | 25 | Let's add a Liveness Probe to our Helloworld Service by editing the Deployment: 26 | 27 | [source, bash, subs="normal,attributes"] 28 | ---- 29 | $ *kubectl edit deployment helloworld-service-vertx* 30 | ---- 31 | include::includes/tip.adoc[] 32 | 33 | In the editor, add a Liveness Probe: 34 | 35 | [source, yaml, subs="normal,attributes"] 36 | ---- 37 | apiVersion: extensions/v1beta1 38 | kind: Deployment 39 | ... 40 | spec: 41 | ... 42 | template: 43 | ... 44 | spec: 45 | ... 46 | containers: 47 | - image: rafabene/microservices-helloworld-vertx:... 48 | *livenessProbe: 49 | initialDelaySeconds: 5 50 | timeoutSeconds: 1 51 | httpGet: 52 | path: /api/hello/Kubernetes 53 | port: 8080* 54 | ... 55 | ---- 56 | 57 | NOTE: You can configure both Liveness Probe and Readiness Probe by checking via a HTTP GET request, a HTTPS GET request, TCP port connectivity, or even a shell script! See the http://kubernetes.io/docs/user-guide/production-pods/#liveness-and-readiness-probes-aka-health-checks[Liveness and Readiness guide] for more information. 58 | 59 | You can add a Readiness Probe in the similar way: 60 | 61 | [source, bash, subs="normal,attributes"] 62 | ---- 63 | $ *kubectl edit deployment helloworld-service-vertx* 64 | ---- 65 | include::includes/tip.adoc[] 66 | 67 | In the editor, add a Readiness Probe: 68 | 69 | [source, yaml, subs="normal,attributes"] 70 | ---- 71 | apiVersion: extensions/v1beta1 72 | kind: Deployment 73 | ... 74 | spec: 75 | ... 76 | template: 77 | ... 78 | spec: 79 | ... 80 | containers: 81 | - image: rafabene/microservices-helloworld-vertx:... 82 | *readinessProbe: 83 | initialDelaySeconds: 5 84 | timeoutSeconds: 1 85 | httpGet: 86 | path: /api/hello/Kubernetes 87 | port: 8080* 88 | ... 89 | ---- 90 | 91 | NOTE: In a production scenario, the Liveness Probe and the Readiness Probe will probably be different REST endpoints or scripts. 92 | -------------------------------------------------------------------------------- /helloworld-service/src/main/java/com/redhat/developers/helloworld/ApplicationConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.redhat.developers.helloworld; 2 | 3 | import java.util.Map; 4 | import java.util.Objects; 5 | import java.util.Properties; 6 | 7 | import io.vertx.core.AbstractVerticle; 8 | import io.vertx.core.json.JsonObject; 9 | 10 | /** 11 | * Just some configuration utilities. 12 | * 13 | * @author Clement Escoffier 14 | */ 15 | public class ApplicationConfiguration { 16 | 17 | /** 18 | * Creates a Json Object from the environment variables and system properties. 19 | * The system properties override the environment variables. 20 | * 21 | * @return the json object 22 | */ 23 | public static JsonObject load() { 24 | return putAll( 25 | putAll( 26 | new JsonObject(), System.getenv()), System.getProperties() 27 | ); 28 | } 29 | 30 | /** 31 | * Creates a Json Object from the given configuration, the environment variables 32 | * and system properties. 33 | * The system properties override the environment variables that override the given json object. 34 | *

35 | * This method is intended to be used with {@link AbstractVerticle#config()}: 36 | * {@code JsonObject json = ApplicationConfiguration.load(config())} 37 | * 38 | * @param json the json object 39 | * @return 40 | */ 41 | public static JsonObject load(JsonObject json) { 42 | return putAll( 43 | putAll( 44 | json, System.getenv()), System.getProperties() 45 | ); 46 | } 47 | 48 | 49 | /** 50 | * Creates a new json object containing the content of the given json object merged with 51 | * the given Map. The content of the Map overrides the content of the given json object. 52 | * 53 | * @param conf the configuration 54 | * @param props the map 55 | * @return the json object 56 | */ 57 | private static JsonObject putAll(JsonObject conf, Map props) { 58 | Objects.requireNonNull(conf); 59 | Objects.requireNonNull(props); 60 | JsonObject json = conf.copy(); 61 | props.entrySet().stream().forEach(entry -> put(json, entry.getKey(), entry.getValue())); 62 | return json; 63 | } 64 | 65 | /** 66 | * Creates a new json object containing the content of the given json object merged with 67 | * the given Properties. The content of the Properties overrides the content of the given 68 | * json object. 69 | * 70 | * @param conf the configuration 71 | * @param props the map 72 | * @return the json object 73 | */ 74 | private static JsonObject putAll(JsonObject conf, Properties props) { 75 | Objects.requireNonNull(conf); 76 | Objects.requireNonNull(props); 77 | JsonObject json = conf.copy(); 78 | props.stringPropertyNames().stream() 79 | .forEach(name -> put(json, name, props.getProperty(name))); 80 | return json; 81 | } 82 | 83 | private static void put(JsonObject json, String name, String value) { 84 | Objects.requireNonNull(value); 85 | Boolean bool = asBoolean(value); 86 | if (bool != null) { 87 | json.put(name, bool); 88 | } else { 89 | Double integer = asNumber(value); 90 | if (integer != null) { 91 | json.put(name, integer); 92 | } else { 93 | json.put(name, value); 94 | } 95 | } 96 | } 97 | 98 | 99 | private static Double asNumber(String s) { 100 | try { 101 | return Double.parseDouble(s); 102 | } catch (NumberFormatException nfe) { 103 | return null; 104 | } 105 | } 106 | 107 | private static Boolean asBoolean(String s) { 108 | if (s.equalsIgnoreCase("true")) { 109 | return Boolean.TRUE; 110 | } else if (s.equalsIgnoreCase("false")) { 111 | return Boolean.FALSE; 112 | } else { 113 | return null; 114 | } 115 | } 116 | 117 | } -------------------------------------------------------------------------------- /lab/app-deploy-microservices-networking.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | #### Internal Kubernetes networking 17 | Duration: 7:00 18 | 19 | In Kubernetes every pod has a unique IP address! You can “login” into one of these pods by using the _kubectl exec_ command. This can drop you into a shell and execute commands inside of the container. 20 | 21 | First, find the name of the both helloworld-service-vertx pods: 22 | 23 | [source, bash, subs="normal,attributes"] 24 | ---- 25 | $ *kubectl get pods -l app=helloworld-service-vertx* 26 | NAME READY STATUS RESTARTS AGE 27 | helloworld-service-vertx-????? 1/1 Running 0 14m 28 | helloworld-service-vertx-????? 1/1 Running 0 15m 29 | ---- 30 | 31 | NOTE: Note that we used the parameter _-l app=helloworld-service-vertx_. This parameter allows us to specify labels as filter. The label _app=helloworld-service-vertx_ was defined in the ReplicationController as a template for all pods. 32 | 33 | Then, use _kubectl exec_ to exucute a _"bash"_ process into the container: 34 | 35 | [source, bash, subs="normal,attributes"] 36 | ---- 37 | $ *kubectl exec -it helloworld-service-vertx-????? bash* 38 | bash-4.2$ _ 39 | ---- 40 | 41 | You are now in a shell inside of the helloworld-service-vertx container. You can run _ps_, and _hostname_: 42 | 43 | [source, bash, subs="normal,attributes"] 44 | ---- 45 | bash-4.2$ *ps aux* 46 | USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND 47 | 1000160+ 1 0.5 0.1 4123640 68904 ? Ssl 19:12 0:01 java -Dvertx.disableFileCPResolving=true -Xmx256m -jar 48 | 1000160+ 44 0.0 0.0 11768 1676 ? Ss 19:13 0:00 bash 49 | 1000160+ 50 0.0 0.0 47420 1668 ? R+ 19:15 0:00 ps aux 50 | 51 | bash-4.2$ *hostname -i* 52 | 10.1.6.3 53 | 54 | bash-4.2$ *exit* 55 | exit 56 | ---- 57 | 58 | Don’t forget to exit :). 59 | 60 | [TIP] 61 | ==== 62 | You can begin to have a taste of some of the OpenShift enhancements now. 63 | OpenShift Client (oc) allows you to easily access the shell through the command `oc rsh helloworld-service-vertx-?????` 64 | ==== 65 | 66 | Try it with another the other pod and see its IP address. 67 | 68 | Since we are running two instances of the Hello World Service (one instance in one pod), and that the IP addresses are not only unique, but also ephemeral - how will a client reach our services? We need a way to discover the service. 69 | 70 | In Kubernetes, Service Discovery is a first class citizen. We created a Service that will: 71 | 72 | - act as a load balancer to load balance the requests to the pods, and 73 | - provide a stable IP address, allow discovery from the API, and also create a DNS name! 74 | 75 | If you login into a container (find and use the frontend-ui container), you can access the helloworldservice via the DNS name: 76 | 77 | [source, bash, subs="normal,attributes"] 78 | ---- 79 | $ *kubectl exec -it frontend-ui-????? bash* 80 | 81 | bash-4.2$ *wget -qO- http://helloworld-service-vertx:8080/api/hello/Rafael* 82 | Hello Rafael from helloworld-service-vertx-a4zq3 with 1.0 83 | 84 | bash-4.2$ *exit* 85 | exit 86 | ---- 87 | 88 | Pretty simple right!? 89 | -------------------------------------------------------------------------------- /lab/external-access.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | ### Accessing the frontend 17 | Duration: 5:00 18 | 19 | When we deployed the frontend, we needed to specify that *the service needs to be externally accessible*. In Kubernetes, you can instruct the underlying infrastructure to create an external load balancer, by specifying the Service Type as a _LoadBalancer_. 20 | 21 | You can see it in the frontend-service.yaml: 22 | 23 | [source,yaml,subs="normal,attributes"] 24 | ---- 25 | include::../kubernetes/frontend-service.yaml[] 26 | ---- 27 | 28 | Kubernetes *ServiceTypes* allow you to specify what kind of service you want. The default and base type is *ClusterIP*, which exposes a service to connection from inside the cluster. *_NodePort_ and _LoadBalancer_ are two types that expose services to external traffic*. 29 | 30 | Valid values for the ServiceType field are: 31 | 32 | - *ClusterIP*: use a cluster-internal IP only - this is the default and is discussed above. Choosing this value means that you want this service to be reachable only from inside of the cluster. 33 | - *NodePort*: on top of having a cluster-internal IP, expose the service on a port on each node of the cluster (the same port on each node). You’ll be able to contact the service on any :NodePort address. 34 | - *LoadBalancer*: on top of having a cluster-internal IP and exposing service on a NodePort also, ask the cloud provider for a load balancer which forwards to the Service exposed as a :NodePort for each Node. 35 | 36 | Note that we have specified *LoadBalancer*, but it only works on cloud providers which support external load balancers. For example, in Google Cloud Platform (GCE), a load balancer will be created asynchronously and a new external ip will be assigned. The external ip address would be available under the field *LoadBalancer Ingress*. Example: 37 | 38 | [source, bash, subs="normal,attributes"] 39 | ---- 40 | $ *kubectl describe service frontend-ui* 41 | Name: frontend-ui 42 | Namespace: myproject 43 | Labels: app=frontend-ui 44 | lab=kubernetes-lab 45 | Annotations: 46 | Selector: app=frontend-ui 47 | Type: LoadBalancer 48 | IP: 172.30.40.241 49 | External IPs: 172.29.133.81 50 | *LoadBalancer Ingress: 172.29.133.81* 51 | Port: http-80 80/TCP 52 | *NodePort: http-80 3????/TCP& 53 | Endpoints: 172.17.0.3:8080,172.17.0.4:8080 54 | Session Affinity: None 55 | Events: 56 | ---- 57 | 58 | IMPORTANT: Since CDK doesn't support the creation of external LoadBalancers, you can access the service through the *NodePort*. Kubernetes allocates a port _(default: 30000-32767)_, and each Node in the cluster will proxy that port (the same port number on every Node) into the frontend PODs. Later, in this lab, you will learn an alternative to *NodePorts* and *LoadBalancer*. 59 | 60 | First, execute *kubectl describe services frontend-ui* and find out which port (between: 30000-32767) Kubernetes assigned in the OpenShift node. Once that you have the NodePort, you can access the guestbook via the cluster address and port number by navigating the browser to http://master.xpto.com.br:/. 61 | 62 | Example: http://{ocp-cluster}:31079/ 63 | 64 | NOTE: The NodePort (31079) is a random value. You should use the value described in NodePort via _kubectl describe service frontend-service_. The IP is the external ip of the Kubernetes Cluster 65 | 66 | You should see something like this: 67 | 68 | 69 | image::images/app-screenshot.png[App Screenshot,float="center",align="center"] 70 | -------------------------------------------------------------------------------- /helloworld-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 4.0.0 20 | 21 | com.redhat.developers.helloworld 22 | helloworld-service 23 | jar 24 | 0.0.1-SNAPSHOT 25 | hellworld-service 26 | 27 | https://developers.redhat.com/ 28 | 29 | 30 | 31 | Apache License, Version 2.0 32 | repo 33 | http://www.apache.org/licenses/LICENSE-2.0.html 34 | 35 | 36 | 37 | 38 | 40 | 42 | UTF-8 43 | 44 | io.vertx.core.Launcher 45 | com.redhat.developers.helloworld.HelloworldVerticle 46 | 47 | 48 | 1.8 49 | 1.8 50 | 51 | 52 | 1.4.0 53 | 3.2.1 54 | 55 | 56 | 57 | 58 | 59 | io.vertx 60 | vertx-core 61 | ${vertx.version} 62 | 63 | 64 | io.vertx 65 | vertx-web 66 | ${vertx.version} 67 | 68 | 69 | org.apache.commons 70 | commons-lang3 71 | 3.4 72 | 73 | 74 | 75 | 76 | helloworld-service 77 | 78 | 79 | org.codehaus.mojo 80 | exec-maven-plugin 81 | ${version.exec.plugin} 82 | 83 | ${java.main.class} 84 | 85 | run 86 | ${vertx.main.verticle} 87 | -conf 88 | config.json 89 | 90 | 91 | 92 | 93 | org.apache.maven.plugins 94 | maven-shade-plugin 95 | 2.4.3 96 | 97 | 98 | package 99 | 100 | shade 101 | 102 | 103 | 104 | 106 | 107 | ${java.main.class} 108 | ${vertx.main.verticle} 109 | 110 | 111 | 112 | ${project.build.directory}/${project.artifactId}-fat.jar 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /lab/app-deploy-microservices.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | ### Deploy Microservices 17 | Duration: 5:00 18 | 19 | As mentioned before, the application makes use of two other microservices: 20 | 21 | - the Guestbook service (that writes to the MySQL database) 22 | - a Hello World service 23 | 24 | Both services are containers whose images contain self-executing JAR files. The sources are available in the git repository if you are interested in seeing it. 25 | 26 | When deploying these microservices instances, we want to make sure that: 27 | 28 | * We can scale the number of instances once deployed. 29 | * If any of the instances becomes unhealthy and/or fails, we want to make sure they are restarted automatically. 30 | 31 | Let’s deploy the microservices one at a time: 32 | 33 | First, deploy the Hello World: 34 | 35 | [source, bash, subs="normal,attributes"] 36 | ---- 37 | $ *kubectl create -f helloworldservice-deployment.yaml -f helloworldservice-service.yaml* 38 | deployment.extensions/helloworld-service-vertx created 39 | service/helloworld-service-vertx created 40 | ---- 41 | 42 | Once created, you can see the replicas with: 43 | 44 | [source, bash, subs="normal,attributes"] 45 | ---- 46 | $ *kubectl get deployments* 47 | NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE 48 | frontend-ui 2 2 2 2 12m 49 | helloworld-service-vertx 2 2 2 2 22s 50 | mysql 1 1 1 1 3m 51 | ---- 52 | 53 | You can see the pods running: 54 | 55 | [source, bash, subs="normal,attributes"] 56 | ---- 57 | $ *kubectl get pods* 58 | NAME READY STATUS RESTARTS AGE 59 | frontend-ui-1bvcv 1/1 Running 0 2h 60 | frontend-ui-5vtsp 1/1 Running 0 2h 61 | helloworld-service-vertx-prnhv 1/1 Running 0 4m 62 | helloworld-service-vertx-sgds6 1/1 Running 0 4m 63 | mysql-xvi3c 1/1 Running 0 1h 64 | ---- 65 | 66 | You can also look at each pod’s log output by running: 67 | 68 | [source, bash, subs="normal,attributes"] 69 | ---- 70 | $ *kubectl logs -f helloworld-service-vertx-?????* 71 | Aug 02, 2016 5:38:11 AM io.vertx.core.impl.launcher.commands.VertxIsolatedDeployer 72 | INFO: Succeeded in deploying verticle 73 | ---- 74 | *Note:* The _-f_ flag tails the log. To stop tailing, press _Ctrl+C_. 75 | 76 | Our descriptor file specified 2 replicas. So, if you delete one of the pods (and now you only have 1 replica rather than 2), the ReplicationController will notice that and start another pod for you to meet the configured 2 replicas specification. Let's try it! 77 | 78 | [source, bash, subs="normal,attributes"] 79 | ---- 80 | $ *kubectl delete pod helloworld-service-vertx-?????* 81 | pod "helloworld-service-vertx-????" deleted 82 | ---- 83 | 84 | You should see that the pod was deleted, and the ReplicationController will ensure a second instance is started. Sometimes this goes by very fast - and you'll notice that the pod you deleted is no longer there, and another pod, with a different name, was started. 85 | 86 | [source, bash, subs="normal,attributes"] 87 | ---- 88 | $ *kubectl get pods* 89 | NAME READY STATUS RESTARTS AGE 90 | ... 91 | helloworld-service-vertx-ezuq3 1/1 Running 0 1m 92 | helloworld-service-vertx-sgds6 1/1 Running 0 10m 93 | ... 94 | ---- 95 | 96 | Lastly, let’s create the Guestbook Service replication controller and service too! 97 | 98 | [source, bash, subs="normal,attributes"] 99 | ---- 100 | $ *kubectl create -f guestbookservice-deployment.yaml -f guestbookservice-service.yaml* 101 | deployment "guestbook-service" created 102 | service "guestbook-service" created 103 | ---- 104 | 105 | include::app-deploy-microservices-networking.adoc[] 106 | -------------------------------------------------------------------------------- /guestbook-service/src/main/java/com/redhat/developers/guestbook/rest/BadwordFilter.java: -------------------------------------------------------------------------------- 1 | package com.redhat.developers.guestbook.rest; 2 | 3 | import javax.annotation.PostConstruct; 4 | import javax.inject.Singleton; 5 | import java.io.BufferedReader; 6 | import java.io.IOException; 7 | import java.io.InputStreamReader; 8 | import java.net.URL; 9 | import java.util.ArrayList; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | @Singleton 14 | public class BadwordFilter { 15 | 16 | static Map words = new HashMap<>(); 17 | static int largestWordLength = 0; 18 | 19 | @PostConstruct 20 | public void loadConfigs() { 21 | try { 22 | BufferedReader reader = new BufferedReader(new InputStreamReader(new URL("https://docs.google.com/spreadsheets/d/1hIEi2YG3ydav1E06Bzf2mQbGZ12kh2fe4ISgLg_UBuM/export?format=csv").openConnection().getInputStream())); 23 | String line = ""; 24 | int counter = 0; 25 | while((line = reader.readLine()) != null) { 26 | counter++; 27 | String[] content = null; 28 | try { 29 | content = line.split(","); 30 | if(content.length == 0) { 31 | continue; 32 | } 33 | String word = content[0]; 34 | String[] ignore_in_combination_with_words = new String[]{}; 35 | if(content.length > 1) { 36 | ignore_in_combination_with_words = content[1].split("_"); 37 | } 38 | 39 | if(word.length() > largestWordLength) { 40 | largestWordLength = word.length(); 41 | } 42 | words.put(word.replaceAll(" ", ""), ignore_in_combination_with_words); 43 | 44 | } catch(Exception e) { 45 | e.printStackTrace(); 46 | } 47 | 48 | } 49 | System.out.println("Loaded " + counter + " words to filter out"); 50 | } catch (IOException e) { 51 | e.printStackTrace(); 52 | } 53 | 54 | } 55 | 56 | 57 | /** 58 | * Iterates over a String input and checks whether a cuss word was found in a list, then checks if the word should be ignored (e.g. bass contains the word *ss). 59 | * @param input 60 | * @return 61 | */ 62 | public ArrayList badWordsFound(String input) { 63 | if(input == null) { 64 | return new ArrayList<>(); 65 | } 66 | 67 | // remove leetspeak 68 | input = input.replaceAll("1","i"); 69 | input = input.replaceAll("!","i"); 70 | input = input.replaceAll("3","e"); 71 | input = input.replaceAll("4","a"); 72 | input = input.replaceAll("@","a"); 73 | input = input.replaceAll("5","s"); 74 | input = input.replaceAll("7","t"); 75 | input = input.replaceAll("0","o"); 76 | input = input.replaceAll("9","g"); 77 | 78 | ArrayList badWords = new ArrayList<>(); 79 | input = input.toLowerCase().replaceAll("[^a-zA-Z]", ""); 80 | 81 | // iterate over each letter in the word 82 | for(int start = 0; start < input.length(); start++) { 83 | // from each letter, keep going to find bad words until either the end of the sentence is reached, or the max word length is reached. 84 | for(int offset = 1; offset < (input.length()+1 - start) && offset < largestWordLength; offset++) { 85 | String wordToCheck = input.substring(start, start + offset); 86 | if(words.containsKey(wordToCheck)) { 87 | // for example, if you want to say the word bass, that should be possible. 88 | String[] ignoreCheck = words.get(wordToCheck); 89 | boolean ignore = false; 90 | for(int s = 0; s < ignoreCheck.length; s++ ) { 91 | if(input.contains(ignoreCheck[s])) { 92 | ignore = true; 93 | break; 94 | } 95 | } 96 | if(!ignore) { 97 | badWords.add(wordToCheck); 98 | } 99 | } 100 | } 101 | } 102 | 103 | 104 | return badWords; 105 | 106 | } 107 | 108 | 109 | public String filterText(String input) { 110 | ArrayList badWords = badWordsFound(input); 111 | if(badWords.size() > 0) { 112 | return "This message was blocked because a bad word was found. If you believe this word should not be blocked, please message support."; 113 | } 114 | return input; 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /lab/configuring-configmap.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | #### Using ConfigMap 17 | 18 | In this section, we'll use Kubernetes 1.2's new feature, ConfigMap, to configure the application. You can store multiple string-based configuration files inside of a single ConfigMap configuration. In our example, we'll store Vert.x's config.json into a ConfigMap entry. 19 | 20 | First, update the _kubernetes-lab/hellworld-service/config.json_ with a new configuration value: 21 | [source, bash, subs="normal,attributes"] 22 | ---- 23 | $ *cd kubernetes-lab/hellworld-service/* 24 | $ *vi config.json* 25 | ---- 26 | include::includes/tip.adoc[] 27 | 28 | Here is a suggestion for you: 29 | 30 | [source, json, subs="normal,attributes"] 31 | ---- 32 | { 33 | "GREETING": "Hello {name} from ConfigMap" 34 | } 35 | ---- 36 | 37 | Next, create a ConfigMap entry with this file: 38 | 39 | [source, bash, subs="normal,attributes"] 40 | ---- 41 | $ *oc create configmap greeting-config --from-file=config.json* 42 | configmap "greeting-config" created 43 | ---- 44 | 45 | Let's take a look inside the newly created entry: 46 | 47 | [source, bash, subs="normal,attributes"] 48 | ---- 49 | $ *oc edit configmap greeting-config* 50 | # HINT: Type ':wq' to exit from vi 51 | ---- 52 | 53 | You'll see that the _config.json_ is now part of the YAML file: 54 | 55 | [source, yaml, subs="normal,attributes"] 56 | ---- 57 | apiVersion: v1 58 | data: 59 | *config.json: | 60 | { 61 | "GREETING": "Hello {name} from ConfigMap" 62 | }* 63 | kind: ConfigMap 64 | ... 65 | ---- 66 | 67 | You can, of course, edit this ConfigMap in the editor too. If you do, edit only the value for the greeting variable. 68 | 69 | There are several ways to access the values in this ConfigMap: 70 | 71 | * Mount the entries (in our case, config.json) as a file. 72 | * Access from the Kubernetes API (we won't cover this today). 73 | 74 | Let's see how we can mount the configurations as files under a specific directory, e.g., _/etc/config/config.json_. 75 | 76 | First, edit the Helloworld Service Deployment: 77 | 78 | [source, bash, subs="normal,attributes"] 79 | ---- 80 | $ *oc edit deployment helloworld-service-vertx* 81 | ---- 82 | include::includes/tip.adoc[] 83 | 84 | In the editor, add volumes and volume mounts (important - indentation matters!): 85 | 86 | [source,yaml, subs="normal,attributes"] 87 | ---- 88 | apiVersion: v1 89 | kind: DeploymentConfig 90 | ... 91 | spec: 92 | ... 93 | template: 94 | ... 95 | spec: 96 | *volumes: 97 | - name: config-volume 98 | configMap: 99 | name: greeting-config* 100 | containers: 101 | - image: rafabene/microservices-helloworld-vertx:1.0 102 | *volumeMounts: 103 | - name: config-volume 104 | mountPath: /etc/config* 105 | ... 106 | ---- 107 | 108 | This will make the configuration file available as the file _/etc/config/config.json_. Let's verify by going into the pod itself (remember how to do this by using _kubectl exec_? You can also use _oc exec_, but now you will learn another option: _oc rsh_): 109 | 110 | First, find the pod name: 111 | 112 | [source, bash, subs="normal,attributes"] 113 | ---- 114 | $ *oc get pods* 115 | NAME READY STATUS RESTARTS AGE 116 | ... 117 | helloworld-service-vertx-7-e1o5u 1/1 Running 0 54s 118 | helloworld-service-vertx-7-sgosp 1/1 Running 0 40s 119 | ... 120 | ---- 121 | 122 | Then, run a shell inside the pod, and see what's in _/etc/config_: 123 | 124 | [source,bash, subs="normal,attributes"] 125 | ---- 126 | $ *oc rsh helloworld-service-vertx-7-?????* 127 | 128 | sh-4.2$ *ls /etc/config/* 129 | config.json 130 | 131 | sh-4.2$ *cat /etc/config/config.json* 132 | { 133 | "GREETING": "Hello {name} from ConfigMap" 134 | } 135 | 136 | sh-4.2$ *exit* 137 | exit 138 | ---- 139 | 140 | NOTE: Don't forget to exit out of the pod environment! 141 | 142 | Great, the file is there, but the application needs to be configured to reference to the file. Vert.x can reference to an external configuration with the command line argument: 143 | 144 | [source,subs="normal,attributes"] 145 | ---- 146 | -conf /etc/config/config.json 147 | ---- 148 | 149 | Recall how you were able to configure the command line arguments in the previous steps. You know the drill. Edit the Helloworld Service Deployment and add the arguments: 150 | 151 | [source,yaml, subs="normal,attributes"] 152 | ---- 153 | apiVersion: extensions/v1beta1 154 | kind: Deployment 155 | ... 156 | spec: 157 | ... 158 | template: 159 | ... 160 | spec: 161 | ... 162 | containers: 163 | - image: rafabene/microservices-helloworld-vertx:... 164 | *args: 165 | - -conf 166 | - /etc/config/config.json* 167 | ... 168 | ---- 169 | 170 | Check the application to see it is using the new greeting string. 171 | 172 | Last, but not least, you can also specify simple key/value pairs in ConfigMap, and then expose them directly as environmental variables too. See the http://kubernetes.io/docs/user-guide/configmap/[ConfigMap guide] for more examples. 173 | -------------------------------------------------------------------------------- /lab/managing-credentials.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | ### Managing Credentials 17 | Duration: 20:00 18 | 19 | ConfigMap is great to store text-based configurations. Depending on your use cases, it may not be the best place to store your credentials (which sometimes may be a binary file rather than text). Secrets can be used to hold sensitive information, such as passwords, OAuth tokens, and SSH keys. Entries in Secrets are Base64 encoded. However, Secrets are not additionally encrypted when stored in Kubernetes. 20 | 21 | In this section, we'll create a Secret that contains the MySQL username and password. We'll subsequently update both the MySQL Replication Controller and the Guestbook Service to refer to the same credentials. 22 | 23 | First, let's create a Secret with username and password the command line: 24 | 25 | [source, bash, subs="normal,attributes"] 26 | ---- 27 | $ *oc create secret generic mysql-secret \ 28 | --from-literal=username=app,password=1337* 29 | secret "mysql-secret" created 30 | ---- 31 | 32 | If you look into the newly created Secret, you'll see that the values are Base64 encoded: 33 | 34 | [source, bash, subs="normal,attributes"] 35 | ---- 36 | $ *oc edit secret mysql-secret* 37 | # HINT: Type ':wq' to exit from vi 38 | ---- 39 | 40 | In the Editor, you'll see: 41 | 42 | [source, yaml, subs="normal,attributes"] 43 | ---- 44 | apiVersion: v1 45 | data: 46 | password: MTMzNw== 47 | username: YXBw 48 | kind: Secret 49 | ... 50 | ---- 51 | 52 | In the pods, you can access these values a couple of ways: 53 | 54 | * Mount each entry as a file under a directory (similar to what we did with ConfigMap) 55 | * Use http://kubernetes.io/docs/user-guide/downward-api/#exposing-pod-information-into-a-container[Downward API] to expose each entry as an Environmental Variable (which you can also do with ConfigMap). 56 | 57 | Since the MySQL container already expects username and password to be configured using the Environmental Variables, we'll use the latter (Downward API) approach. 58 | 59 | First, in kubernetes/ directory, edit the mysql-deployment.yaml. Edit the mysql Deployment and modify the variables MYSQL_USER and MYSQL_PASSWORD with the following values: 60 | 61 | [source, yaml, subs="normal,attributes"] 62 | ---- 63 | apiVersion: extensions/v1beta1 64 | kind: Deployment 65 | metadata: 66 | name: mysql 67 | spec: 68 | ... 69 | template: 70 | spec: 71 | containers: 72 | - resources: 73 | ... 74 | env: 75 | - name: MYSQL_ROOT_PASSWORD 76 | value: yourpassword 77 | - name: MYSQL_DATABASE 78 | value: guestbook 79 | *- name: MYSQL_USER 80 | valueFrom: 81 | secretKeyRef: 82 | name: mysql-secret 83 | key: username 84 | - name: MYSQL_PASSWORD 85 | valueFrom: 86 | secretKeyRef: 87 | name: mysql-secret 88 | key: password* 89 | ... 90 | ---- 91 | 92 | We'll also need to recreate the *PersistentVolumeClaim* too in order to force MySQL to create the user): 93 | 94 | [source, bash, subs="normal,attributes"] 95 | ---- 96 | $ *oc delete pvc/mysql-pvc deployment/mysql* 97 | persistentvolumeclaim "mysql-pvc" deleted 98 | replicationcontroller "mysql" deleted 99 | 100 | $ *oc create -f mysql-pvc.yaml -f mysql-deployment.yaml* 101 | persistentvolumeclaim "mysql-pvc" created 102 | deployment "mysql" created 103 | ---- 104 | 105 | Once MySQL comes back up, test the connection by running MySQL client directly inside the pod. Recall how you can use _oc rsh_ to do this: 106 | 107 | [source, bash, subs="normal,attributes"] 108 | ---- 109 | $ *oc get pods* 110 | NAME READY STATUS RESTARTS AGE 111 | ... 112 | mysql-... 1/1 Running 0 2m 113 | ... 114 | 115 | $ *oc rsh mysql-...* 116 | sh-4.2$ *mysql -u app -p -h 127.0.0.1* 117 | Enter password: *1337* 118 | Welcome to the MySQL monitor. Commands end with ; or \g. 119 | Your MySQL connection id is 3 120 | Server version: 5.6.24 MySQL Community Server (GPL) 121 | 122 | Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. 123 | 124 | Oracle is a registered trademark of Oracle Corporation and/or its 125 | affiliates. Other names may be trademarks of their respective 126 | owners. 127 | 128 | Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. 129 | 130 | mysql> *exit* 131 | Bye 132 | sh-4.2$ *exit* 133 | exit 134 | ---- 135 | 136 | Great! Now MySQL is picking up the credentials from the Secret. 137 | 138 | Next, configure the Guestbook Service and update the Environmental Variables too. 139 | 140 | Now edit the Guestbook Service deployment and add a couple of environment variables: 141 | 142 | [source, yaml, subs="normal,attributes"] 143 | ---- 144 | apiVersion: extensions/v1beta1 145 | kind: Deployment 146 | ... 147 | spec: 148 | ... 149 | template: 150 | ... 151 | spec: 152 | … 153 | containers: 154 | - image: rafabene/microservices-guestbook:1.0 155 | *env: 156 | - name: DATASOURCE_USERNAME 157 | valueFrom: 158 | secretKeyRef: 159 | name: mysql-secret 160 | key: username 161 | - name: DATASOURCE_PASSWORD 162 | valueFrom: 163 | secretKeyRef: 164 | name: mysql-secret 165 | key: password* 166 | ... 167 | ---- 168 | 169 | Once the deployment completes, check that the application is still working. -------------------------------------------------------------------------------- /guestbook-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 4.0.0 21 | 22 | com.redhat.developers.guestbook 23 | guestbook-service 24 | 0.0.1-SNAPSHOT 25 | war 26 | guestbook 27 | Guestbook microservice running on WildFly Swarm 28 | 29 | https://developers.redhat.com/ 30 | 31 | 32 | Apache License, Version 2.0 33 | repo 34 | http://www.apache.org/licenses/LICENSE-2.0.html 35 | 36 | 37 | 38 | 39 | 41 | 43 | UTF-8 44 | 45 | 46 | 1.0.0.Final 47 | 48 | 49 | 1.6.1 50 | 51 | 52 | 2.10 53 | 2.1.1 54 | 55 | 56 | 1.8 57 | 1.8 58 | 59 | 5.1.38 60 | 61 | 62 | 63 | 64 | 65 | 69 | 70 | org.wildfly.swarm 71 | bom 72 | ${version.wildfly.swarm} 73 | pom 74 | import 75 | 76 | 77 | org.apache.deltaspike.distribution 78 | distributions-bom 79 | ${deltaspike.version} 80 | pom 81 | import 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | org.wildfly.swarm 92 | jaxrs-jsonp 93 | 94 | 95 | org.wildfly.swarm 96 | jaxrs-cdi 97 | 98 | 99 | org.wildfly.swarm 100 | datasources 101 | 102 | 103 | org.wildfly.swarm 104 | jpa 105 | 106 | 107 | org.wildfly.swarm 108 | undertow 109 | 110 | 111 | 112 | 113 | org.apache.deltaspike.core 114 | deltaspike-core-api 115 | compile 116 | 117 | 118 | 119 | org.apache.deltaspike.core 120 | deltaspike-core-impl 121 | runtime 122 | 123 | 124 | 125 | org.apache.deltaspike.modules 126 | deltaspike-data-module-api 127 | compile 128 | 129 | 130 | 131 | org.apache.deltaspike.modules 132 | deltaspike-data-module-impl 133 | runtime 134 | 135 | 136 | 137 | 138 | 139 | org.hibernate.javax.persistence 140 | hibernate-jpa-2.1-api 141 | 1.0.0.Final 142 | 143 | 144 | 145 | mysql 146 | mysql-connector-java 147 | ${version.mysql} 148 | 149 | 150 | 151 | 152 | 153 | 155 | ${project.artifactId} 156 | 157 | 158 | src/main/resources 159 | true 160 | 161 | 162 | 163 | 164 | maven-war-plugin 165 | ${version.war.plugin} 166 | 167 | 168 | false 169 | 170 | 171 | 172 | 173 | 174 | org.wildfly.swarm 175 | wildfly-swarm-plugin 176 | ${version.wildfly.swarm} 177 | 178 | com.redhat.developers.guestbook.Main 179 | 180 | 181 | 182 | 183 | package 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | -------------------------------------------------------------------------------- /lab/extra.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | 17 | ## Extra Credit 18 | Duration: 10:00 19 | 20 | Here are some ideas for next steps. 21 | 22 | ### Try OpenShift Source-to-image feature. 23 | 24 | OpenShift allows you to get an Source code and transform it in a container image. This is very useful for people who don't know how to create your own image. OpenShift automatically detects the language and uses an appropriate "builder" to convert that in a functional container image. Actually the following languages are supported: Ruby, JavaEE, NodeJS, PHP, Pytho and Perl. 25 | 26 | Let's see how it works using the link:https://github.com/redhat-developer-demos/kubernetes-lab/tree/master/frontend[frontend sources] as an example: 27 | 28 | First, let's delete the existing frontend *Route*, *Service* and *ReplicationController* 29 | 30 | [source, bash, subs="normal,attributes"] 31 | ---- 32 | $ *oc delete deployment,svc,route frontend-ui* 33 | deployment "frontend-ui" deleted 34 | service "frontend-ui" deleted 35 | route "frontend-ui" deleted 36 | 37 | $ *oc new-app --name=frontend-ui \ 38 | https://github.com/redhat-developer-demos/kubernetes-lab \ 39 | --strategy=source --context-dir=frontend* 40 | --> Found image 0b37bce (5 weeks old) in image stream "openshift/nodejs" under tag "4" for "nodejs" 41 | 42 | Node.js 4 43 | --------- 44 | Platform for building and running Node.js 4 applications 45 | 46 | Tags: builder, nodejs, nodejs4 47 | 48 | * The source repository appears to match: nodejs 49 | * A source build using source code from https://github.com/redhat-developer-demos/kubernetes-lab will be created 50 | * The resulting image will be pushed to image stream "frontend-ui:latest" 51 | * Use 'start-build' to trigger a new build 52 | * This image will be deployed in deployment config "frontend-ui" 53 | * Port 8080/tcp will be load balanced by service "frontend-ui" 54 | * Other containers can access this service through the hostname "frontend-ui" 55 | 56 | --> Creating resources ... 57 | imagestream "frontend-ui" created 58 | buildconfig "frontend-ui" created 59 | deploymentconfig "frontend-ui" created 60 | service "frontend-ui" created 61 | --> Success 62 | Build scheduled, use 'oc logs -f bc/frontend-ui' to track its progress. 63 | Run 'oc status' to view your app. 64 | ---- 65 | 66 | This will trigger the build inside OpenShift. You can explore it using the following commands: 67 | 68 | [source, bash, subs="normal,attributes"] 69 | ---- 70 | $ *oc get builds* 71 | NAME TYPE FROM STATUS STARTED DURATION 72 | frontend-ui-1 Source Git@e09f71e Running About a minute ago 1m23s 73 | 74 | $ *oc logs -f bc/frontend-ui* 75 | ---- 76 | 77 | You can also see the build happening in the OpenShift console: 78 | 79 | image::images/build.png[Build,float="center",align="center"] 80 | 81 | Don't forget to expose the *Route* and try the application. Do you remember how to it, right? 82 | 83 | #### Building a new version. 84 | 85 | When OpenShift is installed in a public address, you can enable link:https://developer.github.com/webhooks/[Github webhooks] that triggers a new OpenShift build each commit. This is useful for Continuous Integration environments. You can read more about it in the following link:https://docs.openshift.com/enterprise/3.2/dev_guide/builds.html#webhook-triggers[guide]. 86 | 87 | You can also trigger a new build using *oc start-build * command. It allows you to specify different location for the sources. Try it yourself! Clone the repository or make a local change and run the command. 88 | 89 | Some examples that you can try. 90 | 91 | NOTE: To build from local, you should be in the root path of the kubernetes lab (kubernetes-lab) because you already specified the --context-dir=frontend parameter. 92 | 93 | [source, bash, subs="normal,attributes"] 94 | ---- 95 | $ cd kubernetes-lab/ 96 | $ *oc start-build frontend-ui \ 97 | --from-dir=. \ 98 | --follow* 99 | Uploading directory "." as binary input for the build ... 100 | frontend-ui-? 101 | ---- 102 | 103 | You can also build from Github sources 104 | 105 | [source, bash, subs="normal,attributes"] 106 | ---- 107 | $ *oc start-build frontend-ui \ 108 | --git-repository=https://github.com/rafabene/kubernetes-lab \ 109 | --follow* 110 | frontend-ui-? 111 | I0804 08:03:45.260863 1 source.go:197] Downloading "https://github.com/redhat-developer-demos/kubernetes-lab" ... 112 | ---- 113 | 114 | ### Try some microservices 115 | 116 | link:https://developers.redhat.com/[Red Hat Developers] has worked intensively to integrate different opensource technologies and create a showcase of how cloud-native apps can interact in a microservices architecture: The link:https://github.com/redhat-helloworld-msa/helloworld-msa[Helloworld-MSA] playground! 117 | 118 | This distinct demo allows developers execute some “helloworld” microservices, built using different technologies, and explore the following features: 119 | 120 | - Different implementations: link:http://wildfly-swarm.io/[WildFly Swarm], Spring Boot, link:http://vertx.io/[Vert.X] and link:https://nodejs.org/en/[NodeJS]. 121 | - 3 invocation patterns: Browser as a client, link:http://microservices.io/patterns/apigateway.html[API-Gateway], Chained invocation; 122 | - link:http://microservices.io/patterns/service-registry.html[Service-registry], Self-healing, Load-balancing and link:http://blog.christianposta.com/deploy/blue-green-deployments-a-b-testing-and-canary-releases/[Blue/Green deployments] – Provided by link:https://www.openshift.com/[OpenShift]; 123 | - JVM Monitoring – Provided by link:https://jolokia.org/[Jolokia]; 124 | - Service Monitoring – Provided by link:https://github.com/Netflix/Hystrix/tree/master/hystrix-dashboard[Hystrix Dashboard] via link:https://github.com/fabric8io/kubeflix[Kubeflix]; 125 | - Service Tracing – Provided by link:http://zipkin.io/[Zipkin] via link:https://github.com/fabric8io/kubernetes-zipkin[Fabric8’s Kubernetes Zipkin]; 126 | - link:https://github.com/Netflix/Hystrix/wiki/Configuration#CommandCircuitBreaker[Circuit breaker] and link:https://github.com/Netflix/Hystrix/wiki/How-To-Use#Fallback[Fallback] – Provided by link:https://github.com/Netflix/Hystrix[Hystrix]; 127 | - REST invocation – Provided by link:https://github.com/OpenFeign/feign[Feign] via link:https://github.com/OpenFeign/feign/tree/master/hystrix[HystrixFeign]; 128 | - REST API specification – Provided by link:http://swagger.io/[Swagger]; 129 | - CI/CD pipelines – Provided by link:https://jenkins.io/[Jenkins] with link:https://wiki.jenkins-ci.org/display/JENKINS/Pipeline+Plugin[Pipeline] plugin. 130 | 131 | image::images/helloworldmsa.png[OpenShift,float="center",align="center"] -------------------------------------------------------------------------------- /lab/openshift.adoc: -------------------------------------------------------------------------------- 1 | // JBoss, Home of Professional Open Source 2 | // Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual 3 | // contributors by the @authors tag. See the copyright.txt in the 4 | // distribution for a full listing of individual contributors. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | ### A console to manage your Kubernetes Cluster 17 | Duration: 10:00 18 | 19 | Until now we have been using Kubernetes CLI (_kubectl_) to manage our cluster. Wouldn't it be good if we could visualize/manage our cluster in a user/interface? 20 | 21 | Let's take a look in OpenShift console. 22 | 23 | NOTE: Don't worry. This is still a Kubernetes lab! OpenShift runs on top of Kubernetes but adds features like deployments, source-to-image, user management, routes, etc. 24 | 25 | Access https://{ocp-cluster} 26 | 27 | [NOTE] 28 | ==== 29 | Accept the self-signed HTTPS certificate. 30 | 31 | Login with the credentials: 32 | 33 | - username: *userX* 34 | - password: *openshift* 35 | ==== 36 | 37 | Click on *OpenShift sample project* and now you will see all Kubernetes objects that you have created with kubectl command. This happens because OpenShift is built on top of Kubernetes. 38 | 39 | image::images/openshift.png[OpenShift,float="center",align="center"] 40 | 41 | Take some minutes to explore this interface. 42 | 43 | - Click on the Service and Deployment links and see the details. 44 | - Click on the POD number and see the list of PODS. Select one POD to explore. 45 | - Explore the POD details and the other tabs (Environment, Logs, Terminal and Events) 46 | - In the right top corner, click in the gray _Actions_ button and check that you can also edit the YAML file. 47 | 48 | NOTE: The blue bars on top of the pods are "Label filters" that were applied to select just the specific pods for the *ReplicationController* that you clicked. 49 | 50 | image::images/pod.png[Pod,float="center",align="center"] 51 | 52 | 53 | Back to the *Overview* page and check that you can scale up and scale down the number of the pods simply by clicking on the gray arrows on the right hand side of the pods number. 54 | 55 | Let's perform a rolling-update in the shell and see how it behaves visually in OpenShift. Execute the following command and return to the OpenShift console in the browser: 56 | 57 | [source, bash, subs="normal,attributes"] 58 | ---- 59 | $ *kubectl set image deployment/frontend-ui frontend-ui=rafabene/microservices-frontend:1.0* 60 | deployment.extensions/frontend-ui image updated 61 | ---- 62 | 63 | image::images/rolling-update.png[Rolling Update,float="center",align="center"] 64 | 65 | #### A word about oc command 66 | 67 | You will be introduced now to the _oc_ command. You can think of it as a super set of _kubectl_. You can use it to do almost all operations that you did with _kubectl_. Let's try: 68 | 69 | [source, bash, subs="normal,attributes"] 70 | ---- 71 | $ *oc get pods* 72 | NAME READY STATUS RESTARTS AGE 73 | frontend-ui-anbox 1/1 Running 0 1h 74 | frontend-ui-l7jbo 1/1 Running 0 1h 75 | guestbook-service-h4fvr 1/1 Running 0 1h 76 | helloworld-service-vertx-1-738ux 1/1 Running 0 5m 77 | mysql-yhl82 1/1 Running 0 1h 78 | 79 | $ *oc get deployments* 80 | NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE 81 | frontend-ui 2 2 2 2 36m 82 | guestbook-service 1 1 1 1 30m 83 | helloworld-service-vertx 2 2 2 2 32m 84 | mysql 1 1 1 1 33m 85 | 86 | $ *oc get service* 87 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 88 | frontend-ui LoadBalancer 172.30.58.95 172.29.26.18,172.29.26.18 80:31391/TCP 35m 89 | guestbook-service ClusterIP 172.30.205.209 8080/TCP 30m 90 | helloworld-service-vertx ClusterIP 172.30.9.65 8080/TCP 33m 91 | mysql ClusterIP 172.30.240.203 3306/TCP 33m 92 | 93 | $ *oc describe service frontend-ui* 94 | Name: frontend-ui 95 | Namespace: sample-project 96 | Labels: app=frontend-ui,lab=kubernetes-lab 97 | Selector: app=frontend-ui 98 | Type: LoadBalancer 99 | IP: 172.30.212.103 100 | Port: http-80 80/TCP 101 | NodePort: http-80 32186/TCP 102 | Endpoints: 172.17.0.2:8080,172.17.0.5:8080 103 | Session Affinity: None 104 | No events. 105 | 106 | $ *oc delete pod frontend-ui-?????* 107 | pod "frontend-ui-?????" deleted 108 | ---- 109 | 110 | Now let's use _oc_ to: 111 | 112 | - Easily set a ReadinessProbe. 113 | 114 | 115 | To create a *ReadinessProbe* with _oc_ command, execute: 116 | 117 | [source, bash, subs="normal,attributes"] 118 | ---- 119 | $ *oc set probe deployment helloworld-service-vertx --readiness --get-url=http://:8080/api/hello/Kubernetes* 120 | deployment "helloworld-service-vertx" updated 121 | ---- 122 | 123 | This was much easier than the previous time, right? 124 | You can use _oc get deployment helloworld-service-vertx -o yaml_ to see the configuration inside the *DeploymentConfig* object. 125 | 126 | TIP: You can also use *oc set probe deployment helloworld-service-vertx --readiness --remove* to remove the *ReadinessProbe* using *oc* command. 127 | 128 | - Create a route to frontend-ui. 129 | 130 | Now let's create a route and expose the service. But first let's understand what is a *Route*. 131 | Remember that we needed to execute *kubectl describe service frontend-ui* to get the *NodePort*? 132 | A *Route* uses the port 80 of OpenShift and "routes" the requests based on the defined hostname. 133 | Let's see how it works. Execute: 134 | 135 | [source, bash, subs="normal,attributes"] 136 | ---- 137 | 138 | $ *oc expose service frontend-ui* 139 | route "frontend-ui" exposed 140 | 141 | $ *oc get routes* 142 | NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD 143 | frontend-ui frontend-ui-labX.apps.boston.openshiftworkshop.com frontend-ui http-80 None 144 | ---- 145 | 146 | 147 | [source, bash, subs="normal,attributes"] 148 | ---- 149 | Now point your browser to the route http://frontend-ui-labX.{app-domain} 150 | ---- 151 | 152 | Amazing, right? 153 | 154 | TIP: You can delete the *Route* with the command: *oc delete route frontend-ui* 155 | 156 | [NOTE] 157 | ==== 158 | *How frontend.10.1.2.2.nip.io resolved to 10.1.2.2?* 159 | 160 | link:http://www.nip.io/[NIP.IO] allows you to map any IP Address in the following DNS wildcard entries: 161 | 162 | - 10.0.0.1.nip.io maps to 10.0.0.1 163 | - app.10.0.0.1.nip.io maps to 10.0.0.1 164 | - customer1.app.10.0.0.1.nip.io maps to 10.0.0.1 165 | - customer2.app.10.0.0.1.nip.io maps to 10.0.0.1 166 | - otherapp.10.0.0.1.nip.io maps to 10.0.0.1 167 | 168 | NIP.IO maps *.*.nip.io to the corresponding **, even 127.0.0.1.nip.io maps to 127.0.0.1 169 | ==== -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------