Deploying sample Spring Boot app on Kubernetes with a MySQL RDS - dpsp-summit/wiki GitHub Wiki

In this tutorial we are going to deploy a sample application on a Kubernetes cluster and connect it to an external database.

The sample application is Products from this repository.
The database is going to be MySQL and will be created in AWS RDS.

Deploy MySQL RDS

Go to the AWS console -> Services -> RDS Select "Create Database"

Select "MySQL" then "Next" 1_select_engine

On the "Use Case" screen and for the purpose of this tutorial we are going to select "Dev/Test - MySQL" then "Next" 2_use_case

On the "Instance Specifications" screen we are going to check the "Only enable options eligible for RDS Free Usage Tier" on the "Free Tier" card.
3a_instance_specifications

On the same page, for the "Settings" card set an instance identifier, master username and master password then "Next" 3b_settings

Finally, on the "Network & Security" card, the available VPC and Subnet options will depend on your AWS configuration. For this tutorial, we are selecting the default VPC and Subnet, which is public, but this is not recommended for a production environment. 4_network

Also, for the Database name we will input "products" as we will be using the Products sample app. Then we click "Next", and we are done configuring our RDS.

After a few minutes the status of the instance is going to transition to "Available".

Add Kubernetes Cluster IPs to the RDS Security Group

We need to make sure that our Kubernetes cluster worker nodes can access the RDS instance. For that, we need to add the Kubernetes node IPs as inbound rules for the RDS security group or else we won't be able to reach the RDS from the nodes.

On the database details, click on the "VPN Security group" 5_instance

This will take you to the "Security groups" page with your security group selected. There, click on "Inbound" on the details section. You will see that there's only one IP allowed: 6a_inbound_rules

Click on "Edit", then "Add Rule". For the rule type select "MYSQL/Aurora" and on Source add your node ips separated by commas as in the next image:
6b_inbound_rules

Click "Save" and you're done!

Test DB connection locally

Once ready, we can test our MySQL connection locally by using the mysql client:

mysql -h mysqlinstance.ctnhfqspsvbe.us-west-2.rds.amazonaws.com -u username -p

Then we input the password and connect successfully to the instance.

Test DB connection from Kubernetes

To test if we can connect to our db from the Kubernetes cluster, we need to do the following:

  1. Run an Ubuntu pod that you can use as a client:
   kubectl run -i --tty ubuntu --image=ubuntu:16.04 --restart=Never -- bash -il
  1. Install the mysql client:
   apt-get update && apt-get install mysql-client -y
  1. Connect using the mysql cli, then provide your password:
   mysql -h mysqlinstance.ctnhfqspsvbe.us-west-2.rds.amazonaws.com -p

Then we input the password and connect successfully to the instance.

Creating DB Products

Once connected to the DB, we create Products the schema:

create schema products;
use products;

Create the products table:

CREATE TABLE IF NOT EXISTS products (
    id INT AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    PRIMARY KEY (id)
)  ENGINE=INNODB;

And insert some sample data:

INSERT INTO products VALUES (1, 'Produto 1');
INSERT INTO products VALUES (2, 'Produto 2');
INSERT INTO products VALUES (3, 'Produto 3');
INSERT INTO products VALUES (4, 'Produto 4');
INSERT INTO products VALUES (5, 'Produto 5');

Creating an External Service on the Kubernetes cluster

As we are connecting to an external resource, is a good practice to create an external service, so our application doesn't have to know about the real location of the database.

We create a file named external_service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: mysql-external
spec:
  type: ExternalName
  externalName: mysqlinstance.ctnhfqspsvbe.us-west-2.rds.amazonaws.com
  ports:
  - port: 3306

Remember to replace the "externalName" value with your actual RDS url.

And we create the service:

kubectl create -f external_service.yaml

Deploying the Spring-boot app

Now that we have our database and external service ready, we need to deploy the Products App. The code for our application is in this repository.

Create a file named products.yaml for the products and service deployment:

kind: Deployment
apiVersion: apps/v1
metadata:
  name: products
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: products
  template:
    metadata:
      labels:
        app: products
    spec:
      containers:
      - name: products
        image: fbereche/products-api:4.0.0
        env:
        - name: DB_SERVER
          value: mysql-external
        - name: DB_USERNAME
          value: username
        - name: DB_PASSWORD
          value: mypassword
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: products-service
spec:
  selector:
    app: products
  type: LoadBalancer
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

Note: Remember to replace the DB_SERVER value with your external service name, and to replace DB_USERNAME and DB_PASSWORD values with the username and password defined in your RDS instance.

Execute the creation:

kubectl create -f products.yaml

Testing the app

After deploying the products service, we should see a new Load Balancer being created on the AWS console. Similar to this:

afd0aa50ea0fd11e9b53a02f515ffc3f-1489305742.us-west-2.elb.amazonaws.com

We can confirm this is the same URL shown for our products-service on Kubernetes:

kubectl get svc

The result should show something similar to this:

NAME               TYPE           CLUSTER-IP       EXTERNAL-IP                                                               PORT(S)        AGE
kubernetes         ClusterIP      100.64.0.1       <none>                                                                    443/TCP        14d
mysql-external     ExternalName   <none>           mysqlinstance.ctnhfqspsvbe.us-west-2.rds.amazonaws.com                                                                    3306/TCP       22h
products-service   LoadBalancer   100.65.111.242   afd0aa50ea0fd11e9b53a02f515ffc3f-1489305742.us-west-2.elb.amazonaws.com   80:31808/TCP   22h

It will take a few minutes to transition from OutOfService to InService. After it is ready, we can do a GET to the following URL:

afd0aa50ea0fd11e9b53a02f515ffc3f-1489305742.us-west-2.elb.amazonaws.com/products

We should get the following information:

[{"id":1,"name":"Produto 1"},{"id":2,"name":"Produto 2"},{"id":3,"name":"Produto 3"},{"id":4,"name":"Produto 4"},{"id":5,"name":"Produto 5"}]

Now you have an Spring Boot application connecting to an RDS instance. Congratulations!

⚠️ **GitHub.com Fallback** ⚠️