When Java meet GKE
Tags: java, kubernetes, cloudcomputing, gcp
Published: 2023-05-07 05:15:14

## Introduction

This post is the third and last one in our series 'When Java Meets...'. In the first two posts, we learned how to deploy a Java application with Docker and then with Kubernetes in a local environment. 

In this article, we will learn how to deploy our Java application on GKE, which is a managed service for deploying and managing containerized applications on Google Cloud Platform.
&nbsp;
## What is GKE ?

GKE stands for Google Kubernetes Engine, which is a managed service for deploying and managing containerized applications on Google Cloud Platform. It is a fully managed platform that allows you to easily run and manage containerized applications in the cloud.

As we explained in the previous posts, Kubernetes is an open-source container orchestration system that allows you to deploy, scale, and manage containerized applications. GKE provides a fully managed Kubernetes environment that is optimized for running containerized applications on Google Cloud Platform. With GKE, you can focus on your application development while Google manages the underlying infrastructure.

GKE provides features such as automatic scaling, load balancing, and automatic upgrades to ensure your application is always available and running smoothly. It also integrates with other Google Cloud Platform services such as Cloud Storage, Cloud SQL, and Cloud Build, making it easy to build and deploy modern cloud-native applications.

In summary, GKE is a powerful and fully managed platform for deploying and managing containerized applications on Google Cloud Platform using Kubernetes.

 &nbsp;   
## Environment configuration

Before we can create a GKE cluster and deploy our application, The steps below needs to be performed:

>Before to start, please ensure that you already have a GCP account, if not you can a create a GCP free tier  account, which will be sufficient for this tutorial.

  &nbsp;   
### Install gcloud CLI

Google Cloud (gcloud) CLI is a tool we can use to interact  with various Google Cloud Platform services from the command line, such as Google Compute Engine, Google Kubernetes Engine, and Google Cloud Storage.  

For example, you can use the gcloud CLI to create and manage the following:
- Compute Engine virtual machine instances and other resources
- Cloud SQL instances
- Google Kubernetes Engine clusters
- Dataproc clusters and jobs
- Cloud DNS managed zones and record sets
- Cloud Deployment Manager deployments

gcloud also provides access to additional tools and commands for managing Google Cloud Platform services, including authentication and authorization, configuration management, and resource management.

The installation below was done on a **64-bit Ubuntu 20.04.1 LTS**. your environment may differ, you can find the installation types for other platfroms in this link : https://cloud.google.com/sdk/docs/install

1. 
    First download the gcloud archive and extract the content of 
    the file:

    ```
    curl -O 
    https://dl.google.com/dl/cloudsdk/channels/rapid/downloads
    /google-cloud-cli-429.0.0-linux-x86_64.tar.gz

    tar -xf google-cloud-cli-429.0.0-linux-x86_64.tar.gz

    ```



2. Run the installation script from the root of the folder you 
    extracted to using the following command:
    ```
    ./google-cloud-sdk/install.sh
    ```


3. Once the installation is done, run the gcloud init command:
    ```
    gcloud init
    ```


    gcloud init performs the following setup steps:
     - Authorizes the gcloud CLI to use your user account 
       credentials to access Google Cloud, or lets you select an 
       account if you have previously authorized access
     - Sets up a gcloud CLI configuration and sets a base set of 
       properties, including the active account from the step 
       above, the current project, and if applicable, the default 
       Compute Engine region and zone


    When gcloud init finishes, it prints the properties in the
    active configuration to the terminal::
    ```
    gcloud init    
    [compute]
    region = us-east1
    zone = us-east1-b
    [core]
    account = user@google.com
    disable_usage_reporting = False
    project = example-project```
    

Now we are ready to create our project dedicated to our Players application.

  &nbsp;   
### Create a new project in GCP

1. To create a new project run this command: 
    ```
    gcloud projects create players-app --name="players-app project" --labels=type=tuto
    ```

2. Once is done, activate the new project configuration by running this command:
    ```
    gcloud config configurations create playersapp --account your-gcp-account --project players-app
    gcloud config configurations activate playersapp
    ```
    
    This command will create a new configuration and make it active. If you want to see the configuration list, run this command:
    ```
    gcloud config configurations list
    ```
        
   
   
3. Set the default region and zone for your project. This way you will not need to type those info when creating the GKE cluster and other resources:
    ```
    gcloud compute project-info add-metadata --metadata google-compute-default-region=europe-west1,google-compute-default-zone=europe-west1-b
    ```

    If you want to do a check, you should see the keys **google-compute-default-region** and **google-compute-default-zone** with the region entered above after you execute this command: 
    ```
    gcloud compute project-info describe --project players-app
    ```

4. We are almost there, to avoid having an error message when creating our GKE cluster, we need to activate some GCP services by running this command: 
    ```
    gcloud services enable compute.googleapis.com container.googleapis.com
    ```
&nbsp;
## Play with GKE!
&nbsp;
### Create the GKE cluster
Now that everything is ready, we can create a GKE cluster that we will call players-gke by executing this command:
```
gcloud container clusters create players-gke --release-channel None
```

We can check in the GCP web console that our GKE cluster is now up and running:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uhvvnlwdkl2r2wc6ilb1.png)


As simple as that! now we have a Kubernetes cluster ready to host our application!
&nbsp;
### Install kubectl tool
To interact with our cluster we need to use kubectl. in your shell terminal run this command:
```
gcloud components install kubectl
```

To verify that **kubectl** is installed run:
```
kubectl version
```

Run this command to update **kubectl** configuration:
```
gcloud container clusters get-credentials players-gke \
    --region=northamerica-northeast2
```

Verify that your configuration is done properly by typing this command :
```
$ kubectl get namespaces
NAME              STATUS   AGE
default           Active   40m
kube-node-lease   Active   40m
kube-public       Active   40m
kube-system       Active   40m
```
&nbsp;

Alright, let's deploy our application on our newly created cluster!

### Deploy players app on GKE
In the same way we did on the local Kubernetes cluster in the [previous post](https://dev.to/malek_ramdani/when-java-meet-docker-part-ii-kubernetes-1cm1), we will use kubectl appl to deploy our application, using two yaml files that you can find in this [GitHub repo](https://github.com/MalikooR/players_spring_boot/tree/main/kubernetes), one for the SpringBoot application and the other for the postgres database :
```
$ kubectl apply -f postgres.yaml 
deployment.apps/playersdb created
service/playersdb created
$ kubectl apply -f deployment.yaml 
deployment.apps/players created
service/players created
```
Now our workload is deployed and we can see in the cloud console:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ppl2t4mgswlg5sszje2c.png)

We can also see the services that has been created:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yig0g0whe4ktmtowx3fh.png)

### Test our application
To test our application we need to make a REST api call to the players app which is exposed through a Node port.

First we need to view the service, the output shows a nodePort value:
```
$ kubectl get service players --output yaml
apiVersion: v1
kind: Service
metadata:
  annotations:
    cloud.google.com/neg: '{"ingress":true}'
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"creationTimestamp":null,"labels":{"app":"players"},"name":"players","namespace":"default"},"spec":{"ports":[{"port":8080,"protocol":"TCP","targetPort":8080}],"selector":{"app":"players"},"type":"NodePort"},"status":{"loadBalancer":{}}}
  creationTimestamp: "2023-05-08T03:12:39Z"
  labels:
    app: players
  name: players
  namespace: default
  resourceVersion: "27799"
  uid: a719a733-f2d9-4a42-9a97-f49af11d62fb
spec:
  clusterIP: 10.72.9.232
  clusterIPs:
  - 10.72.9.232
  externalTrafficPolicy: Cluster
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - nodePort: 31538
    port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    app: players
  sessionAffinity: None
  type: NodePort
status:
  loadBalancer: {}
```

We can see above that the nodePort value is **31538**. We create a firewall rule to allow TCP traffic on your node port:
```
gcloud compute firewall-rules create test-node-port --allow tcp:31538
```

We need alos to find the external IP address of one of our nodes :
```
$ kubectl get nodes --output wide
NAME                                         STATUS   ROLES    AGE   VERSION            INTERNAL-IP   EXTERNAL-IP      OS-IMAGE                             KERNEL-VERSION   CONTAINER-RUNTIME
gke-players-gke-default-pool-5fe50b35-6l48   Ready    <none>   65m   v1.25.7-gke.1000   10.188.0.9    34.130.171.114   Container-Optimized OS from Google   5.15.65+         containerd://1.6.18
gke-players-gke-default-pool-5fe50b35-j7dw   Ready    <none>   65m   v1.25.7-gke.1000   10.188.0.8    34.130.43.212    Container-Optimized OS from Google   5.15.65+         containerd://1.6.18
gke-players-gke-default-pool-5fe50b35-jn77   Ready    <none>   65m   v1.25.7-gke.1000   10.188.0.7    34.130.245.5     Container-Optimized OS from Google   5.15.65+         containerd://1.6.18
```

Finally we can start testing our service by sending our API call using on of the external node IPs in our URL:
```
$ curl -i --location --request GET '34.130.43.212:31538/api/player/v1/test'
HTTP/1.1 200 
Content-Type: text/plain;charset=UTF-8
Content-Length: 14
Date: Mon, 08 May 2023 03:40:52 GMT

This is a test
```

Great! We can see that our application is responding, now we can make another api calls to add players and get the list of them as well:
```
$ curl -i --location --request POST 'http://34.130.171.114:31538/api/player/v1/add' \
--header 'Content-Type: application/json' \
--data-raw '{
    "firstName": "Riyad",
    "lastName": "Mahrez",
    "team": "Manchester City",
    "position": "RW"
}'

HTTP/1.1 200 
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 08 May 2023 03:43:54 GMT

{"id":1,"firstName":"Riyad","lastName":"Mahrez","team":"Manchester City","position":"RW"}

$ curl -i --location --request POST 'http://34.130.171.114:31538/api/player/v1/add' \
--header 'Content-Type: application/json' \
--data-raw '{
    "firstName": "Ismail",
    "lastName": "Bennacer",
    "team": "AC Milan",
    "position": "CM"
}'

{"id":2,"firstName":"Ismail","lastName":"Bennacer","team":"AC Milan","position":"CM"}

$ curl -i --location --request GET 'http://34.130.245.5:31538/api/player/v1/list'

HTTP/1.1 200 
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 08 May 2023 03:47:42 GMT

[{"id":1,"firstName":"Riyad","lastName":"Mahrez","team":"Manchester City","position":"RW"},{"id":2,"firstName":"Ismail","lastName":"Bennacer","team":"AC Milan","position":"CM"}]
```

Congratulations! You've made it to the end of our practical guide on containerizing a Java application and deploying it in various environments using Docker, a local Kubernetes cluster, and a public cloud Kubernetes cluster. By following the steps outlined in this series of posts, you should now have a solid understanding of the containerization process and how to deploy your application to a Kubernetes cluster.

We hope this guide has been helpful in your journey towards mastering containerization and Kubernetes deployment. Remember, this is just the beginning, and there is always more to learn and explore in this ever-evolving field.

Thank you for reading, and happy containerizing!