{"id":90611,"date":"2019-04-15T08:44:32","date_gmt":"2019-04-15T05:44:32","guid":{"rendered":"http:\/\/www.javacodegeeks.com\/?p=90611"},"modified":"2019-04-24T11:59:25","modified_gmt":"2019-04-24T08:59:25","slug":"build-microservice-architecture-spring-boot-kubernetes","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2019\/04\/build-microservice-architecture-spring-boot-kubernetes.html","title":{"rendered":"Build a Microservice Architecture with Spring Boot and Kubernetes"},"content":{"rendered":"<p><span style=\"font-size: 20px;\"><b>\u201cI love writing authentication and authorization code.\u201d ~ No Java Developer Ever.<\/b> Tired of building the same login screens over and over? <a href=\"https:\/\/developer.okta.com\/signup\/?utm_campaign=text_website_all_multiple_dev_ciam_microservice-architecture-spring-boot-kubernetes_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Try the Okta API for hosted authentication, authorization, and multi-factor auth.<\/a><\/span><\/p>\n<p>In this tutorial, you\u2019re going to use Kubernetes to deploy a Spring Boot microservice architecture to Google Cloud, specifically the Google Kubernetes Engine (GKE). You\u2019re also going to use Istio to create a service mesh layer and to create a public gateway. The whole thing is going to be secured using Okta OAuth JWT authentication.<\/p>\n<p>That was a mess of jargon. We\u2019re not going to explain microservices in-depth here. In short, microservices are a design pattern that splits larger monolithic services into smaller, independent \u201cmicro\u201d services. These services are loosely coupled over a network. The benefits of this architecture are that each service becomes testable, maintainable, and independently deployable. At internet scale, and in enormous companies like Amazon and Netflix, this architecture is great because it allows companies to assign small teams responsibility for manageable, discrete units of function; as opposed to having enormous monolithic blocks of code overseen by thousands of people. The downside is the high initial cost of complexity and infrastructure, which may not make sense for smaller projects that aren\u2019t going to scale.<\/p>\n<p><strong>Kubernetes<\/strong>&nbsp;is a platform for deploying containerized services. You can think of it as a container orchestrator for Docker containers (this is a simplification, but it\u2019ll work). It will allow us to write YAML scripts that automate the deployment of our microservice architecture to our chosen platform, GKE. It\u2019s a huge project with lots to dig into. Take a look at&nbsp;<a href=\"https:\/\/kubernetes.io\/docs\/home\/\">their docs<\/a>&nbsp;for more info.<\/p>\n<p><strong>Istio<\/strong>&nbsp;adds another layer of features on top of Kubernetes, adding some great monitoring, security, access control, and load balancing features. Check out&nbsp;<a href=\"https:\/\/istio.io\/docs\/concepts\/what-is-istio\/\">their website<\/a>&nbsp;for more info.<\/p>\n<p>The last piece of the microservice architecture is&nbsp;<strong>Google Cloud and GKE<\/strong>. This is the platform you\u2019ll be using to deploy the microservice. Another option not covered in this tutorial is Minikube. Minikube runs locally on your computer and might work great for some people; I found Google Kubernetes Engine easier to use and more performant.<\/p>\n<p>We\u2019re going to assume you\u2019re familiar with Spring Boot and Java. If not, take a look at the end of the tutorial for some links to get you started.<\/p>\n<h2 class=\"wp-block-heading\" id=\"requirements-for-spring-boot-and-kubernetes\">Requirements for Spring Boot and Kubernetes<\/h2>\n<p><strong>HTTPie<\/strong>: Install HTTPie from&nbsp;<a href=\"https:\/\/httpie.org\/\">their website<\/a>&nbsp;so that we can run HTTP requests easily from the terminal.<\/p>\n<p><strong>Docker<\/strong>: Please download and install Docker Desktop from&nbsp;<a href=\"https:\/\/www.docker.com\/products\/docker-desktop\">their website<\/a>&nbsp;if you don\u2019t have it already installed.<\/p>\n<p><strong>kubectl<\/strong>: This is Kubernetes\u2019 command line interface. Instructions for installing it are on&nbsp;<a href=\"https:\/\/kubernetes.io\/docs\/tasks\/tools\/install-kubectl\/\">their website<\/a>.<\/p>\n<p><strong>Google Cloud<\/strong>: You\u2019ll need a Google Cloud account with billing enabled. A free trial is available and should include more than enough credit and time to get you through this tutorial. Go to the&nbsp;<a href=\"https:\/\/cloud.google.com\/free\/\">Google Cloud website<\/a>&nbsp;and sign up.<\/p>\n<p><strong>developer.okta.com<\/strong>: We offer free developer accounts on&nbsp;<a href=\"https:\/\/developer.okta.com\/?utm_campaign=text_website_all_multiple_dev_ciam_microservice-architecture-spring-boot-kubernetes_null&amp;utm_source=jcg&amp;utm_medium=cpc\">our developer site<\/a>. Please sign up for one now. You\u2019ll use it toward the end of the tutorial.<\/p>\n<p><strong>gcloud<\/strong>: This is the Google Cloud CLI. Install it using the instructions from&nbsp;<a href=\"https:\/\/cloud.google.com\/sdk\/docs\/\">their website.<\/a>. Once that is done, you\u2019ll need to install the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">gcloud kubectl<\/code>&nbsp;components by running the following command:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">gcloud components install kubectl<\/pre>\n<p>Did I mention microservices have a high initial complexity cost?<\/p>\n<h2 class=\"wp-block-heading\" id=\"create-a-google-kubernetes-engine-project-with-istio\">Create a Google Kubernetes Engine Project with Istio<\/h2>\n<p>You should now have a Google Cloud account with billing enabled. Again, you shouldn\u2019t need to actually spend any money, but without billing, you won\u2019t be able to access the free trial.<\/p>\n<p>Create a new project. Name it&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">spring-boot-gke<\/code>&nbsp;(or whatever you want, but you\u2019ll need the project ID for the various commands). Wait for the project to be created.<\/p>\n<p>The project name will likely end up with an ID number tacked onto the end, like&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">spring-boot-gke-232934<\/code>. You\u2019ll need this project name a few times, so go ahead and store it in a shell variable and take note of it.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">PROJECT_NAME=&lt;your project name and ID&gt;\n<\/pre>\n<p>Once the project is ready, open the project dashboard, open the navigation menu, and click on&nbsp;<strong>Kubernetes Engine<\/strong>. Click the&nbsp;<strong>Enable Billing<\/strong>&nbsp;button (if you haven\u2019t already enabled billing) and select a billing account.<\/p>\n<p>Click&nbsp;<strong>Create Cluster<\/strong>.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/google-cloud-create-cluster.png\" alt=\"Microservice Architecture\" class=\"wp-image-90613\" width=\"652\" height=\"404\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/google-cloud-create-cluster.png 869w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/google-cloud-create-cluster-300x186.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/google-cloud-create-cluster-768x475.png 768w\" sizes=\"(max-width: 652px) 100vw, 652px\" \/><\/figure>\n<\/div>\n<p>From the left-side panel, select&nbsp;<strong>Your First Cluster<\/strong>.<\/p>\n<p>Name the cluster \u201cspring-boot-cluster\u201d.<\/p>\n<p>Select the zone \u201cus-west1-a\u201d.<\/p>\n<p>Click on the&nbsp;<strong>Advanced Options<\/strong>&nbsp;link at the bottom of the cluster config panel to show the advanced options. Scroll down to the bottom and check the box for&nbsp;<strong>Enable Istio (beta)<\/strong>. This will automatically install Istio on the cluster.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" width=\"668\" height=\"314\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/enable-istio.png\" alt=\"Microservice Architecture\" class=\"wp-image-90614\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/enable-istio.png 668w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/enable-istio-300x141.png 300w\" sizes=\"(max-width: 668px) 100vw, 668px\" \/><\/figure>\n<\/div>\n<p>At the bottom, click&nbsp;<strong>Create<\/strong>&nbsp;to create the cluster. Grab a coffee or take a break; it will take a few minutes to create the cluster.<\/p>\n<p>Meanwhile, if you haven\u2019t already, go ahead and initialize the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">gcloud<\/code>&nbsp;CLI by running:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">gcloud init<\/pre>\n<p>During the initialization process, you can set your new project as the default project and the project\u2019s region as your default region.<\/p>\n<p>Once the cluster is deployed, you need to connect your local&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">gcloud<\/code>&nbsp;and&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">kubectl<\/code>&nbsp;CLI to it with the following command:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">gcloud container clusters get-credentials {yourClusterName} --zone us-west1-a --project {yourProjectId}<\/pre>\n<p>If you used a different project name, you\u2019ll need to change the command to reflect that.<\/p>\n<p><strong>NOTE:<\/strong>&nbsp;If you click on the&nbsp;<strong>Connect<\/strong>&nbsp;button to the right of the Google Cloud Platform dashboard, you\u2019ll see the correct command to enter:<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/connect-to-cluster-1024x468.png\" alt=\"Microservice Architecture\" class=\"wp-image-90615\" width=\"768\" height=\"351\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/connect-to-cluster-1024x468.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/connect-to-cluster-300x137.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/connect-to-cluster-768x351.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/connect-to-cluster.png 1999w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<p>You should see something like the following as a result:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">Fetching cluster endpoint and auth data.\nkubeconfig entry generated for spring-boot-cluster.<\/pre>\n<p>You will also need to give yourself admin privileges on the cluster:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=$(gcloud config get-value core\/account)\n<\/pre>\n<p>Now you need to check and make sure the Istio services were installed and are running. There are a couple of ways to check this. First, in your Google Cloud Platform Kubernetes Engine dashboard, click on the&nbsp;<strong>Services<\/strong>&nbsp;button. You should see a list of Istio services in your&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">spring-boot-cluster<\/code>. They should all have green \u201cOk\u201d under the status column.<\/p>\n<p>While you\u2019re there, note the service named&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">istio-ingressgateway<\/code>&nbsp;of type&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">LoadBalancer<\/code>. This is the public load balancer for your cluster, and the entry shows the public IP and open ports.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/kubernetes-services-1024x709.png\" alt=\"Microservice Architecture\" class=\"wp-image-90616\" width=\"768\" height=\"532\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/kubernetes-services-1024x709.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/kubernetes-services-300x208.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/kubernetes-services-768x532.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/kubernetes-services.png 1093w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<p>Another way to check is by using the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">kubectl<\/code>&nbsp;CLI.<\/p>\n<p>To check the services use the following command:&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">kubectl get services --all-namespaces<\/code>. The&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">--all-namespaces<\/code>&nbsp;is required to show the Istio services, which are in the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">istio-system<\/code>&nbsp;namespace.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">$ kubectl get services --all-namespaces\nNAMESPACE      NAME                     TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)                                                                                                                   AGE\ndefault        kubernetes               ClusterIP      10.31.240.1     &lt;none&gt;           443\/TCP                                                                                                                   5m\nistio-system   istio-citadel            ClusterIP      10.31.252.214   &lt;none&gt;           8060\/TCP,9093\/TCP                                                                                                         3m\nistio-system   istio-egressgateway      ClusterIP      10.31.247.186   &lt;none&gt;           80\/TCP,443\/TCP                                                                                                            3m\nistio-system   istio-galley             ClusterIP      10.31.249.131   &lt;none&gt;           443\/TCP,9093\/TCP                                                                                                          3m\nistio-system   istio-ingressgateway     LoadBalancer   10.31.244.186   35.185.213.229   80:31380\/TCP,443:31390\/TCP,31400:31400\/TCP,15011:30675\/TCP,8060:31581\/TCP,853:32460\/TCP,15030:30998\/TCP,15031:31606\/TCP   3m\nistio-system   istio-pilot              ClusterIP      10.31.251.44    &lt;none&gt;           15010\/TCP,15011\/TCP,8080\/TCP,9093\/TCP                                                                                     3m\nistio-system   istio-policy             ClusterIP      10.31.246.176   &lt;none&gt;           9091\/TCP,15004\/TCP,9093\/TCP                                                                                               3m\nistio-system   istio-sidecar-injector   ClusterIP      10.31.240.214   &lt;none&gt;           443\/TCP                                                                                                                   3m\nistio-system   istio-telemetry          ClusterIP      10.31.247.23    &lt;none&gt;           9091\/TCP,15004\/TCP,9093\/TCP,42422\/TCP                                                                                     3m\nistio-system   promsd                   ClusterIP      10.31.246.88    &lt;none&gt;           9090\/TCP                                                                                                                  3m\nkube-system    default-http-backend     NodePort       10.31.250.134   &lt;none&gt;           80:31955\/TCP                                                                                                              4m\nkube-system    heapster                 ClusterIP      10.31.250.242   &lt;none&gt;           80\/TCP                                                                                                                    4m\nkube-system    kube-dns                 ClusterIP      10.31.240.10    &lt;none&gt;           53\/UDP,53\/TCP                                                                                                             4m\nkube-system    metrics-server           ClusterIP      10.31.245.127   &lt;none&gt;           443\/TCP\n<\/pre>\n<p>To check the Kubernetes pods, use:&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">kubectl get pods --all-namespaces<\/code><\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">$ kubectl get pods --all-namespaces\nNAMESPACE      NAME                                                      READY     STATUS      RESTARTS   AGE\nistio-system   istio-citadel-7c4864c9d5-7xq9x                            1\/1       Running     0          10m\nistio-system   istio-cleanup-secrets-ghqbl                               0\/1       Completed   0          10m\nistio-system   istio-egressgateway-c7f44ff8-tz7br                        1\/1       Running     0          10m\nistio-system   istio-galley-698f5c74d6-hmntq                             1\/1       Running     0          10m\nistio-system   istio-ingressgateway-774d77cb7c-qvhkb                     1\/1       Running     0          10m\nistio-system   istio-pilot-6bd6f7cdb-gb2gd                               2\/2       Running     0          10m\nistio-system   istio-policy-678bd4cf9-r8p6z                              2\/2       Running     0          10m\nistio-system   istio-sidecar-injector-6555557c7b-99c6k                   1\/1       Running     0          10m\nistio-system   istio-telemetry-5f4cfc5b6-vj8cf                           2\/2       Running     0          10m\nistio-system   promsd-ff878d44b-hlkpg                                    2\/2       Running     1          10m\nkube-system    heapster-v1.6.0-beta.1-8c76f98c7-2b4dm                    2\/2       Running     0          9m\nkube-system    kube-dns-7549f99fcc-z5trl                                 4\/4       Running     0          10m\nkube-system    kube-dns-autoscaler-67c97c87fb-m52vb                      1\/1       Running     0          10m\nkube-system    kube-proxy-gke-spring-boot-cluster-pool-1-b6988227-p09h   1\/1       Running     0          10m\nkube-system    l7-default-backend-7ff48cffd7-ppvnn                       1\/1       Running     0          10m\nkube-system    metrics-server-v0.2.1-fd596d746-njws2                     2\/2       Running     0          10m\n<\/pre>\n<p>The pods need to all have a status of&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Completed<\/code>&nbsp;or&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Running<\/code>. I ran into a problem a couple of times where the auto-configuration didn\u2019t work and some of the pods never reached the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Running<\/code>&nbsp;status and were stuck in&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ContainerCreating<\/code>. I had to delete the cluster and reinstall it to get it to work.<div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<p>If this happens you can use the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">describe pods<\/code>&nbsp;command to see what\u2019s going on:&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">kubectl describe pods -n istio-system<\/code>. This will give you a TON of information on all of the pods in the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">istio-system<\/code>&nbsp;namespace, which is specified using the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">-n<\/code>&nbsp;options.<\/p>\n<p>If you\u2019ve gotten this far without problems, you now have a Kubernetes cluster deployed on GKE with Istio installed! Pretty sweet.<\/p>\n<p>Both Google and Istio have some pretty helpful docs if you have a problem. Check out the&nbsp;<a href=\"https:\/\/cloud.google.com\/kubernetes-engine\/docs\/quickstart\">Google GKE docs<\/a>&nbsp;and the&nbsp;<a href=\"https:\/\/istio.io\/docs\/setup\/kubernetes\/quick-start-gke\/\">Istio GKE docs<\/a>&nbsp;for further support.<\/p>\n<h2 class=\"wp-block-heading\" id=\"create-a-spring-boot-project-for-your-microservices\">Create a Spring Boot Project for Your Microservices<\/h2>\n<p>Now go to the&nbsp;<a href=\"https:\/\/start.spring.io\/\">Spring Initializer<\/a>&nbsp;and create your starter project.<\/p>\n<ul class=\"wp-block-list\">\n<li>Change the build tool from Maven to&nbsp;<strong>Gradle<\/strong><\/li>\n<li>Use&nbsp;<strong>Java<\/strong>&nbsp;and Spring Boot version&nbsp;<strong>2.1.3<\/strong><\/li>\n<li>Update the&nbsp;<strong>Group<\/strong>&nbsp;to:&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">com.okta.spring<\/code><\/li>\n<li>Use&nbsp;<strong>Artifact<\/strong>:&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">springbootkbe<\/code><\/li>\n<li>Add three&nbsp;<strong>Dependencies<\/strong>:&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Reactive Web<\/code>,&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Reactive MongoDB<\/code>, and&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Lombok<\/code><\/li>\n<\/ul>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/spring-initializr-1024x803.png\" alt=\"Microservice Architecture\" class=\"wp-image-90617\" width=\"768\" height=\"602\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/spring-initializr-1024x803.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/spring-initializr-300x235.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/spring-initializr-768x602.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/spring-initializr.png 1999w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<p>Click&nbsp;<strong>Generate Project<\/strong>&nbsp;and download the project. Uncompress the project somewhere on your local computer and open it in your favorite IDE or editor.<\/p>\n<p>The Spring Initializer has created a barebones reactive Webflux project with MongoDB support for you to expand upon.<\/p>\n<p>As in some of my other tutorials, and because I like kayaking, you\u2019re going to build a simple reactive REST service that maintains a database of kayak entries. It\u2019s really just to demonstrate basic CRUD functionality (Create, Read, Update, and Delete) and could be generalized to any type of resource.<\/p>\n<p>In the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">com.okta.spring.springbootkbe<\/code>&nbsp;package under&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">src\/main\/java<\/code>, create a document class called&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Kayak.java<\/code>and paste the following into it. This is your reactive data model document.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">package com.okta.spring.springbootkbe;\n  \nimport lombok.AllArgsConstructor;  \nimport lombok.Data;  \nimport lombok.NoArgsConstructor;  \nimport org.springframework.data.mongodb.core.mapping.Document;  \n  \n@Document  \n@Data  \n@AllArgsConstructor  \n@NoArgsConstructor  \npublic class Kayak {  \n  \n    private String name;  \n    private String owner;  \n    private Number value;  \n    private String makeModel;  \n}\n<\/pre>\n<p>Now create another file in the same package called&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">KayakRepository.java<\/code>.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">package com.okta.spring.springbootkbe;  \n  \nimport org.springframework.data.mongodb.repository.ReactiveMongoRepository;  \n  \npublic interface KayakRepository extends ReactiveMongoRepository&lt;Kayak, Long&gt; {  \n}\n<\/pre>\n<p>I\u2019m not going to go into too much detail in this tutorial about what\u2019s going on here. Spring Boot is doing a lot of auto-magicking between these two files to create a fully functional reactive Mongo document.<\/p>\n<p>Next, you need to add a controller to allow access to the Kayak document data model. Create a file called&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">KayakController<\/code>&nbsp;in the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">com.okta.spring.springbootkbe<\/code>&nbsp;package.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">package com.okta.spring.springbootkbe;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.*;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\n@Controller\n@RequestMapping(path = \"\/kayaks\")\npublic class KayakController {\n\n    private final KayakRepository kayakRepository;\n\n    public KayakController(KayakRepository kayakRepository) {\n        this.kayakRepository = kayakRepository;\n    }\n\n    @PostMapping()\n    public @ResponseBody\n    Mono&lt;Kayak&gt; addKayak(@RequestBody Kayak kayak) {\n        return kayakRepository.save(kayak);\n    }\n  \n    @GetMapping()\n    public @ResponseBody\n    Flux&lt;Kayak&gt; getAllKayaks() {\n        Flux&lt;Kayak&gt; result = kayakRepository.findAll();\n        return result;\n    }}\n<\/pre>\n<p>This controller adds two methods to the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/kayaks<\/code>&nbsp;endpoint, a POST and GET endpoint that add a new kayak and list all kayaks, respectively.<\/p>\n<p>Finally, add a simple root controller called&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">RootController<\/code>.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">package com.okta.spring.springbootkbe;  \n  \nimport org.springframework.stereotype.Controller;  \nimport org.springframework.web.bind.annotation.*;  \nimport reactor.core.publisher.Flux;  \n  \n@Controller  \npublic class RootController {  \n  \n    @GetMapping(\"\/\")  \n    @ResponseBody  \n    public Flux&lt;String&gt; getRoot() {  \n      return Flux.just(\"Alive\");  \n    }\n}\n<\/pre>\n<p>This controller is required because Kuberenetes performs health checks on the root endpoint of our services and needs to return a response otherwise the cluster will think your service is down. The actual endpoint is configurable but you can just leave it at the root for now.<\/p>\n<p>To bootstrap in some sample data into our database, update the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">SpringbootkbeApplication<\/code>&nbsp;class definition to match the following.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">package com.okta.spring.springbootkbe;  \n  \nimport org.springframework.boot.ApplicationRunner;  \nimport org.springframework.boot.SpringApplication;  \nimport org.springframework.boot.autoconfigure.SpringBootApplication;  \nimport org.springframework.context.annotation.Bean;  \nimport reactor.core.publisher.Flux;  \n  \n@SpringBootApplication  \npublic class SpringbootkbeApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringbootkbeApplication.class, args);\n    }\n\n    @Bean\n    ApplicationRunner init(KayakRepository repository) {\n\n        Object[][] data = {\n            {\"sea\", \"Andrew\", 300.12, \"NDK\"},\n            {\"creek\", \"Andrew\", 100.75, \"Piranha\"},\n            {\"loaner\", \"Andrew\", 75, \"Necky\"}\n        };\n\n        return args -&gt; {\n            repository\n                .deleteAll()\n                .thenMany(\n                    Flux\n                        .just(data)\n                        .map(array -&gt; {\n                            return new Kayak((String) array[0], (String) array[1], (Number) array[2], (String) array[3]);\n                        })\n                        .flatMap(repository::save)\n                )\n                .thenMany(repository.findAll())\n                .subscribe(kayak -&gt; System.out.println(\"saving \" + kayak.toString()));\n\n        };\n    }\n}\n<\/pre>\n<p>At this point, you have a fully functioning Spring Boot app (minus a MongoDB server). To test your app, add the following dependency to your&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">build.gradle<\/code>&nbsp;file.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">compile 'de.flapdoodle.embed:de.flapdoodle.embed.mongo'<\/pre>\n<p>This adds an embedded MongoDB database to your project. You\u2019ll need to remove this dependency before you deploy to the cluster, but it will let you run the Spring Boot app locally.<\/p>\n<p>Run the Spring Boot app using:&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">gradle bootRun<\/code>.<\/p>\n<p>You should see a bunch of output ending with:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">2019-02-14 19:29:34.941  INFO 35982 --- [ntLoopGroup-2-4] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:5, serverValue:5}] to localhost:61858\n2019-02-14 19:29:34.946  INFO 35982 --- [ntLoopGroup-2-3] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:4, serverValue:4}] to localhost:61858\nsaving Kayak(name=sea, owner=Andrew, value=300.12, makeModel=NDK)\nsaving Kayak(name=loaner, owner=Andrew, value=75, makeModel=Necky)\nsaving Kayak(name=creek, owner=Andrew, value=100.75, makeModel=Piranha)\n<\/pre>\n<p>Use HTTPie to test the app:&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http :8080<\/code>&nbsp;(this runs a get request on the default Spring Boot port).<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">HTTP\/1.1 200 OK\nContent-Type: text\/plain;charset=UTF-8\ntransfer-encoding: chunked\n\nAlive\n<\/pre>\n<p>And GET your&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/kayaks<\/code>&nbsp;endpoint using:&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http :8080\/kayaks<\/code><\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">HTTP\/1.1 200 OK\nContent-Type: application\/json;charset=UTF-8\ntransfer-encoding: chunked\n[\n  {\n    \"makeModel\": \"NDK\",\n    \"name\": \"sea\",\n    \"owner\": \"Andrew\",\n    \"value\": 300.12\n  },\n  {\n    \"makeModel\": \"Necky\",\n    \"name\": \"loaner\",\n    \"owner\": \"Andrew\",\n    \"value\": 75\n  },\n  {\n    \"makeModel\": \"Piranha\",\n    \"name\": \"creek\",\n    \"owner\": \"Andrew\",\n    \"value\": 100.75\n  }\n]\n<\/pre>\n<p>Assuming that all worked,&nbsp;<strong>delete the embedded Mongo dependency<\/strong>. You\u2019re going to be using a Mongo Kubernetes pod and this dependency will cause problems with the cluster deployment.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">compile 'de.flapdoodle.embed:de.flapdoodle.embed.mongo'<\/pre>\n<h2 class=\"wp-block-heading\" id=\"deploy-the-mongodb-kubernetes-pod-for-your-spring-boot-app\">Deploy the MongoDB Kubernetes Pod for Your Spring Boot App<\/h2>\n<p>Kubernetes works (to grossly generalize and simplify) by deploying Docker containers using YAML deployment scripts.<\/p>\n<p>Create a file called&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">deployment-mongo.yml<\/code>&nbsp;in your project\u2019s root directory.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">apiVersion: apps\/v1  \nkind: Deployment  \nmetadata:  \n  name: mongodb  \n  labels:  \n    appdb: mongodb  \nspec:  \n  replicas: 1  \n  selector:  \n    matchLabels:  \n      appdb: mongodb  \n  template:  \n    metadata:  \n      labels:  \n        appdb: mongodb  \n    spec:  \n      containers:  \n        - name: mongodb  \n          image: mongo:3.6.6  \n          ports:  \n            - containerPort: 27017  \n---  \napiVersion: v1  \nkind: Service  \nmetadata:  \n  name: mongodb  \n  labels:  \n    app: mongodb  \nspec:  \n  ports:  \n    - port: 27017  \n      protocol: TCP  \n  selector:  \n    appdb: mongodb\n<\/pre>\n<p>This defines the MongoDB Kubernetes&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Deployment<\/code>&nbsp;and&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Service<\/code>&nbsp;required to create the Mongo database on the cluster. I\u2019m not going to try and fully explain what these objects are here, but you can read the Kubernetes&nbsp;<a href=\"https:\/\/kubernetes.io\/docs\/concepts\/workloads\/controllers\/deployment\/\">deployment docs<\/a>&nbsp;and the&nbsp;<a href=\"https:\/\/kubernetes.io\/docs\/concepts\/services-networking\/service\/\">service docs<\/a>. Roughly speaking, deployments define the micro-applications that run in the deployed pods while services provide the overarching abstraction that defines the access point to the apps in the pods. This abstraction provides a necessary continuity because pods may be killed and restarted and there may be multiple pods running a single service.<\/p>\n<p>Now for some excitement! You\u2019re going to deploy the Mongo database deployment and service to your GKE cluster.<\/p>\n<p>Use the following command:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">kubectl apply -f deployment-mongo.yml<\/pre>\n<p>You should see:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">deployment.apps \"mongodb\" created\nservice \"mongodb\" created<\/pre>\n<p>Check on the pod by running:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">$ kubectl get pods\n<\/pre>\n<p>You should see:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">NAME                      READY     STATUS    RESTARTS   AGE\nmongodb-c5b8bf947-rkw5f   1\/1       Running   0          21s\n<\/pre>\n<p>If the status is listed as&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ContainerCreating<\/code>, wait a moment and run the command again. If it gets stuck on&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ContainerCreating<\/code>&nbsp;for more than a few minutes, likely something has gone wrong. You can use the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">kubectl describe pods<\/code>&nbsp;and&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">kubectl get events<\/code>&nbsp;commands to get an idea of what\u2019s happening.<\/p>\n<p>This configured a Mongo database running on port 27017 using the standard docker image&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">mongo:3.6.6<\/code>.<\/p>\n<p>Pretty great, huh? Next stop, rocket science!<\/p>\n<h2 class=\"wp-block-heading\" id=\"deploy-the-spring-boot-app-to-the-cluster\">Deploy the Spring Boot App to the Cluster<\/h2>\n<p>Add a file called&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Dockerfile<\/code>&nbsp;in the root directory:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:sql\">FROM openjdk:8-jdk-alpine  \nENV APP_FILE springbootkbe-0.1.0-SNAPSHOT.jar  \nENV APP_HOME \/usr\/app  \nEXPOSE 8000  \nCOPY build\/libs\/*.jar $APP_HOME\/  \nWORKDIR $APP_HOME  \nENTRYPOINT [\"sh\", \"-c\"]  \nCMD [\"exec java -jar $APP_FILE\"]\n<\/pre>\n<p>Update the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">src\/main\/resources\/application.properties<\/code>:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">server.port=8000\nspring.data.mongodb.host=mongodb\nspring.data.mongodb.port=27017\n<\/pre>\n<p>This configures your Spring Boot port to the port you\u2019re exposing in the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Dockerfile<\/code>&nbsp;as well as configuring the MongoDB host and port. The host by default will be the name of the service inside the cluster.<\/p>\n<p>Build your app again (you did remove the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">flapdoodle<\/code>&nbsp;dependency, right?):<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">gradle clean build<\/pre>\n<p>Create another Kubernetes deployment script called&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">deployment.yml<\/code>&nbsp;in the root project directory:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">apiVersion: v1  \nkind: Service  \nmetadata:  \n  name: kayak-service  \n  labels:  \n    app: kayak-service  \nspec:  \n  ports:  \n    - name: http  \n      port: 8000  \n  selector:  \n    app: kayak-service  \n---  \napiVersion: extensions\/v1beta1  \nkind: Deployment  \nmetadata:  \n  name: kayak-service  \nspec:  \n  replicas: 1  \n  template:  \n    metadata:  \n      labels:  \n        app: kayak-service  \n        version: v1  \n    spec:  \n      containers:  \n        - name: kayak-app  \n          image: gcr.io\/spring-boot-gke-\/kayak-app:1.0  \n          imagePullPolicy: IfNotPresent  \n          env:  \n            - name: MONGODB_HOST  \n              value: mongodb  \n          ports:  \n            - containerPort: 8000  \n          livenessProbe:  \n            httpGet:  \n              path: \/  \n              port: 8000  \n            initialDelaySeconds: 5  \n            periodSeconds: 5\n<\/pre>\n<p><strong>NOTE:<\/strong>&nbsp;Take a close look at the line with&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">gcr.io\/spring-boot-gke\/kayak-app:1.0 <\/code>. That middle part there is the Google Cloud project name. This needs to match the project name you used along with the assigned ID number (something like&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">spring-boot-gke-43234<\/code>).<\/p>\n<p><code class=\"highlighter-rouge\" style=\"font-size: 13px;\">gcr.io<\/code>&nbsp;specifies a Google Cloud host for the docker image in the United States. It\u2019s possible to specify other locations. See the&nbsp;<a href=\"https:\/\/cloud.google.com\/container-registry\/docs\/pushing-and-pulling\">Google Container Registry docs<\/a>&nbsp;for more info.<\/p>\n<p>A brief summary of what\u2019s about to happen, as there are a lot of moving parts. The Spring Boot app is going to be docker-ized: built into a docker image. When you run the deployment script on your cluster, it\u2019s going to try to pull this image from the Google Container registry. Therefore you need to push the image to the container registry and tag it so that Kubernetes can find the correct image.<\/p>\n<p>If you\u2019re using a local Docker Desktop, go ahead and start it and wait for it to start.<\/p>\n<p>Before you do anything, you will need to configure Google Cloud and docker to play nicely together:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">gcloud auth configure-docker<\/pre>\n<p>Build the docker image:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">docker build -t kayak-app:1.0 .<\/pre>\n<p>Tag the image and push it to the Google container registry (again note the Google Cloud project name):<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">docker tag kayak-app:1.0 gcr.io\/$PROJECT_NAME\/kayak-app:1.0;  \ndocker push gcr.io\/$PROJECT_NAME\/kayak-app:1.0\n<\/pre>\n<p>Now apply the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">deployment.yml<\/code>&nbsp;file to the GKE cluster:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">kubectl apply -f deployment.yml<\/pre>\n<p>Check to make sure the pod deployed properly:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">kubectl get pods<\/pre>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">NAME                             READY     STATUS    RESTARTS   AGE\nkayak-service-7df4fb9c88-srqkr   1\/1       Running   0          56s\nmongodb-c5b8bf947-dmghb          1\/1       Running   0          16m\n<\/pre>\n<p>At this point, however, your cluster isn\u2019t quite ready. It\u2019s not publicly accessible.<\/p>\n<p>Create a file called&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">istio-gateway.yml<\/code><\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">apiVersion: networking.istio.io\/v1alpha3  \nkind: Gateway  \nmetadata:  \n  name: kayak-gateway  \nspec:  \n  selector:  \n    istio: ingressgateway # use Istio default gateway implementation  \n  servers:  \n  - port:  \n      name: http  \n      number: 80  \n      protocol: HTTP  \n    hosts:  \n    - '*'  \n---  \napiVersion: networking.istio.io\/v1alpha3  \nkind: VirtualService  \nmetadata:  \n  name: kayak-service  \nspec:  \n  hosts:  \n  - \"*\"  \n  gateways:  \n  - kayak-gateway  \n  http:  \n  - match:  \n    - uri:  \n        prefix: \/  \n    route:  \n    - destination:  \n        port:  \n          number: 8000  \n        host: kayak-service\n<\/pre>\n<p>And apply it:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">kubectl apply -f istio-gateway.yml<\/pre>\n<p>You should get:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">gateway.networking.istio.io \"kayak-gateway\" created\nvirtualservice.networking.istio.io \"kayak-service\" created<\/pre>\n<h2 class=\"wp-block-heading\" id=\"test-the-deployed-google-kubernetes-engine--spring-boot-app\">Test the Deployed Google Kubernetes Engine + Spring Boot App<\/h2>\n<p>Now that you have successfully deployed the Spring Boot app to the Google Kubernetes cluster and created the gateway linking your service to the outside world, you\u2019ll want to test the endpoint.<\/p>\n<p>There are some&nbsp;<a href=\"https:\/\/istio.io\/docs\/tasks\/traffic-management\/ingress\/\">good docs on the Istio website about ingress traffic<\/a>&nbsp;that have a lot of good information. Below, copied from that page, are some commands that will determine the public-facing host\/ip address and ports and save them into shell variables<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}');\nexport INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name==\"http2\")].port}');\n<\/pre>\n<p>In your configuration,&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">INGRESS_PORT<\/code>&nbsp;will likely just be the default 80 for HTTP (no SSL).<\/p>\n<p>Run the following command to see the host and ports:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">echo \"$INGRESS_HOST, HTTP PORT=$INGRESS_PORT\";<\/pre>\n<p>The public IP address can also be found by looking at the load balancer IP address in the&nbsp;<strong>Cloud Platform Dashboard -&gt; Kubernetes Engine -&gt; Services<\/strong>. Look for&nbsp;<strong>istio-ingressgateway<\/strong>&nbsp;service of type&nbsp;<strong>LoadBalancer<\/strong>.<\/p>\n<p>Test the app!<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">http $INGRESS_HOST:$INGRESS_PORT\/\n<\/pre>\n<p>You should see:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">HTTP\/1.1 200 OK\ncontent-type: text\/plain;charset=UTF-8\n...\n\nAlive\n<\/pre>\n<p>And hit the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/kayaks<\/code>&nbsp;endpoint:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">http $INGRESS_HOST:$INGRESS_PORT\/kayaks<\/pre>\n<p>You should see:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">HTTP\/1.1 200 OK\ncontent-type: application\/json;charset=UTF-8\n...\n[\n  {\n    \"makeModel\": \"NDK\",\n    \"name\": \"sea\",\n    \"owner\": \"Andrew\",\n    \"value\": 300.12\n  },\n  {\n    \"makeModel\": \"Piranha\",\n    \"name\": \"creek\",\n    \"owner\": \"Andrew\",\n    \"value\": 100.75\n  },\n  {\n    \"makeModel\": \"Necky\",\n    \"name\": \"loaner\",\n    \"owner\": \"Andrew\",\n    \"value\": 75\n  }\n]<\/pre>\n<p>Welcome to the world of microservices!<\/p>\n<p>There\u2019s obviously a ton more that can be done with GKE and Istio. In practices, microservices typically manage a large mesh of services and deployed pods that can be scaled up and down as needed, and complex security architectures can be managed between the different pieces and with the outside world. This tutorial won\u2019t get into more of that, but there is one more step left: adding JSON web token authentication with Okta.<\/p>\n<h2 class=\"wp-block-heading\" id=\"create-an-openid-connect-app-on-okta\">Create an OpenID Connect App on Okta<\/h2>\n<p>Log into your developer.okta.com account (You did sign up for one of their free developer accounts, right? If not head over to&nbsp;<a href=\"https:\/\/developer.okta.com?utm_campaign=text_website_all_multiple_dev_ciam_microservice-architecture-spring-boot-kubernetes_null&amp;utm_source=jcg&amp;utm_medium=cpc\">developer.okta.com<\/a>).<\/p>\n<p>Click on the&nbsp;<strong>Application<\/strong>&nbsp;top menu, then the&nbsp;<strong>Add Application<\/strong>&nbsp;button.<\/p>\n<p>Choose application type&nbsp;<strong>Web<\/strong>.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/create-new-application.png\" alt=\"Microservice Architecture\" class=\"wp-image-90618\" width=\"742\" height=\"551\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/create-new-application.png 989w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/create-new-application-300x223.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/create-new-application-768x571.png 768w\" sizes=\"(max-width: 742px) 100vw, 742px\" \/><\/figure>\n<\/div>\n<p>Click&nbsp;<strong>Next<\/strong>.<\/p>\n<p>Give the app a name. I named mine \u201cSpring Boot GKE\u201d.<\/p>\n<p>Under&nbsp;<strong>Login redirect URIs<\/strong>&nbsp;add&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">https:\/\/oidcdebugger.com\/debug<\/code>.<\/p>\n<p>Toward the bottom, under&nbsp;<strong>Grant type allowed<\/strong>, check the&nbsp;<strong>Implicit (hybrid)<\/strong>&nbsp;box.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" width=\"726\" height=\"883\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/oidc-application-setting.png\" alt=\"Microservice Architecture\" class=\"wp-image-90619\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/oidc-application-setting.png 726w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/04\/oidc-application-setting-247x300.png 247w\" sizes=\"(max-width: 726px) 100vw, 726px\" \/><\/figure>\n<\/div>\n<p>Click&nbsp;<strong>Done<\/strong>.<\/p>\n<p>Leave the page open and take note of the&nbsp;<strong>Client ID<\/strong>&nbsp;and&nbsp;<strong>Client Secret<\/strong>. You\u2019ll need them in a minute when you use the OIDC Debugger to generate a JSON web token.<\/p>\n<h2 class=\"wp-block-heading\" id=\"update-your-spring-boot-microservices-for-oauth-20\">Update Your Spring Boot Microservices for OAuth 2.0<\/h2>\n<p>Add the following dependencies to your&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">build.gradle<\/code>:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">compile 'org.springframework.security:spring-security-oauth2-client'\ncompile 'org.springframework.security:spring-security-oauth2-resource-server'\n\n<\/pre>\n<p>You also need to add the following to your&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">src\/main\/resources\/application.properties<\/code>&nbsp;file (filling in your own Oktadeveloper URL, something like dev-123456.okta.com):<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">spring.security.oauth2.resourceserver.jwt.issuer-uri=https:\/\/{yourOktaDomain}\/oauth2\/default<\/pre>\n<p>This tells Spring where it needs to go to authenticate the JSON web token (JWT) that you\u2019re going to generate in a moment.<\/p>\n<p>Finally, you need to add a new Java class called&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">SecurityConfiguration.java<\/code>:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">package com.okta.spring.springbootkbe;  \n  \nimport org.springframework.context.annotation.Bean;  \nimport org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;  \nimport org.springframework.security.config.web.server.ServerHttpSecurity;  \nimport org.springframework.security.web.server.SecurityWebFilterChain;  \n  \n@EnableWebFluxSecurity\n@EnableReactiveMethodSecurity\npublic class SecurityConfiguration {\n\n    @Bean\n    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {\n        http\n            .authorizeExchange()\n            .pathMatchers(\"\/\").permitAll()\n            .anyExchange().authenticated()\n            .and()\n            .oauth2ResourceServer()\n            .jwt();\n        return http.build();\n    }\n}\n<\/pre>\n<p>This file configures the project to allow all transactions on the root endpoint but to authorize all other transactions.<\/p>\n<h2 class=\"wp-block-heading\" id=\"build-a-new-docker-image-and-push-to-the-gke-cluster\">Build A New Docker Image and Push to the GKE Cluster<\/h2>\n<p>Now that you have a new, auth-enabled Spring Boot app, you need to build it, package it in a Docker container, push it to the Google Cloud Docker registry, and apply a new deployment to your Kubernetes cluster.<\/p>\n<p>Go to the project root directory from your shell.<\/p>\n<p>Build the Spring Boot app with the authentication updates:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">gradle clean build<\/pre>\n<p>Build the new Docker image. Notice the new image name (it includes&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">-auth<\/code>). Also: make sure your Docker Desktop is running.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">docker build -t kayak-app-auth:1.0 .<\/pre>\n<p>Tag and push your Docker image to the Google Cloud container registry. Change the project name in the repo path, if necessary.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">docker tag kayak-app-auth:1.0 gcr.io\/$PROJECT_NAME\/kayak-app-auth:1.0;  \ndocker push gcr.io\/$PROJECT_NAME\/kayak-app-auth:1.0;<\/pre>\n<p>Delete the deployed pod on the cluster:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">kubectl delete -f deployment.yml<\/pre>\n<p>Update the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">deployment.yml<\/code>&nbsp;file to reflect the new image name (line 28 in the file):<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">spec:  \n  containers:  \n    - name: kayak-app  \n      image: gcr.io\/spring-boot-gke\/kayak-app-auth:1.0\n<\/pre>\n<p>Re-deploy the updated Kubernetes deployment:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">kubectl apply -f deployment.yml<\/pre>\n<p>Use&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">kubectl get pods<\/code>&nbsp;to check the status of the pod. It will take a few seconds to fully update. Once it\u2019s ready, test the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/<\/code>endpoint.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">http $INGRESS_HOST:$INGRESS_PORT\/\nHTTP\/1.1 200 OK\n...\n\nAlive\n<\/pre>\n<p>And the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/kayaks<\/code>&nbsp;endpoint, which should be protected:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">$ http $INGRESS_HOST:$INGRESS_PORT\/kayaks\nHTTP\/1.1 401 Unauthorized\n...\n<\/pre>\n<p>So close! The last thing you need to do is to use the OIDC Debugger tool to generate a token and test the JWT authentication.<\/p>\n<h2 class=\"wp-block-heading\" id=\"generate-a-jwt-and-test-oauth-20\">Generate A JWT and Test OAuth 2.0<\/h2>\n<p>Go to the&nbsp;<a href=\"http:\/\/oidcdebugger.com\/\">OIDC Debugger<\/a>. You\u2019ll need your&nbsp;<strong>Client ID<\/strong>&nbsp;from your Okta OIDC application.<\/p>\n<ul class=\"wp-block-list\">\n<li>Fill in the Authorize URI:&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\"><span class=\"okta-preview-domain\">https:\/\/{yourOktaDomain}<\/span>\/oauth2\/default\/v1\/authorize<\/code><\/li>\n<li>Fill in the&nbsp;<strong>Client ID<\/strong>.<\/li>\n<li>Put&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">abcdef<\/code>&nbsp;for the&nbsp;<strong>state<\/strong>.<\/li>\n<li>At the bottom, click&nbsp;<strong>Send Request<\/strong>.<\/li>\n<\/ul>\n<p>Copy the generated token, and store it in a shell variable for convenience:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">TOKEN=eyJraWQiOiI4UlE5REJGVUJOTnJER0VGaEExekd6bWJqREp...<\/pre>\n<p>Run the GET on the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/kayaks<\/code>&nbsp;endpoint again, this time with the token:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">http $INGRESS_HOST:$INGRESS_PORT\/kayaks Authorization:\"Bearer $TOKEN\"\n<\/pre>\n<p><strong>NOTE the double quotes!<\/strong>&nbsp;Single quotes won\u2019t work because the variable won\u2019t be expanded in the string.<\/p>\n<p>You should get:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:js\">HTTP\/1.1 200 OK\ncache-control: no-cache, no-store, max-age=0, must-revalidate\ncontent-type: application\/json;charset=UTF-8\n...\n[\n  {\n    \"makeModel\": \"NDK\",\n    \"name\": \"sea\",\n    \"owner\": \"Andrew\",\n    \"value\": 300.12\n  },\n  {\n    \"makeModel\": \"Piranha\",\n    \"name\": \"creek\",\n    \"owner\": \"Andrew\",\n    \"value\": 100.75\n  },\n  {\n    \"makeModel\": \"Necky\",\n    \"name\": \"loaner\",\n    \"owner\": \"Andrew\",\n    \"value\": 75\n  }\n]\n<\/pre>\n<h2 class=\"wp-block-heading\" id=\"move-forward-with-spring-boot-microservices-and-kubernetes\">Move Forward with Spring Boot Microservices and Kubernetes<\/h2>\n<p>That\u2019s it! You\u2019ve covered a ton of ground here. You created a Kubernetes Cluster with Istio using Google Kubernetes on Google Cloud. You configured your local system to interact with the cluster using&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">gcloud<\/code>&nbsp;and&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">kubectl<\/code>. You created a Spring Boot app that used a MongoDB backend, dockerized it, pushed it to the Google Cloud registry, and deployed it to your cluster. You also added OIDC authentication to the app.<\/p>\n<p>You can find the source code for this example on GitHub at&nbsp;<a href=\"https:\/\/github.com\/oktadeveloper\/okta-spring-boot-microservice-kubernetes\">oktadeveloper\/okta-spring-boot-microservice-kubernetes<\/a>.<\/p>\n<p>If you\u2019re into microservices and Spring Boot, you might like these posts too:<\/p>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2019\/02\/28\/spring-microservices-docker?utm_campaign=text_website_all_multiple_dev_ciam_microservice-architecture-spring-boot-kubernetes_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Build Spring Microservices and Dockerize Them for Production<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2019\/03\/07\/spring-microservices-https-oauth2?utm_campaign=text_website_all_multiple_dev_ciam_microservice-architecture-spring-boot-kubernetes_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Secure Service-to-Service Spring Microservices with HTTPS and OAuth 2.0<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2018\/05\/17\/microservices-spring-boot-2-oauth?utm_campaign=text_website_all_multiple_dev_ciam_microservice-architecture-spring-boot-kubernetes_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Build and Secure Microservices with Spring Boot 2.0 and OAuth 2.0<\/a><\/li>\n<\/ul>\n<p>If you have any questions about this post, please add a comment below. For more awesome content, follow&nbsp;<a href=\"https:\/\/twitter.com\/oktadev\">@oktadev<\/a>&nbsp;on Twitter, like us&nbsp;<a href=\"https:\/\/www.facebook.com\/oktadevelopers\/\">on Facebook<\/a>, or subscribe to&nbsp;<a href=\"https:\/\/www.youtube.com\/channel\/UC5AMiWqFVFxF1q9Ya1FuZ_Q\">our YouTube channel<\/a>.<\/p>\n<p>&#8220;<a href=\"https:\/\/developer.okta.com\/blog\/2019\/04\/01\/spring-boot-microservices-with-kubernetes?utm_campaign=text_website_all_multiple_dev_ciam_microservice-architecture-spring-boot-kubernetes_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Build a Microservice Architecture with Spring Boot and Kubernetes<\/a>\u201d was originally published on the Okta developer blog on April 1, 2019.<\/p>\n<p><span style=\"font-size: 20px;\"><b>\u201cI love writing authentication and authorization code.\u201d ~ No Java Developer Ever.<\/b> Tired of building the same login screens over and over? <a href=\"https:\/\/developer.okta.com\/signup\/?utm_campaign=text_website_all_multiple_dev_ciam_microservice-architecture-spring-boot-kubernetes_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Try the Okta API for hosted authentication, authorization, and multi-factor auth.<\/a><\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u201cI love writing authentication and authorization code.\u201d ~ No Java Developer Ever. Tired of building the same login screens over and over? Try the Okta API for hosted authentication, authorization, and multi-factor auth. In this tutorial, you\u2019re going to use Kubernetes to deploy a Spring Boot microservice architecture to Google Cloud, specifically the Google Kubernetes &hellip;<\/p>\n","protected":false},"author":49514,"featured_media":240,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[1064,960,30,854],"class_list":["post-90611","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-enterprise-java","tag-kubernetes","tag-microservices","tag-spring","tag-spring-boot"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Build a Microservice Architecture with Spring Boot and Kubernetes - Java Code Geeks<\/title>\n<meta name=\"description\" content=\"Interested to learn about Microservice Architecture? Check our article explaining how to use Kubernetes to deploy a Spring Boot microservice architecture.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/developer.okta.com\/blog\/2019\/04\/01\/spring-boot-microservices-with-kubernetes\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Build a Microservice Architecture with Spring Boot and Kubernetes - Java Code Geeks\" \/>\n<meta property=\"og:description\" content=\"Interested to learn about Microservice Architecture? Check our article explaining how to use Kubernetes to deploy a Spring Boot microservice architecture.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/developer.okta.com\/blog\/2019\/04\/01\/spring-boot-microservices-with-kubernetes\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2019-04-15T05:44:32+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2019-04-24T08:59:25+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Andrew Hughes\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andrew Hughes\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"24 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/04\\\/01\\\/spring-boot-microservices-with-kubernetes#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/04\\\/build-microservice-architecture-spring-boot-kubernetes.html\"},\"author\":{\"name\":\"Andrew Hughes\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/0ded99ab51010abb68790f6189ce99d3\"},\"headline\":\"Build a Microservice Architecture with Spring Boot and Kubernetes\",\"datePublished\":\"2019-04-15T05:44:32+00:00\",\"dateModified\":\"2019-04-24T08:59:25+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/04\\\/build-microservice-architecture-spring-boot-kubernetes.html\"},\"wordCount\":3312,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/04\\\/01\\\/spring-boot-microservices-with-kubernetes#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"keywords\":[\"Kubernetes\",\"Microservices\",\"Spring\",\"Spring Boot\"],\"articleSection\":[\"Enterprise Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/04\\\/01\\\/spring-boot-microservices-with-kubernetes#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/04\\\/build-microservice-architecture-spring-boot-kubernetes.html\",\"url\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/04\\\/01\\\/spring-boot-microservices-with-kubernetes\",\"name\":\"Build a Microservice Architecture with Spring Boot and Kubernetes - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/04\\\/01\\\/spring-boot-microservices-with-kubernetes#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/04\\\/01\\\/spring-boot-microservices-with-kubernetes#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"datePublished\":\"2019-04-15T05:44:32+00:00\",\"dateModified\":\"2019-04-24T08:59:25+00:00\",\"description\":\"Interested to learn about Microservice Architecture? Check our article explaining how to use Kubernetes to deploy a Spring Boot microservice architecture.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/04\\\/01\\\/spring-boot-microservices-with-kubernetes#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/04\\\/01\\\/spring-boot-microservices-with-kubernetes\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/04\\\/01\\\/spring-boot-microservices-with-kubernetes#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"width\":150,\"height\":150,\"caption\":\"spring-interview-questions-answers\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/04\\\/01\\\/spring-boot-microservices-with-kubernetes#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Enterprise Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\\\/enterprise-java\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Build a Microservice Architecture with Spring Boot and Kubernetes\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/0ded99ab51010abb68790f6189ce99d3\",\"name\":\"Andrew Hughes\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/703689ecb161268c8a6ca8ad4057b8342d22972ec435111a055712b399716dbd?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/703689ecb161268c8a6ca8ad4057b8342d22972ec435111a055712b399716dbd?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/703689ecb161268c8a6ca8ad4057b8342d22972ec435111a055712b399716dbd?s=96&d=mm&r=g\",\"caption\":\"Andrew Hughes\"},\"sameAs\":[\"https:\\\/\\\/developer.okta.com\\\/blog\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/andrew-hughes\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Build a Microservice Architecture with Spring Boot and Kubernetes - Java Code Geeks","description":"Interested to learn about Microservice Architecture? Check our article explaining how to use Kubernetes to deploy a Spring Boot microservice architecture.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/developer.okta.com\/blog\/2019\/04\/01\/spring-boot-microservices-with-kubernetes","og_locale":"en_US","og_type":"article","og_title":"Build a Microservice Architecture with Spring Boot and Kubernetes - Java Code Geeks","og_description":"Interested to learn about Microservice Architecture? Check our article explaining how to use Kubernetes to deploy a Spring Boot microservice architecture.","og_url":"https:\/\/developer.okta.com\/blog\/2019\/04\/01\/spring-boot-microservices-with-kubernetes","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2019-04-15T05:44:32+00:00","article_modified_time":"2019-04-24T08:59:25+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","type":"image\/jpeg"}],"author":"Andrew Hughes","twitter_card":"summary_large_image","twitter_creator":"@javacodegeeks","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Andrew Hughes","Est. reading time":"24 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/developer.okta.com\/blog\/2019\/04\/01\/spring-boot-microservices-with-kubernetes#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2019\/04\/build-microservice-architecture-spring-boot-kubernetes.html"},"author":{"name":"Andrew Hughes","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/0ded99ab51010abb68790f6189ce99d3"},"headline":"Build a Microservice Architecture with Spring Boot and Kubernetes","datePublished":"2019-04-15T05:44:32+00:00","dateModified":"2019-04-24T08:59:25+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2019\/04\/build-microservice-architecture-spring-boot-kubernetes.html"},"wordCount":3312,"commentCount":1,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/developer.okta.com\/blog\/2019\/04\/01\/spring-boot-microservices-with-kubernetes#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","keywords":["Kubernetes","Microservices","Spring","Spring Boot"],"articleSection":["Enterprise Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/developer.okta.com\/blog\/2019\/04\/01\/spring-boot-microservices-with-kubernetes#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2019\/04\/build-microservice-architecture-spring-boot-kubernetes.html","url":"https:\/\/developer.okta.com\/blog\/2019\/04\/01\/spring-boot-microservices-with-kubernetes","name":"Build a Microservice Architecture with Spring Boot and Kubernetes - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/developer.okta.com\/blog\/2019\/04\/01\/spring-boot-microservices-with-kubernetes#primaryimage"},"image":{"@id":"https:\/\/developer.okta.com\/blog\/2019\/04\/01\/spring-boot-microservices-with-kubernetes#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","datePublished":"2019-04-15T05:44:32+00:00","dateModified":"2019-04-24T08:59:25+00:00","description":"Interested to learn about Microservice Architecture? Check our article explaining how to use Kubernetes to deploy a Spring Boot microservice architecture.","breadcrumb":{"@id":"https:\/\/developer.okta.com\/blog\/2019\/04\/01\/spring-boot-microservices-with-kubernetes#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/developer.okta.com\/blog\/2019\/04\/01\/spring-boot-microservices-with-kubernetes"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/developer.okta.com\/blog\/2019\/04\/01\/spring-boot-microservices-with-kubernetes#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","width":150,"height":150,"caption":"spring-interview-questions-answers"},{"@type":"BreadcrumbList","@id":"https:\/\/developer.okta.com\/blog\/2019\/04\/01\/spring-boot-microservices-with-kubernetes#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Java","item":"https:\/\/www.javacodegeeks.com\/category\/java"},{"@type":"ListItem","position":3,"name":"Enterprise Java","item":"https:\/\/www.javacodegeeks.com\/category\/java\/enterprise-java"},{"@type":"ListItem","position":4,"name":"Build a Microservice Architecture with Spring Boot and Kubernetes"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/0ded99ab51010abb68790f6189ce99d3","name":"Andrew Hughes","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/703689ecb161268c8a6ca8ad4057b8342d22972ec435111a055712b399716dbd?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/703689ecb161268c8a6ca8ad4057b8342d22972ec435111a055712b399716dbd?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/703689ecb161268c8a6ca8ad4057b8342d22972ec435111a055712b399716dbd?s=96&d=mm&r=g","caption":"Andrew Hughes"},"sameAs":["https:\/\/developer.okta.com\/blog"],"url":"https:\/\/www.javacodegeeks.com\/author\/andrew-hughes"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/90611","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/49514"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=90611"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/90611\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/240"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=90611"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=90611"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=90611"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}