Deploy a Java application to Kubernetes on Google Kubernetes Engine

Get the Spring Boot Getting Started Example source code

git clone https://github.com/spring-guides/gs-spring-boot.git
cd gs-spring-boot/complete

Run the Application Locally

You can start the Spring Boot application normally with the Spring Boot plugin:

./mvnw -DskipTests spring-boot:run

Package the Java application as a Docker container

Next, prepare your app to run on Kubernetes. The first step is to define the container and its contents.

First, create the JAR deployable for the application

./mvnw -DskipTests package

Use Jib to create the container image and push it to the Container Registry.

./mvnw -DskipTests com.google.cloud.tools:jib-maven-plugin:build \
  -Dimage=gcr.io/$GOOGLE_CLOUD_PROJECT/hello-java:v1

At this point you now have a project-wide Docker image available which Kubernetes can access and orchestrate as you'll see in a few minutes.

You can test the image locally with the following command which will run a Docker container as a daemon on port 8080 from your newly-created container image:

docker run -ti --rm -p 8080:8080 \
  gcr.io/$GOOGLE_CLOUD_PROJECT/hello-java:v1

Create your cluster

A cluster consists of a Kubernetes master API server managed by Google and a set of worker nodes. The worker nodes are Compute Engine virtual machines. Let's use the gcloud CLI from your CloudShell session to create a cluster with two n1-standard-1 nodes (this will take a few minutes to complete):

gcloud container clusters create hello-java-cluster \
  --num-nodes 2 \
  --machine-type n1-standard-1 \
  --zone us-central1-c

Deploy your application to Kubernetes

A Kubernetes deployment can create, manage, and scale multiple instances of your application using the container image you've just created. Let's deploy one instance of your application into Kubernetes using the kubectl run command:

kubectl run hello-java \
  --image=gcr.io/$GOOGLE_CLOUD_PROJECT/hello-java:v1 \
  --port=8080
deployment.apps/hello-java created

To view the deployment you just created, simply run:

kubectl get deployments
NAME         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-java   1         1         1            1           39s

To view the application instances created by the deployment, run this command:

kubectl get pods
NAME                         READY     STATUS    RESTARTS   AGE
hello-java-9cc6bbf87-62np4   1/1       Running   0          1m

Allow external traffic

By default, the pod is only accessible by its internal IP within the cluster. In order to make the hello-java container accessible from outside the kubernetes virtual network, you have to expose the pod as a kubernetes service.

From Cloud Shell you can expose the pod to the public internet with the kubectl expose command combined with the --type=LoadBalancer flag. This flag is required for the creation of an externally accessible IP :

kubectl expose deployment hello-java --type=LoadBalancer
service/hello-java exposed

To find the publicly-accessible IP address of the service, simply request kubectl to list all the cluster services:

kubectl get services
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)          AGE
hello-java   LoadBalancer   10.15.245.109   35.209.103.19   8080:32124/TCP   2m
kubernetes   ClusterIP      10.15.240.1     <none>          443/TCP          7m

You should now be able to reach the service by pointing your browser to this address: http://<EXTERNAL_IP>:8080

curl http://35.209.103.19:8080/
Greetings from Spring Boot!

Scale up your service

One of the powerful features offered by Kubernetes is how easy it is to scale your application. Suppose you suddenly need more capacity for your application; you can simply tell the replication controller to manage a new number of replicas for your application instances:

kubectl scale deployment hello-java --replicas=3
deployment.extensions/hello-java scaled
kubectl get deployment
NAME         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-java   3         3         3            3           7m

Note the declarative approach here - rather than starting or stopping new instances you declare how many instances should be running at all time. Kubernetes reconciliation loops simply make sure the reality matches what you requested and takes action if needed.

Roll out an upgrade to your service

At some point the application that you've deployed to production will require bug fixes or additional features. Kubernetes is here to help you deploy a new version to production without impacting your users.

vim src/main/java/hello/HelloController.java

Update the value of the response:

package hello;

import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;

@RestController
public class HelloController {

    @RequestMapping("/")
    public String index() {
        return "Greetings from Admatic!";
    }
}

Then rebuild the application with the latest changes:

./mvnw -DskipTests package

Then use Jib to build and push a new version of the container image:

./mvnw -DskipTests com.google.cloud.tools:jib-maven-plugin:build \
  -Dimage=gcr.io/$GOOGLE_CLOUD_PROJECT/hello-java:v2

You can use kubectl set image command to ask Kubernetes to deploy the new version of your application across the entire cluster one instance at a time with rolling update:

kubectl set image deployment/hello-java \
  hello-java=gcr.io/$GOOGLE_CLOUD_PROJECT/hello-java:v2
deployment.extensions/hello-java image updated

Check http://EXTERNAL_IP:8080 again to see that it's returning the new response.

curl http://35.209.103.19:8080/
Greetings from Admatic!

Roll back

Oops - did you make a mistake with a new version of the application? Perhaps the new version contained an error and you need to rollback quickly. With Kubernetes, you can roll back to the previous state easily. Let's rollback the application by running:

kubectl rollout undo deployment/hello-java

results matching ""

    No results matching ""