Spotted a bug? Have a great idea? Help us make google.dev great!

Kubernetes is an open-source project which can run in many different environments, from laptops to high-availability multi-node clusters, from public clouds to on-premise deployments, and from virtual machine (VM) instances to bare metal.

In this codelab, you'll deploy a simple Spring Boot Java web app to Kubernetes on GKE, with the goal being for you to run your web app as a replicated app running on Kubernetes. You'll take code that you develop on your machine, turn it into a Docker container image, and run the image on GKE.

Here's a diagram of the various parts at play in the codelab to help you understand how the pieces will fit together. Use it as a reference as you progress through the codelab, but remember that it'll make more sense by the end.

Kubernetes Codelab Diagram 1 (2).png

You'll use GKE (a Google-hosted version of Kubernetes that runs on Compute Engine), which allows you to focus more on experiencing Kubernetes, rather than setting up the underlying infrastructure.

If you're interested in running Kubernetes on your local machine, such as a development laptop, then look into Minikube, which offers a simple setup of a single-node Kubernetes cluster for development and testing purposes. You can use Minikube to go through the codelab if you wish.

The codelab will use the sample code from the guide about Building an Application with Spring Boot.

What you'll learn

  • How to package a simple Java app as a Docker container
  • How to create your Kubernetes cluster on GKE
  • How to deploy your Java app into Kubernetes on GKE
  • How to scale up your service and roll out an upgrade
  • How to access Dashboard, a web-based Kubernetes user interface

What you'll need

  • A Google Cloud project
  • A Browser, such Google Chrome
  • Familiarity with standard Linux text editors, such as Vim, EMACs or Nano

How will you use the codelab?

Read it through only Read it and complete the exercises

How would you rate your experience with building HTML and CSS web apps?

Novice Intermediate Proficient

How would you rate your experience with using Google Cloud services?

Novice Intermediate Proficient

Self-paced environment setup

If you don't already have a Google Account (Gmail or Google Apps), you must create one. Sign-in to Google Cloud Platform console (console.cloud.google.com) and create a new project:

Screenshot from 2016-02-10 12:45:26.png

Remember the project ID, a unique name across all Google Cloud projects (the name above has already been taken and will not work for you, sorry!). It will be referred to later in this codelab as PROJECT_ID.

Next, you'll need to enable billing in the Cloud Console in order to use Google Cloud resources.

Running through this codelab shouldn't cost you more than a few dollars, but it could be more if you decide to use more resources or if you leave them running (see "cleanup" section at the end of this document).

New users of Google Cloud Platform are eligible for a $300 free trial.

After Cloud Shell launches, you can use the command line to clone the example source code in the home directory.

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

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

$ ./mvnw -DskipTests spring-boot:run

After the app starts, click on the Web preview icon in the Cloud Shell toolbar and choose Preview on port 8080.

A tab in your browser opens and connects to the server you just started.

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

Create the JAR deployable for the app.

$ ./mvnw -DskipTests package

Enable Container Registry to store the container image that you'll create.

$ gcloud services enable containerregistry.googleapis.com

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

If all goes well, then you should be able to see the container image listed in the console by navigating to Container Registry > Images. You now have a project-wide Docker image available, which Kubernetes can access and orchestrate as you'll see in a few minutes.

After that completes (it'll take some time to download and extract everything), you can locally test the image 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

Again, take advantage of the Web preview feature of Cloud Shell.

Screenshot from 2015-11-03 17:20:22.png

You should see the default page in a new tab. After you sverify that the app is locally running in a Docker container, you can stop the running container by pressing Control+C (Command+C on Macintosh).

You're ready to create your GKE 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 VMs.

First, make sure that the related API features are enabled.

$ gcloud services enable compute.googleapis.com container.googleapis.com
Operation "operations/..." finished successfully

Create a cluster with two n1-standard-1 nodes (it 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

In the end, you should see the cluster created.

Creating cluster hello-java-cluster...done.
Created [https://container.googleapis.com/v1/projects/...].
kubeconfig entry generated for hello-dotnet-cluster.
NAME                  ZONE            MASTER_VERSION  
hello-java-cluster  us-central1-c  ...

You should now have a fully functioning Kubernetes cluster powered by GKE.

It's now time to deploy your containerized app to the Kubernetes cluster! From now on, you'll use the kubectl command line (already set up in your Cloud Shell environment). The rest of the codelab requires the Kubernetes client and server version to be 1.2 or above. kubectl version will show you the current version of the command.

A Kubernetes deployment can create, manage, and scale multiple instances of your app using the container image that you created. Deploy one instance of your app to Kubernetes using the kubectl run command:

$ kubectl create deployment hello-java \
  --image=gcr.io/$GOOGLE_CLOUD_PROJECT/hello-java:v1

To view the deployment that you created, simply run the following command:

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

To view the app instances created by the deployment, run the following command:

$ kubectl get pods
NAME                         READY     STATUS    RESTARTS   AGE
hello-java-714049816-ztzrb   1/1       Running   0          57s

At this point, you should have your container running under the control of Kubernetes, but you still have to make it accessible to the outside world.

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.

In Cloud Shell, you can expose the Pod to the public internet with the kubectl expose command combined with the --type=LoadBalancer flag. The flag is required for the creation of an externally accessible IP.

$ kubectl create service loadbalancer hello-java --tcp=8080:8080

The flag used in the command specifies that you'll be using the load balancer provided by the underlying infrastructure. Note that you directly expose the deployment, not the pod. That will cause the resulting service to load balance traffic across all Pods managed by the deployment (in this case, only one Pod, but you'll add more replicas later).

The Kubernetes Master creates the load balancer and related Compute Engine forwarding rules, target pools, and firewall rules to make the service fully accessible from outside of Google Cloud.

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

$ kubectl get services
NAME         CLUSTER-IP     EXTERNAL-IP      PORT(S)    AGE
Hello-java   10.3.253.62    aaa.bbb.ccc.ddd  8080/TCP    1m
kubernetes   10.3.240.1     <none>           443/TCP    5m

Notice that there are two IP addresses listed for your service, both serving port 8080. One is the internal IP address that is only visible inside your Virtual Private Cloud (VPC). The other is the external load-balanced IP address. In the example, the external IP address is aaa.bbb.ccc.ddd. You should now be able to reach the service by pointing your browser to http://<EXTERNAL_IP>:8080.

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

$ kubectl scale deployment hello-java --replicas=3
deployment "hello-java" scaled

$ kubectl get deployment
NAME         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-java   3         3         3            3           22m

Notice the declarative approach. Rather than starting or stopping new instances, you declare how many instances should be running at all times. Kubernetes reconciliation loops simply make sure that the reality matches what you requested and takes action, if needed.

At some point, the app that you deployed to production will require bug fixes or additional features. Kubernetes can help you deploy a new version to production without impacting your users.

First, you need to modify the app, so open the code editor in Cloud Shell.

Navigate to src/main/java/hello/HelloController.java and 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 Google Kubernetes Engine!";
    }
}

Use Jib to build and push a new version of the container image.

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

You're ready for Kubernetes to smoothly update your replication controller to the new version of the app!

In order to change the image label for your running container, you need to edit the existing hello-java deployment and change the image from gcr.io/PROJECT_ID/hello-java:v1 to gcr.io/PROJECT_ID/hello-java:v2.

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

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

deployment "hello-java" image updated

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

Oops! Did you make a mistake with a new version of the app? Perhaps the new version contained an error and you need to quickly roll it back. With Kubernetes, you can roll it back to the previous state easily. Rollback the app by running the following command:

$ kubectl rollout undo deployment/hello-java

You learned to build and deploy a new Java-based web app to Kubernetes on GKE.

Learn more

License

This work is licensed under a Creative Commons Attribution 2.0 Generic License.