├── .github └── workflows │ └── build.yml ├── .gitignore ├── HOW-TO-RUN.md ├── LICENSE ├── README.md ├── WIE-LAUFEN.md └── microservice-kubernetes-demo ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── apache ├── 000-default.conf ├── Dockerfile └── index.html ├── docker-build.sh ├── kubernetes-deploy.sh ├── kubernetes-remove.sh ├── microservice-kubernetes-demo-catalog ├── Dockerfile ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── ewolff │ │ │ └── microservice │ │ │ └── catalog │ │ │ ├── CatalogApp.java │ │ │ ├── Item.java │ │ │ ├── ItemRepository.java │ │ │ ├── SpringRestDataConfig.java │ │ │ └── web │ │ │ └── CatalogController.java │ └── resources │ │ ├── application.properties │ │ ├── bootstrap.properties │ │ └── templates │ │ ├── item.html │ │ ├── itemlist.html │ │ ├── layout.html │ │ ├── searchForm.html │ │ └── success.html │ └── test │ ├── java │ └── com │ │ └── ewolff │ │ └── microservice │ │ └── catalog │ │ ├── CatalogTestApp.java │ │ ├── CatalogWebIntegrationTest.java │ │ ├── RepositoryTest.java │ │ └── cdc │ │ ├── CatalogClient.java │ │ ├── CatalogConsumerDrivenContractTest.java │ │ └── Item.java │ └── resources │ ├── application-test.properties │ └── bootstrap.properties ├── microservice-kubernetes-demo-customer ├── Dockerfile ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── ewolff │ │ │ └── microservice │ │ │ └── customer │ │ │ ├── Customer.java │ │ │ ├── CustomerApp.java │ │ │ ├── CustomerRepository.java │ │ │ ├── SpringRestDataConfig.java │ │ │ └── web │ │ │ └── CustomerController.java │ └── resources │ │ ├── application.properties │ │ ├── bootstrap.properties │ │ └── templates │ │ ├── customer.html │ │ ├── customerlist.html │ │ ├── layout.html │ │ └── success.html │ └── test │ ├── java │ └── com │ │ └── ewolff │ │ └── microservice │ │ └── customer │ │ ├── CustomerTestApp.java │ │ ├── CustomerWebIntegrationTest.java │ │ └── cdc │ │ ├── Customer.java │ │ ├── CustomerClient.java │ │ └── CustomerConsumerDrivenContractTest.java │ └── resources │ ├── application-test.properties │ └── bootstrap.properties ├── microservice-kubernetes-demo-order ├── Dockerfile ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── ewolff │ │ │ └── microservice │ │ │ └── order │ │ │ ├── OrderApp.java │ │ │ ├── clients │ │ │ ├── CatalogClient.java │ │ │ ├── Customer.java │ │ │ ├── CustomerClient.java │ │ │ └── Item.java │ │ │ └── logic │ │ │ ├── Order.java │ │ │ ├── OrderController.java │ │ │ ├── OrderLine.java │ │ │ ├── OrderRepository.java │ │ │ ├── OrderService.java │ │ │ └── SpringRestDataConfig.java │ └── resources │ │ ├── application.properties │ │ ├── bootstrap.properties │ │ ├── static │ │ └── monitor.html │ │ └── templates │ │ ├── layout.html │ │ ├── order.html │ │ ├── orderForm.html │ │ ├── orderlist.html │ │ └── success.html │ └── test │ ├── java │ └── com │ │ └── ewolff │ │ └── microservice │ │ └── order │ │ ├── OrderTestApp.java │ │ ├── catalogstub │ │ └── CatalogStub.java │ │ ├── customerstub │ │ └── CustomerStub.java │ │ └── logic │ │ ├── CatalogConsumerDrivenContractTest.java │ │ ├── CustomerConsumerDrivenContractTest.java │ │ └── OrderWebIntegrationTest.java │ └── resources │ ├── application-test.properties │ └── bootstrap.properties ├── microservices.yaml ├── mvnw ├── mvnw.cmd └── pom.xml /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build and Publish Docker Images 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Set up JDK 11 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: 11 20 | - name: Build bonus microservice with Maven 21 | run: cd microservice-kubernetes-demo && mvn -B package --file pom.xml 22 | - name: Log into registry 23 | run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin 24 | - name: Create and push Docker images 25 | run: cd microservice-kubernetes-demo && sh ./docker-build.sh 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .vagrant 3 | .springBeans 4 | .classpath 5 | .project 6 | .settings 7 | .idea 8 | *.iml 9 | target/ 10 | pom.xml.tag 11 | pom.xml.releaseBackup 12 | pom.xml.versionsBackup 13 | pom.xml.next 14 | release.properties 15 | dependency-reduced-pom.xml 16 | buildNumber.properties 17 | .mvn/timing.properties -------------------------------------------------------------------------------- /HOW-TO-RUN.md: -------------------------------------------------------------------------------- 1 | # How to Run 2 | 3 | This is a step-by-step guide how to run the example: 4 | 5 | ## Installation 6 | 7 | * Install 8 | [minikube](https://github.com/kubernetes/minikube/releases). Minikube 9 | is a Kubernetes environment in a virtual machine that is easy to use 10 | and install. It is not meant for production but to test Kubernetes or 11 | for developer environments. 12 | 13 | * Install 14 | [kubectl](https://kubernetes.io/docs/tasks/kubectl/install/). This 15 | is the command line interface for Kubernetes. 16 | 17 | ## Build the Docker images (optional) 18 | 19 | This step is *optional*. There are Docker images on the public Docker 20 | Hub that are used if you do not build your own. 21 | 22 | * The example is implemented in Java. See 23 | https://www.java.com/en/download/help/download_options.xml . The 24 | examples need to be compiled so you need to install a JDK (Java 25 | Development Kit). A JRE (Java Runtime Environment) is not 26 | sufficient. After the installation you should be able to execute 27 | `java` and `javac` on the command line. 28 | 29 | * The example run in Docker Containers. You need to install Docker 30 | Community Edition, see https://www.docker.com/community-edition/ 31 | . You should be able to run `docker` after the installation. 32 | 33 | Change to the directory `microservice-kubernetes-demo` and run `./mvnw clean 34 | package` or `mvnw.cmd clean package` (Windows). This will take a while: 35 | 36 | ``` 37 | [~/microservice-kubernetes/microservice-kubernetes-demo]./mvnw clean package 38 | .... 39 | [INFO] 40 | [INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ microservice-kubernetes-demo-order --- 41 | [INFO] Building jar: /Users/wolff/microservice-kubernetes/microservice-kubernetes-demo/microservice-kubernetes-demo-order/target/microservice-kubernetes-demo-order-0.0.1-SNAPSHOT.jar 42 | [INFO] 43 | [INFO] --- spring-boot-maven-plugin:1.4.5.RELEASE:repackage (default) @ microservice-kubernetes-demo-order --- 44 | [INFO] ------------------------------------------------------------------------ 45 | [INFO] Reactor Summary: 46 | [INFO] 47 | [INFO] microservice-kubernetes-demo ....................... SUCCESS [ 0.986 s] 48 | [INFO] microservice-kubernetes-demo-customer .............. SUCCESS [ 16.953 s] 49 | [INFO] microservice-kubernetes-demo-catalog ............... SUCCESS [ 18.016 s] 50 | [INFO] microservice-kubernetes-demo-order ................. SUCCESS [ 18.512 s] 51 | [INFO] ------------------------------------------------------------------------ 52 | [INFO] BUILD SUCCESS 53 | [INFO] ------------------------------------------------------------------------ 54 | [INFO] Total time: 57.633 s 55 | [INFO] Finished at: 2017-09-08T09:36:32+02:00 56 | [INFO] Final Memory: 56M/420M 57 | [INFO] ------------------------------------------------------------------------ 58 | ``` 59 | 60 | If this does not work: 61 | 62 | * Ensure that `settings.xml` in the directory `.m2` in your home 63 | directory contains no configuration for a specific Maven repo. If in 64 | doubt: delete the file. 65 | 66 | * The tests use some ports on the local machine. Make sure that no 67 | server runs in the background. 68 | 69 | * Skip the tests: `./mvnw clean package -Dmaven.test.skip=true` or 70 | `mvnw.cmd clean package -Dmaven.test.skip=true` (Windows). 71 | 72 | * In rare cases dependencies might not be downloaded correctly. In 73 | that case: Remove the directory `repository` in the directory `.m2` 74 | in your home directory. Note that this means all dependencies will 75 | be downloaded again. 76 | 77 | Now the Java code has been compiles. The next step is to create Docker 78 | images and upload them to the public Docker Hub: 79 | 80 | * Create an account at the public 81 | [Docker Hub](https://hub.docker.com/). 82 | 83 | * Log in to your Docker Hub account by entering `docker login` on the command 84 | line. 85 | 86 | * Set the environment variable `DOCKER_ACCOUNT` to the name of the account. 87 | 88 | * Run `docker-build.sh` in the directory 89 | `microservice-kubernetes-demo`. It builds the images and uploads them to the 90 | Docker Hub using your account. Of course uploading the images takes 91 | some time: 92 | 93 | ``` 94 | [~/microservice-kubernetes/microservice-kubernetes-demo]export DOCKER_ACCOUNT=ewolff 95 | [~/microservice-kubernetes/microservice-kubernetes-demo]echo $DOCKER_ACCOUNT 96 | ewolff 97 | [~/microservice-kubernetes/microservice-kubernetes-demo]./docker-build.sh 98 | ... 99 | Removing intermediate container 36e9b0c2ac0e 100 | Successfully built b76261d1e4ee 101 | f4ffcb9c643d: Pushed 102 | 14c5bfa09694: Mounted from ewolff/microservice-kubernetes-demo-order 103 | 41a5c76632fc: Mounted from ewolff/microservice-kubernetes-demo-order 104 | 5bef08742407: Mounted from ewolff/microservice-kubernetes-demo-order 105 | latest: digest: sha256:36d87ea5c8628da9a6677c1eafb9009c8f99310f5376872e7b9a1edace37d1a0 size: 1163 106 | ``` 107 | 108 | ## Run the containers 109 | 110 | * Create a Minikube instance with `minikube start --memory=4000`. This 111 | will set the memory of the Kubernetes VM to 4.000 MB - which should 112 | be enough for most experiments: 113 | 114 | ``` 115 | [~/microservice-kubernetes]minikube start --memory=4000 116 | Starting local Kubernetes v1.7.5 cluster... 117 | Starting VM... 118 | Getting VM IP address... 119 | Moving files into cluster... 120 | Setting up certs... 121 | Connecting to cluster... 122 | Setting up kubeconfig... 123 | Starting cluster components... 124 | Kubectl is now configured to use the cluster. 125 | ``` 126 | 127 | * If you created your own Docker images: Ensure that the environment 128 | variable `DOCKER_ACCOUNT` is set to the name of the account on Docker 129 | Hub you created. 130 | 131 | * Run `kubernetes-deploy.sh` in the directory 132 | `microservice-kubernetes-demo` : 133 | 134 | ``` 135 | [~/microservice-kubernetes/microservice-kubernetes-demo]./kubernetes-deploy.sh 136 | deployment "apache" created 137 | service "apache" exposed 138 | deployment "catalog" created 139 | service "catalog" exposed 140 | deployment "customer" created 141 | service "customer" exposed 142 | deployment "order" created 143 | service "order" exposed 144 | ``` 145 | 146 | An alternative is to use the command `kubectl apply -f 147 | microservices.yaml` . This command takes the description of the 148 | services and deployments from the file `microservices.yaml` and 149 | creates them if they do not already exist. The YAML uses the images 150 | from the Docker Hub account `ewolff`. You will need to modify the YAML 151 | if you want to use different images. 152 | 153 | That deploys the images. It creates Pods. Pods might contain one or 154 | many Docker containers. In this case each Pod contains just one 155 | Docker container. 156 | 157 | Also services are created. Services have a clusterwide unique IP 158 | adress and a DNS entry. Service can use many Pods to do load 159 | balancing. To actually view the services: 160 | 161 | * Run `kubectl get services` to see all services: 162 | 163 | ``` 164 | [~/microservice-kubernetes/microservice-kubernetes-demo]kubectl get services 165 | NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE 166 | apache 10.0.0.90 80:31214/TCP 46s 167 | catalog 10.0.0.219 8080:30161/TCP 46s 168 | customer 10.0.0.163 8080:30620/TCP 45s 169 | kubernetes 10.0.0.1 443/TCP 3m 170 | order 10.0.0.21 8080:30616/TCP 45s 171 | ``` 172 | 173 | 174 | * Run `kubectl describe services` for more 175 | details. This also works for pods (`kubectl describe pods`) and 176 | deployments (`kubectl describe deployments`). 177 | 178 | ``` 179 | [~/microservice-kubernetes/microservice-kubernetes-demo]kubectl describe services 180 | ... 181 | 182 | Name: order 183 | Namespace: default 184 | Labels: run=order 185 | Annotations: 186 | Selector: run=order 187 | Type: LoadBalancer 188 | IP: 10.0.0.21 189 | Port: 8080/TCP 190 | NodePort: 30616/TCP 191 | Endpoints: 172.17.0.7:8080 192 | Session Affinity: None 193 | Events: 194 | ``` 195 | 196 | * You can also get a list of the pods: 197 | 198 | ``` 199 | [~/microservice-kubernetes/microservice-kubernetes-demo]kubectl get pods 200 | NAME READY STATUS RESTARTS AGE 201 | apache-3412280829-k5z5p 1/1 Running 0 2m 202 | catalog-269679894-60dr0 1/1 Running 0 2m 203 | customer-1984516559-1ffjk 1/1 Running 0 2m 204 | order-2204540131-nks5s 1/1 Running 0 2m 205 | ``` 206 | 207 | * ...and you can see the logs of a pod: 208 | 209 | ``` 210 | [~/microservice-kubernetes/microservice-kubernetes-demo]kubectl logs catalog-269679894-60dr0 211 | 212 | . ____ _ __ _ _ 213 | /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ 214 | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ 215 | \\/ ___)| |_)| | | | | || (_| | ) ) ) ) 216 | ' |____| .__|_| |_|_| |_\__, | / / / / 217 | =========|_|==============|___/=/_/_/_/ 218 | :: Spring Boot :: (v1.4.5.RELEASE) 219 | ... 220 | 2017-09-08 08:11:06.128 INFO 7 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup 221 | 2017-09-08 08:11:06.158 INFO 7 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 0 222 | 2017-09-08 08:11:06.746 INFO 7 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http) 223 | 2017-09-08 08:11:06.803 INFO 7 --- [ main] c.e.microservice.catalog.CatalogApp : Started CatalogApp in 53.532 seconds (JVM running for 54.296) 224 | ... 225 | ``` 226 | 227 | * You can also run commands in a pod: 228 | 229 | ``` 230 | [~/microservice-kubernetes/microservice-kubernetes-demo]kubectl exec catalog-269679894-60dr0 /bin/ls 231 | bin 232 | dev 233 | etc 234 | home 235 | lib 236 | lib64 237 | media 238 | microservice-kubernetes-demo-catalog-0.0.1-SNAPSHOT.jar 239 | mnt 240 | proc 241 | root 242 | run 243 | sbin 244 | srv 245 | sys 246 | tmp 247 | usr 248 | var 249 | ``` 250 | 251 | * You can even open a shell in a pod: 252 | 253 | ``` 254 | [~/microservice-kubernetes/microservice-kubernetes-demo]kubectl exec catalog-269679894-60dr0 -it /bin/sh 255 | / # ls 256 | bin proc 257 | dev root 258 | etc run 259 | home sbin 260 | lib srv 261 | lib64 sys 262 | media tmp 263 | microservice-kubernetes-demo-catalog-0.0.1-SNAPSHOT.jar usr 264 | mnt var 265 | / # 266 | ``` 267 | 268 | * Run `kubectl port-forward deployment/apache 8081:80` to create a 269 | proxy to the Apache httpd server on your local machine. Then open 270 | `http://localhost:8081` to see the web page of the Apache httpd 271 | server in the web browser. 272 | 273 | * To remove all services and deployments run `kubernetes-remove.sh`: 274 | 275 | ``` 276 | [~/microservice-kubernetes/microservice-kubernetes-demo]./kubernetes-remove.sh 277 | service "apache" deleted 278 | service "catalog" deleted 279 | service "customer" deleted 280 | service "order" deleted 281 | deployment "apache" deleted 282 | deployment "catalog" deleted 283 | deployment "customer" deleted 284 | deployment "order" deleted 285 | ``` 286 | 287 | This skript must be executed before a new version of the pods can be deployed. 288 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Microservice Kubernetes Sample 2 | ===================== 3 | 4 | [Deutsche Anleitung zum Starten des Beispiels](WIE-LAUFEN.md) 5 | 6 | This sample is like the sample for my Microservices Book 7 | ([English](http://microservices-book.com/) / 8 | [German](http://microservices-buch.de/)) that you can find at 9 | https://github.com/ewolff/microservice . 10 | 11 | However, this demo uses [Kubernetes](https://kubernetes.io/) as Docker 12 | environment. Kubernetes also support service discovery and load 13 | balancing. An Apache httpd as a reverse proxy routes the calls to the 14 | services. 15 | 16 | This project creates a complete micro service demo system in Docker 17 | containers. The services are implemented in Java using Spring and 18 | Spring Cloud. 19 | 20 | 21 | 22 | It uses three microservices: 23 | - `Order` to process orders. 24 | - `Customer` to handle customer data. 25 | - `Catalog` to handle the items in the catalog. 26 | 27 | How to run 28 | --------- 29 | 30 | See [How to run](HOW-TO-RUN.md). 31 | 32 | 33 | Apache HTTP Load Balancer 34 | ------------------------ 35 | 36 | Apache HTTP is used to provide the web page of the demo at 37 | port 8080. It also forwards HTTP requests to the microservices. This 38 | is not really necessary as each service has its own port on the 39 | Minikube host but it provides a single point of entry for the whole system. 40 | Apache HTTP is configured as a reverse proxy for this. 41 | Load balancing is left to Kubernetes. 42 | 43 | To configure this Apache HTTP needs to get all registered services from 44 | Kubernetes. It just uses DNS for that. 45 | 46 | Please refer to the subdirectory [microservice-kubernetes-demo/apache](microservice-kubernetes-demo/apache/) to see how this works. 47 | 48 | 49 | Remarks on the Code 50 | ------------------- 51 | 52 | The microservices are: 53 | 54 | - [microservice-kubernetes-demo-catalog](microservice-kubernetes-demo/microservice-kubernetes-demo-catalog) is the application to take care of items. 55 | - [microservice-kubernetes-demo-customer](microservice-kubernetes-demo/microservice-kubernetes-demo-customer) is responsible for customers. 56 | - [microservice-kubernetes-demo-order](microservice-kubernetes-demo/microservice-kubernetes-demo-order) does order processing. It uses 57 | microservice-kubernetes-demo-catalog and microservice-kubernetes-demo-customer. 58 | 59 | The microservices use REST to communicate to each other. 60 | See e.g. [CatalogClient](microservice-kubernetes-demo/microservice-kubernetes-demo-order/src/main/java/com/ewolff/microservice/order/clients/CatalogClient.java) . 61 | The hostname is configurable to allow tests with stubs. 62 | The default is `catalog` which works with Kubernetes. 63 | Other microservices are found using Kubernetes built-in DNS. 64 | Kubernetes does the load balancing on the IP level. 65 | 66 | The microservices have a Java main application in `src/test/java` to 67 | run them stand alone. `microservice-demo-order` uses a stub for the 68 | other services then. Also there are tests that use _consumer-driven 69 | contracts_. That is why it is ensured that the services provide the 70 | correct interface. These CDC tests are used in microservice-demo-order 71 | to verify the stubs. In `microservice-kubernetes-demo-customer` and 72 | `microserivce-kubernetes-demo-catalog` they are used to verify the implemented 73 | REST services. 74 | 75 | Note that the code has no dependencies on Kubernetes. 76 | -------------------------------------------------------------------------------- /WIE-LAUFEN.md: -------------------------------------------------------------------------------- 1 | # Beispiel starten 2 | 3 | Die ist eine Schritt-für-Schritt-Anleitung zum Starten der Beispiele. 4 | Informationen zu Maven und Docker finden sich im 5 | [Cheatsheet-Projekt](https://github.com/ewolff/cheatsheets-DE). 6 | 7 | 8 | ## Installation 9 | 10 | * Installiere 11 | [minikube](https://github.com/kubernetes/minikube/releases). Minikube 12 | bietet eine Kubernetes-Umgebung in einer virtuellen Maschine. Minikube 13 | ist einfach zu benutzen und zu installieren. Es soll keine 14 | Produktionsumgebung sein, sondern dient nur dazu, Kubernetes 15 | auszuprobieren oder Entwicklermaschinen aufzubauen. 16 | 17 | * Installiere 18 | [kubectl](https://kubernetes.io/docs/tasks/kubectl/install/). Das 19 | ist das Kommandozeilenwerkzeug für den Umgang mit Kubernetes. 20 | 21 | ## Docker Images bauen (optional) 22 | 23 | Dieser Schritt ist *optional*. im öffentlichen Docker Hub liegen 24 | bereits Docker Images bereit, die du nutzen kannst. 25 | 26 | * Die Beispiele sind in Java implementiert. Daher muss Java 27 | installiert werden. Die Anleitung findet sich unter 28 | https://www.java.com/en/download/help/download_options.xml . Da die 29 | Beispiele kompiliert werden müssen, muss ein JDK (Java Development 30 | Kit) installiert werden. Das JRE (Java Runtime Environment) reicht 31 | nicht aus. Nach der Installation sollte sowohl `java` und `javac` in 32 | der Eingabeaufforderung möglich sein. 33 | 34 | * Die Beispiele laufen in Docker Containern. Dazu ist eine 35 | Installation von Docker Community Edition notwendig, siehe 36 | https://www.docker.com/community-edition/ . Docker kann mit 37 | `docker` aufgerufen werden. Das sollte nach der Installation ohne 38 | Fehler möglich sein. 39 | 40 | Wechsel in das Verzeichnis `microservice-kubernetes-demo` und starte 41 | `./mvnw clean package` bzw. `mvnw.cmd clean package` (Windows). Das 42 | wird einige Zeit dauern: 43 | 44 | ``` 45 | [~/microservice-kubernetes/microservice-kubernetes-demo]./mvnw clean package 46 | .... 47 | [INFO] 48 | [INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ microservice-kubernetes-demo-order --- 49 | [INFO] Building jar: /Users/wolff/microservice-kubernetes/microservice-kubernetes-demo/microservice-kubernetes-demo-order/target/microservice-kubernetes-demo-order-0.0.1-SNAPSHOT.jar 50 | [INFO] 51 | [INFO] --- spring-boot-maven-plugin:1.4.5.RELEASE:repackage (default) @ microservice-kubernetes-demo-order --- 52 | [INFO] ------------------------------------------------------------------------ 53 | [INFO] Reactor Summary: 54 | [INFO] 55 | [INFO] microservice-kubernetes-demo ....................... SUCCESS [ 0.986 s] 56 | [INFO] microservice-kubernetes-demo-customer .............. SUCCESS [ 16.953 s] 57 | [INFO] microservice-kubernetes-demo-catalog ............... SUCCESS [ 18.016 s] 58 | [INFO] microservice-kubernetes-demo-order ................. SUCCESS [ 18.512 s] 59 | [INFO] ------------------------------------------------------------------------ 60 | [INFO] BUILD SUCCESS 61 | [INFO] ------------------------------------------------------------------------ 62 | [INFO] Total time: 57.633 s 63 | [INFO] Finished at: 2017-09-08T09:36:32+02:00 64 | [INFO] Final Memory: 56M/420M 65 | [INFO] ------------------------------------------------------------------------ 66 | ``` 67 | 68 | Weitere Information zu Maven gibt es im 69 | [Maven Cheatsheet](https://github.com/ewolff/cheatsheets-DE/blob/master/MavenCheatSheet.md). 70 | 71 | Falls es dabei zu Fehlern kommt: 72 | 73 | * Stelle sicher, dass die Datei `settings.xml` im Verzeichnis `.m2` 74 | in deinem Heimatverzeichnis keine Konfiguration für ein spezielles 75 | Maven Repository enthalten. Im Zweifelsfall kannst du die Datei 76 | einfach löschen. 77 | 78 | * Die Tests nutzen einige Ports auf dem Rechner. Stelle sicher, dass 79 | im Hintergrund keine Server laufen. 80 | 81 | * Führe die Tests beim Build nicht aus: `./mvnw clean package 82 | -Dmaven.test.skip=true` bzw. `mvnw.cmd clean package 83 | -Dmaven.test.skip=true` (Windows). 84 | 85 | * In einigen selten Fällen kann es vorkommen, dass die Abhängigkeiten 86 | nicht korrekt heruntergeladen werden. Wenn du das Verzeichnis 87 | `repository` im Verzeichnis `.m2` löscht, werden alle Abhängigkeiten 88 | erneut heruntergeladen. 89 | 90 | Der Java-Code ist nun kompiliert. Der nächste Schritt ist, die Docker 91 | Images zu erstellen und sie in den öffentlichen Docker Hub hochzuladen: 92 | 93 | * Erstelle dir einen Account im öffentlichen 94 | [Docker Hub](https://hub.docker.com/). 95 | 96 | * Logge dich auf der Kommandozeile via `docker login` in deinen erstellten 97 | Docker Hub Account ein. 98 | 99 | * Weise die Umgebungsvariable `DOCKER_ACCOUNT` den Namen des Accounts zu. 100 | 101 | * Starte `docker-build.sh` im Verzeichnis 102 | `microservice-kubernetes-demo`. Es erzeugt die Docker Images und lädt 103 | sie in den Docker Hub hoch. Das dauert natürlich einige Zeit: 104 | 105 | ``` 106 | [~/microservice-kubernetes/microservice-kubernetes-demo]export DOCKER_ACCOUNT=ewolff 107 | [~/microservice-kubernetes/microservice-kubernetes-demo]echo $DOCKER_ACCOUNT 108 | ewolff 109 | [~/microservice-kubernetes/microservice-kubernetes-demo]./docker-build.sh 110 | ... 111 | Removing intermediate container 36e9b0c2ac0e 112 | Successfully built b76261d1e4ee 113 | f4ffcb9c643d: Pushed 114 | 14c5bfa09694: Mounted from ewolff/microservice-kubernetes-demo-order 115 | 41a5c76632fc: Mounted from ewolff/microservice-kubernetes-demo-order 116 | 5bef08742407: Mounted from ewolff/microservice-kubernetes-demo-order 117 | latest: digest: sha256:36d87ea5c8628da9a6677c1eafb9009c8f99310f5376872e7b9a1edace37d1a0 size: 1163 118 | ``` 119 | 120 | Weitere Information zu Docker gibt es im 121 | [Docker Cheatsheet](https://github.com/ewolff/cheatsheets-DE/blob/master/DockerCheatSheet.md). 122 | 123 | 124 | ## Container starten 125 | 126 | * Installiere eine Minikube-Instanz mit `minikube start 127 | --memory=4000`. Die Instanz hat dann 128 | 4.000 MB RAM. Das sollte für das Beispiel ausreichend sein. 129 | 130 | ``` 131 | [~/microservice-kubernetes]minikube start --memory=4000 132 | Starting local Kubernetes v1.7.5 cluster... 133 | Starting VM... 134 | Getting VM IP address... 135 | Moving files into cluster... 136 | Setting up certs... 137 | Connecting to cluster... 138 | Setting up kubeconfig... 139 | Starting cluster components... 140 | Kubectl is now configured to use the cluster. 141 | ``` 142 | 143 | * Falls du deine eigenen Docker Images erstellt hast, muss die 144 | Umgebungsvariable `DOCKER_ACCOUNT` den Namen deines Accounts beim 145 | Docker Hub enthalten. 146 | 147 | * Starte `kubernetes-deploy.sh` im Verzeichnis 148 | `microservice-kubernetes-demo` : 149 | 150 | ``` 151 | [~/microservice-kubernetes/microservice-kubernetes-demo]./kubernetes-deploy.sh 152 | deployment "apache" created 153 | service "apache" exposed 154 | deployment "catalog" created 155 | service "catalog" exposed 156 | deployment "customer" created 157 | service "customer" exposed 158 | deployment "order" created 159 | service "order" exposed 160 | ``` 161 | 162 | Die Alternative zu dem Skript ist der Befehl `kubectl apply -f 163 | microservices.yaml` . Die Datei `microservices.yaml` enthält die 164 | Definitionen der Services und Deployments. `kubectl` erzeugt dann die 165 | Deployments und Services, falls sie noch nicht existieren. Die 166 | YAML-Datei nutzt die Images vom Docker Account `ewolff`. Wenn du einen 167 | anderen Docker Account nutzen willst, musst du das YAML entsprechend 168 | editieren. 169 | 170 | Das Skript deployt die Images und erzeugt die Pods. Pods können einen 171 | oder mehrere Docker Container enthalten. In diesem Beispiel enthält 172 | jeder Pod nur einen Docker container. 173 | 174 | Außerdem erstellt das Skript Services. Services haben eine eindeutige 175 | IP-Adresse und einen Eintrag im DNS-Namenssystem. Services setzten 176 | außerdem Lastverteilung über mehrere Pods um. Man kann sich die 177 | Services auch anschauen: 178 | 179 | * Führe `kubectl get services` aus, um alle Services zu sehen: 180 | 181 | ``` 182 | [~/microservice-kubernetes/microservice-kubernetes-demo]kubectl get services 183 | NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE 184 | apache 10.0.0.90 80:31214/TCP 46s 185 | catalog 10.0.0.219 8080:30161/TCP 46s 186 | customer 10.0.0.163 8080:30620/TCP 45s 187 | kubernetes 10.0.0.1 443/TCP 3m 188 | order 10.0.0.21 8080:30616/TCP 45s 189 | ``` 190 | 191 | 192 | * `kubectl describe services` gibt mehr Details aus. Der Befehlt 193 | funktioniert auch für Pods (`kubectl describe pods`) und Deployments 194 | (`kubectl describe deployments`). 195 | 196 | ``` 197 | [~/microservice-kubernetes/microservice-kubernetes-demo]kubectl describe services 198 | ... 199 | 200 | Name: order 201 | Namespace: default 202 | Labels: run=order 203 | Annotations: 204 | Selector: run=order 205 | Type: LoadBalancer 206 | IP: 10.0.0.21 207 | Port: 8080/TCP 208 | NodePort: 30616/TCP 209 | Endpoints: 172.17.0.7:8080 210 | Session Affinity: None 211 | Events: 212 | ``` 213 | 214 | * Du kannst dir auch eine Liste der Pods ausgeben lassen: 215 | 216 | ``` 217 | [~/microservice-kubernetes/microservice-kubernetes-demo]kubectl get pods 218 | NAME READY STATUS RESTARTS AGE 219 | apache-3412280829-k5z5p 1/1 Running 0 2m 220 | catalog-269679894-60dr0 1/1 Running 0 2m 221 | customer-1984516559-1ffjk 1/1 Running 0 2m 222 | order-2204540131-nks5s 1/1 Running 0 2m 223 | ``` 224 | 225 | * ...und du kannst die Logs eines Pods sehen: 226 | 227 | ``` 228 | [~/microservice-kubernetes/microservice-kubernetes-demo]kubectl logs catalog-269679894-60dr0 229 | 230 | . ____ _ __ _ _ 231 | /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ 232 | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ 233 | \\/ ___)| |_)| | | | | || (_| | ) ) ) ) 234 | ' |____| .__|_| |_|_| |_\__, | / / / / 235 | =========|_|==============|___/=/_/_/_/ 236 | :: Spring Boot :: (v1.4.5.RELEASE) 237 | ... 238 | 2017-09-08 08:11:06.128 INFO 7 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup 239 | 2017-09-08 08:11:06.158 INFO 7 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 0 240 | 2017-09-08 08:11:06.746 INFO 7 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http) 241 | 2017-09-08 08:11:06.803 INFO 7 --- [ main] c.e.microservice.catalog.CatalogApp : Started CatalogApp in 53.532 seconds (JVM running for 54.296) 242 | ... 243 | ``` 244 | 245 | * Außerdem kannst du ein Kommando in einem Pod ausführen: 246 | 247 | ``` 248 | [~/microservice-kubernetes/microservice-kubernetes-demo]kubectl exec catalog-269679894-60dr0 /bin/ls 249 | bin 250 | dev 251 | etc 252 | home 253 | lib 254 | lib64 255 | media 256 | microservice-kubernetes-demo-catalog-0.0.1-SNAPSHOT.jar 257 | mnt 258 | proc 259 | root 260 | run 261 | sbin 262 | srv 263 | sys 264 | tmp 265 | usr 266 | var 267 | ``` 268 | 269 | * Und du kannst eine Shell in einem Pod starten: 270 | 271 | ``` 272 | [~/microservice-kubernetes/microservice-kubernetes-demo]kubectl exec catalog-269679894-60dr0 -it /bin/sh 273 | / # ls 274 | bin proc 275 | dev root 276 | etc run 277 | home sbin 278 | lib srv 279 | lib64 sys 280 | media tmp 281 | microservice-kubernetes-demo-catalog-0.0.1-SNAPSHOT.jar usr 282 | mnt var 283 | / # 284 | ``` 285 | 286 | * Run to create a 287 | proxy to the Apache httpd server on your local machine. Then open 288 | `http://localhost:8081` to see the web page of the Apache httpd 289 | server in the web browser. 290 | 291 | 292 | * Mit `kubectl port-forward deployment/apache 8081:80` kannst du einen 293 | Proxy für den Apache httpd Server auf dem lokalen Rechner 294 | erzeugt. Unter `http://localhost:8081` kannst du die Webseite des 295 | Apache 296 | httpd Server im Web-Browser öffnen. Dabei kannst du auch sehen, dass 297 | dem Service ein Port auf dem virutellen Minikube-Server zugewiesen 298 | worden ist. 299 | 300 | Der Typ des Service ist `LoadBalancer`. Eigentlich sollte daher der 301 | Service an einen externen Load Balancer angeschlossen werden. Das 302 | funktioniert mit minikube nicht, so dass der Serice unter einem 303 | bestimmten Port auf dem minikube-Host verfügbar ist. 304 | 305 | * Um alle Services und Deployments zu löschen, starte 306 | `kubernetes-remove.sh`: 307 | 308 | ``` 309 | [~/microservice-kubernetes/microservice-kubernetes-demo]./kubernetes-remove.sh 310 | service "apache" deleted 311 | service "catalog" deleted 312 | service "customer" deleted 313 | service "order" deleted 314 | deployment "apache" deleted 315 | deployment "catalog" deleted 316 | deployment "customer" deleted 317 | deployment "order" deleted 318 | ``` 319 | 320 | Dieses Skript muss laufen, bevor eine neue Version der Pods deployt werden kann. 321 | -------------------------------------------------------------------------------- /microservice-kubernetes-demo/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ewolff/microservice-kubernetes/db3af1b3c933c48871fab74d45b466f2dfedb6a3/microservice-kubernetes-demo/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /microservice-kubernetes-demo/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip -------------------------------------------------------------------------------- /microservice-kubernetes-demo/apache/000-default.conf: -------------------------------------------------------------------------------- 1 | 2 | DocumentRoot /var/www/html 3 | 4 | # This should be secured! 5 | 6 | SetHandler balancer-manager 7 | 8 | 9 | ErrorLog ${APACHE_LOG_DIR}/error.log 10 | CustomLog ${APACHE_LOG_DIR}/access.log combined 11 | 12 | ProxyPreserveHost On 13 | 14 | ProxyPass /order http://order:8080/ 15 | ProxyPassReverse /order http://order:8080/ 16 | 17 | ProxyPass /catalog http://catalog:8080/ 18 | ProxyPassReverse /catalog http://catalog:8080/ 19 | 20 | ProxyPass /customer http://customer:8080/ 21 | ProxyPassReverse /customer http://customer:8080/ 22 | 23 | 24 | -------------------------------------------------------------------------------- /microservice-kubernetes-demo/apache/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | 3 | # Update Ubuntu 4 | RUN apt-get update ; apt-get dist-upgrade -y -qq 5 | 6 | # Install Apache + modules 7 | ENV DEBIAN_FRONTEND=noninteractive 8 | RUN apt-get install -y -qq --no-install-recommends apache2 && \ 9 | a2enmod proxy proxy_http proxy_ajp rewrite deflate headers proxy_connect proxy_html lbmethod_byrequests && \ 10 | mkdir /var/lock/apache2 && mkdir /var/run/apache2 11 | 12 | # Config Apache 13 | COPY index.html /var/www/html/index.html 14 | COPY 000-default.conf /etc/apache2/sites-enabled/000-default.conf 15 | 16 | EXPOSE 80 17 | CMD apache2ctl -D FOREGROUND 18 | -------------------------------------------------------------------------------- /microservice-kubernetes-demo/apache/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Order Processing 5 | 6 | 8 | 9 | 11 | 12 | 14 | 15 | 16 | 17 |

Order Processing

18 |
19 |
20 |
21 | Customer 22 |
23 |
List / add / remove customers
24 |
25 |
26 |
27 | Catalog 28 |
29 |
List / add / remove items
30 |
31 |
32 |
33 | Catalog 34 |
35 |
Search Items
36 |
37 |
38 |
39 | Order 40 |
41 |
Create an order
42 |
43 |
44 |
45 |
46 | 47 | 48 | -------------------------------------------------------------------------------- /microservice-kubernetes-demo/docker-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if [ -z "$DOCKER_ACCOUNT" ]; then 3 | DOCKER_ACCOUNT=ewolff 4 | fi; 5 | docker build --tag=microservice-kubernetes-demo-apache apache 6 | docker tag microservice-kubernetes-demo-apache $DOCKER_ACCOUNT/microservice-kubernetes-demo-apache:latest 7 | docker push $DOCKER_ACCOUNT/microservice-kubernetes-demo-apache 8 | 9 | docker build --tag=microservice-kubernetes-demo-catalog microservice-kubernetes-demo-catalog 10 | docker tag microservice-kubernetes-demo-catalog $DOCKER_ACCOUNT/microservice-kubernetes-demo-catalog:latest 11 | docker push $DOCKER_ACCOUNT/microservice-kubernetes-demo-catalog 12 | 13 | docker build --tag=microservice-kubernetes-demo-customer microservice-kubernetes-demo-customer 14 | docker tag microservice-kubernetes-demo-customer $DOCKER_ACCOUNT/microservice-kubernetes-demo-customer:latest 15 | docker push $DOCKER_ACCOUNT/microservice-kubernetes-demo-customer 16 | 17 | docker build --tag=microservice-kubernetes-demo-order microservice-kubernetes-demo-order 18 | docker tag microservice-kubernetes-demo-order $DOCKER_ACCOUNT/microservice-kubernetes-demo-order:latest 19 | docker push $DOCKER_ACCOUNT/microservice-kubernetes-demo-order -------------------------------------------------------------------------------- /microservice-kubernetes-demo/kubernetes-deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if [ -z "$DOCKER_ACCOUNT" ]; then 3 | DOCKER_ACCOUNT=ewolff 4 | fi; 5 | kubectl create deployment apache --image=docker.io/$DOCKER_ACCOUNT/microservice-kubernetes-demo-apache:latest --port=80 6 | kubectl expose deployment apache --type="LoadBalancer" --port 80 7 | kubectl create deployment catalog --image=docker.io/$DOCKER_ACCOUNT/microservice-kubernetes-demo-catalog:latest --port=8080 8 | kubectl expose deployment catalog --type="LoadBalancer" --port 8080 9 | kubectl create deployment customer --image=docker.io/$DOCKER_ACCOUNT/microservice-kubernetes-demo-customer:latest --port=8080 10 | kubectl expose deployment customer --type="LoadBalancer" --port 8080 11 | kubectl create deployment order --image=docker.io/$DOCKER_ACCOUNT/microservice-kubernetes-demo-order:latest --port=8080 12 | kubectl expose deployment order --type="LoadBalancer" --port 8080 13 | -------------------------------------------------------------------------------- /microservice-kubernetes-demo/kubernetes-remove.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | kubectl delete service apache catalog customer order 3 | kubectl delete deployments apache catalog customer order 4 | -------------------------------------------------------------------------------- /microservice-kubernetes-demo/microservice-kubernetes-demo-catalog/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:11.0.2-jre-slim 2 | COPY target/microservice-kubernetes-demo-catalog-0.0.1-SNAPSHOT.jar . 3 | CMD /usr/bin/java -Xmx400m -Xms400m -jar microservice-kubernetes-demo-catalog-0.0.1-SNAPSHOT.jar 4 | EXPOSE 8080 5 | -------------------------------------------------------------------------------- /microservice-kubernetes-demo/microservice-kubernetes-demo-catalog/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | 7 | com.ewolff 8 | microservice-kubernetes-demo 9 | 0.0.1-SNAPSHOT 10 | 11 | 12 | microservice-kubernetes-demo-catalog 13 | 14 | 15 | 16 | 17 | org.springframework.boot 18 | spring-boot-starter-data-jpa 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-data-rest 24 | 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-thymeleaf 29 | 30 | 31 | 32 | nz.net.ultraq.thymeleaf 33 | thymeleaf-layout-dialect 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-web 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-actuator 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-test 49 | test 50 | 51 | 52 | 53 | org.springframework.hateoas 54 | spring-hateoas 55 | 56 | 57 | 58 | com.jayway.jsonpath 59 | json-path 60 | runtime 61 | 62 | 63 | 64 | org.hsqldb 65 | hsqldb 66 | runtime 67 | 68 | 69 | 70 | commons-lang 71 | commons-lang 72 | 2.6 73 | 74 | 75 | 76 | org.webjars 77 | bootstrap 78 | 3.3.6 79 | 80 | 81 | 82 | org.springframework.boot 83 | spring-boot-devtools 84 | true 85 | 86 | 87 | 88 | javax.xml.bind 89 | jaxb-api 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /microservice-kubernetes-demo/microservice-kubernetes-demo-catalog/src/main/java/com/ewolff/microservice/catalog/CatalogApp.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.catalog; 2 | 3 | import javax.annotation.PostConstruct; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 8 | import org.springframework.context.annotation.ComponentScan; 9 | import org.springframework.stereotype.Component; 10 | 11 | @ComponentScan 12 | @EnableAutoConfiguration 13 | @Component 14 | public class CatalogApp { 15 | 16 | private final ItemRepository itemRepository; 17 | 18 | @Autowired 19 | public CatalogApp(ItemRepository itemRepository) { 20 | this.itemRepository = itemRepository; 21 | } 22 | 23 | @PostConstruct 24 | public void generateTestData() { 25 | itemRepository.save(new Item("iPod", 42.0)); 26 | itemRepository.save(new Item("iPod touch", 21.0)); 27 | itemRepository.save(new Item("iPod nano", 1.0)); 28 | itemRepository.save(new Item("Apple TV", 100.0)); 29 | } 30 | 31 | public static void main(String[] args) { 32 | SpringApplication.run(CatalogApp.class, args); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /microservice-kubernetes-demo/microservice-kubernetes-demo-catalog/src/main/java/com/ewolff/microservice/catalog/Item.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.catalog; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Entity; 5 | import javax.persistence.GeneratedValue; 6 | import javax.persistence.Id; 7 | 8 | import org.apache.commons.lang.builder.EqualsBuilder; 9 | import org.apache.commons.lang.builder.HashCodeBuilder; 10 | import org.apache.commons.lang.builder.ToStringBuilder; 11 | 12 | @Entity 13 | public class Item { 14 | 15 | @Id 16 | @GeneratedValue 17 | private Long id; 18 | 19 | @Column(nullable = false) 20 | private String name; 21 | 22 | @Column(nullable = false) 23 | private double price; 24 | 25 | public Item() { 26 | super(); 27 | id = 0l; 28 | } 29 | 30 | public Item(String name, double price) { 31 | super(); 32 | this.name = name; 33 | this.price = price; 34 | } 35 | 36 | public String getName() { 37 | return name; 38 | } 39 | 40 | public void setName(String name) { 41 | this.name = name; 42 | } 43 | 44 | public double getPrice() { 45 | return price; 46 | } 47 | 48 | public void setPrice(double price) { 49 | this.price = price; 50 | } 51 | 52 | public Long getId() { 53 | return id; 54 | } 55 | 56 | public void setId(Long id) { 57 | this.id = id; 58 | } 59 | 60 | @Override 61 | public String toString() { 62 | return ToStringBuilder.reflectionToString(this); 63 | } 64 | 65 | @Override 66 | public int hashCode() { 67 | return HashCodeBuilder.reflectionHashCode(this); 68 | 69 | } 70 | 71 | @Override 72 | public boolean equals(Object obj) { 73 | return EqualsBuilder.reflectionEquals(this, obj); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /microservice-kubernetes-demo/microservice-kubernetes-demo-catalog/src/main/java/com/ewolff/microservice/catalog/ItemRepository.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.catalog; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.data.repository.PagingAndSortingRepository; 6 | import org.springframework.data.repository.query.Param; 7 | import org.springframework.data.rest.core.annotation.RepositoryRestResource; 8 | 9 | @RepositoryRestResource(collectionResourceRel = "catalog", path = "catalog") 10 | public interface ItemRepository extends PagingAndSortingRepository { 11 | 12 | List findByName(@Param("name") String name); 13 | 14 | List findByNameContaining(@Param("name") String name); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /microservice-kubernetes-demo/microservice-kubernetes-demo-catalog/src/main/java/com/ewolff/microservice/catalog/SpringRestDataConfig.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.catalog; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.data.rest.core.config.RepositoryRestConfiguration; 6 | import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer; 7 | import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter; 8 | 9 | @Configuration 10 | class SpringRestDataConfig extends RepositoryRestConfigurerAdapter { 11 | 12 | @Bean 13 | public RepositoryRestConfigurer repositoryRestConfigurer() { 14 | 15 | return new RepositoryRestConfigurerAdapter() { 16 | @Override 17 | public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { 18 | config.exposeIdsFor(Item.class); 19 | } 20 | }; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /microservice-kubernetes-demo/microservice-kubernetes-demo-catalog/src/main/java/com/ewolff/microservice/catalog/web/CatalogController.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.catalog.web; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.http.MediaType; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.web.bind.annotation.PathVariable; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestMethod; 9 | import org.springframework.web.bind.annotation.RequestParam; 10 | import org.springframework.web.servlet.ModelAndView; 11 | 12 | import com.ewolff.microservice.catalog.Item; 13 | import com.ewolff.microservice.catalog.ItemRepository; 14 | 15 | @Controller 16 | public class CatalogController { 17 | 18 | private final ItemRepository itemRepository; 19 | 20 | @Autowired 21 | public CatalogController(ItemRepository itemRepository) { 22 | this.itemRepository = itemRepository; 23 | } 24 | 25 | @RequestMapping(value = "/{id}.html", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE) 26 | public ModelAndView Item(@PathVariable("id") long id) { 27 | return new ModelAndView("item", "item", itemRepository.findById(id).get()); 28 | } 29 | 30 | @RequestMapping("/list.html") 31 | public ModelAndView ItemList() { 32 | return new ModelAndView("itemlist", "items", itemRepository.findAll()); 33 | } 34 | 35 | @RequestMapping(value = "/form.html", method = RequestMethod.GET) 36 | public ModelAndView add() { 37 | return new ModelAndView("item", "item", new Item()); 38 | } 39 | 40 | @RequestMapping(value = "/form.html", method = RequestMethod.POST) 41 | public ModelAndView post(Item Item) { 42 | Item = itemRepository.save(Item); 43 | return new ModelAndView("success"); 44 | } 45 | 46 | @RequestMapping(value = "/{id}.html", method = RequestMethod.PUT) 47 | public ModelAndView put(@PathVariable("id") long id, Item item) { 48 | item.setId(id); 49 | itemRepository.save(item); 50 | return new ModelAndView("success"); 51 | } 52 | 53 | @RequestMapping(value = "/searchForm.html", produces = MediaType.TEXT_HTML_VALUE) 54 | public ModelAndView searchForm() { 55 | return new ModelAndView("searchForm"); 56 | } 57 | 58 | @RequestMapping(value = "/searchByName.html", produces = MediaType.TEXT_HTML_VALUE) 59 | public ModelAndView search(@RequestParam("query") String query) { 60 | return new ModelAndView("itemlist", "items", 61 | itemRepository.findByNameContaining(query)); 62 | } 63 | 64 | @RequestMapping(value = "/{id}.html", method = RequestMethod.DELETE) 65 | public ModelAndView delete(@PathVariable("id") long id) { 66 | itemRepository.deleteById(id); 67 | return new ModelAndView("success"); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /microservice-kubernetes-demo/microservice-kubernetes-demo-catalog/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | management.endpoints.web.exposure.include=* 2 | spring.cloud.refresh.refreshable=none 3 | logging.level.org.springframework.boot.actuate.trace.WebRequestTraceFilter: TRACE 4 | spring.application.name=catalog 5 | server.port=8080 -------------------------------------------------------------------------------- /microservice-kubernetes-demo/microservice-kubernetes-demo-catalog/src/main/resources/bootstrap.properties: -------------------------------------------------------------------------------- 1 | spring.cloud.config.enabled=false 2 | -------------------------------------------------------------------------------- /microservice-kubernetes-demo/microservice-kubernetes-demo-catalog/src/main/resources/templates/item.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Item : Edit 7 | 8 | 9 |

Item : Edit

10 |
11 |
13 |
14 | 16 |
17 | 18 |
19 | 22 |
23 | 24 |
25 |
26 | 27 | -------------------------------------------------------------------------------- /microservice-kubernetes-demo/microservice-kubernetes-demo-catalog/src/main/resources/templates/itemlist.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Item : View all 7 | 8 | 9 |

Item : View all

10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | 28 | 29 | 33 | 34 | 35 |
idNamePrice
No items
1Name42.0
31 | 32 |
36 |
37 |
38 | Add Item 39 |
40 |
41 |
42 | 43 | -------------------------------------------------------------------------------- /microservice-kubernetes-demo/microservice-kubernetes-demo-catalog/src/main/resources/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Layout 6 | 8 | 10 | 14 | 15 | 16 | 17 |
18 | 26 |

Layout

27 |
Fake content
28 |
29 |