Thursday, September 2, 2021

Create, Manage and Connect to MySQL Database Service using OCI Service Operator for Kubernetes

We see a growing trend of cloud native adoption with microservices application running on Kubernetes. Studies show microservices application adoption in an organization can increase development speed, reduce time to market, making the entire development and operation to be agile while helping business to reduce capital expenditure and operating expenses. In Oracle Cloud (OCI), we can deploy microservices application on Container Engine for Kubernetes (OKE), which is essentially Kubernetes cluster as a service. Microservices application for business needs database for storing business data, therefore deploying a new database can be the implication of deploying a new set of microservices application.

Oracle MySQL Database Service (MDS) is a fully managed MySQL database service on OCI using MySQL Enterprise Edition. MDS enables developers to quickly develop and secure, cloud native applications. See below reference architecture for MDS with microservices application on OKE.

 

 

But often having an architecture with microservices application runs on Kubernetes and MySQL database on MDS causes a disjointed experience in terms of lifecycle management. That’s why Oracle recently releases OCI Service Operator for Kubernetes (OSOK), a Kubernetes Operator to enable provisioning and managing OCI resources using Kubernetes API. Using OSOK on OKE, you can provision and manage MDS the same way you manage your microservices application on OKE, unifying the lifecycle management experience. It removes the needs to use OCI console, OCI CLI, or other tools for MDS which often causes a disjointed experience between microservices application and the MDS. This can dramatically increase deployment and development velocity. On top of that, OKE provides a nice way for your microservices application to connect to MDS from OKE environment.

 

This article discusses step by step OSOK installation and how to use OSOK to provision MDS and connect to MDS from OKE.


A. OSOK Installation on OKE

To use OSOK on OKE, first we need to install it. I used OCI Cloud shell as my workspace because it’s easy and straight forward. It’s a web browser terminal accessible from the OCI console which provides access to a Linux Shell with a pre-authenticated OCI CLI, other useful tools such as kubectl, etc.

A.1. Install Operator-SDK

To install OSOK, first time users need to install the Operator-SDK to connect to the OKE cluster. The Operator-SDK is a framework that uses the controller-runtime library to make writing operators easier. Below are the commands I used to install the Operator-SDK onto my cloud shell.

(refer to https://sdk.operatorframework.io/docs/installation/ and https://github.com/oracle/oci-service-operator/blob/main/docs/installation.md#install-operator-sdk for more detail information).

$ export ARCH=$(case $(uname -m) in x86_64) echo -n amd64 ;; aarch64) echo -n arm64 ;; *) echo -n $(uname -m) ;; esac)
$ export OS=$(uname | awk '{print tolower($0)}')
$ export OPERATOR_SDK_DL_URL=https://github.com/operator-framework/operator-sdk/releases/download/v1.11.0
$ curl -LO ${OPERATOR_SDK_DL_URL}/operator-sdk_${OS}_${ARCH}
$ gpg --keyserver keyserver.ubuntu.com --recv-keys 052996E2A20B5C7E
$ curl -LO ${OPERATOR_SDK_DL_URL}/checksums.txt
$ curl -LO ${OPERATOR_SDK_DL_URL}/checksums.txt.asc
$ gpg -u "Operator SDK (release) <cncf-operator-sdk@cncf.io>" --verify checksums.txt.asc
$ grep operator-sdk_${OS}_${ARCH} checksums.txt | sha256sum -c -
$ ln -s operator-sdk_linux_amd64 operator-sdk


Next, I used this Operator-SDK to install OSOK Operator Lifecycle Manager (OLM) bundle onto my OKE cluster. OLM provides a declarative way to install, manage, and upgrade Operators and their dependencies in a Kubernetes cluster. The OSOK OLM bundle contains all required CRDs, RBACs, ConfigMaps, and deployment to install the OSOK in a Kubernetes cluster.

On Cloud Shell:
$ ./operator-sdk olm install

We can check the status of our OLM:
$ ./operator-sdk olm status


 A.2. Configure OCI IAM service policy

Next, I configured OCI IAM service policy to allow OSOK to manage OCI services in my tenancy. First, I created a Dynamic Group using OCI console by navigating to “Identity & Security” > “Dynamic Groups”. Below is a sample format of Matching Rule required that matches the OKE worker instance ocid or the compartment where the compartment where the worker instances are running:

Any {instance.id = 'ocid1.instance.oc1.iad..exampleuniqueid1', instance.compartment.id = 'ocid1.compartment.oc1..exampleuniqueid2'}


The following is my Dynamic Group created. I set its name as “han-oci-operator”.


Then, I added this Dynamic Group into an OCI policy using OCI console by navigating to “Identity & Security” > “Policies”.  The following are the required policy statement added -- please change the below dynamic group name and compartment name according to your tenancy:

Allow dynamic-group han-oci-operator
to manage mysql-family in compartment HanantoWicaksono-Sandbox

Allow dynamic-group han-oci-operator to {SUBNET_READ, SUBNET_ATTACH, SUBNET_DETACH, VCN_READ, COMPARTMENT_INSPECT} in compartment HanantoWicaksono-Sandbox

Allow dynamic-group han-oci-operator to use tag-namespaces in compartment HanantoWicaksono-Sandbox


A.3. Setup User Principal on OKE and Deploy OSOK

A user principal on OKE is required because OSOK needs OCI user credential detail to provision and manage OCI resources in my tenancy. I enabled user principal on OKE using the following sample YAML:

$ vi oci-user-principal.yaml

apiVersion: v1
kind: Namespace
metadata:
  labels:
    control-plane: controller-manager
  name: oci-service-operator-system

Apply the above YAML file into OKE:

$ kubectl apply -f oci-user-principal.yaml

Then, I create a secret on OKE to store OCI credentials using the following command -- please change the below detail with your tenancy detail:

kubectl -n oci-service-operator-system create secret generic ocicredentials \
--from-literal=tenancy=<CUSTOMER_TENANCY_OCID> \
--from-literal=user=<USER_OCID> \
--from-literal=fingerprint=<USER_PUBLIC_API_KEY_FINGERPRINT> \
--from-literal=region=<USER_OCI_REGION> \
--from-literal=passphrase=<PASSPHRASE_STRING> \
--from-file=privatekey=<PATH_OF_USER_PRIVATE_API_KEY>


Let’s take a look if this secret is already created:

 

 

 

Next, I deployed the operator using the following command:

./operator-sdk run bundle iad.ocir.io/oracle/oci-service-operator-bundle:0.0.2


Woohoo, done ! My OKE right now has additional CRD to provision and manage MDS, called “mysqldbsystem”.


B.    Provision MDS from OKE

Once OSOK installation is completed, you can do provisioning and updating many MDS as you want. Even, you can also bind existing MDS into OKE using OSOK, so it can be maintainable from OKE.

First, I created a secret for my new MDS on mysql-cluster namespace. Please note username and password in the YAML file below are written on base64-encoding. The actual meaning for username is “system”, and for password is “Manager@123”.

$ vi oso-mds-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: mds-admin-secret
  namespace: mysql-cluster
type: Opaque
data:
  username: c3lzdGVt
  password: TWFuYWdlckAxMjM=


$ kubectl apply -f oso-mds-secret.yaml

Then, I deployed my new MDS using the following YAML format and applied using kubectl:

apiVersion: oci.oracle.com/v1beta1
kind: MySqlDbSystem
metadata:
  name: <CR_OBJECT_NAME>
  namespace: <namespace-name>
spec:
  compartmentId: <COMPARTMENT_OCID>
  displayName: <DISPLAY_NAME>
  shapeName: <SHAPE>
  subnetId: <SUBNET_OCID>
  configuration:
    id: <CONFIGURATION_OCID>
  availabilityDomain: <AVAIALABILITY_DOMAIN>
  adminUsername:
    secret:
      secretName: <ADMIN_SECRET>
  adminPassword:
    secret:
      secretName: <ADMIN_SECRET>
  description: <DESCRIPTION>
  dataStorageSizeInGBs: <DB_SIZE>
  port: <PORT>
  portX: <PORTX>

PARAMETER REFERENCE:

Parameter

Description

Type

Mandatory

spec.id

The Mysql DbSystem OCID.

string

no

spec.displayName

The user-friendly name for the Mysql DbSystem. The name does not have to be unique.

string

yes

spec.compartmentId

The OCID of the compartment of the Mysql DbSystem.

string

yes

spec.shapeName

The name of the shape. The shape determines the resources allocated. CPU cores and memory for VM shapes; CPU cores, memory and storage for non-VM (or bare metal) shapes.

string

yes

spec.subnetId

The OCID of the subnet the DB System is associated with.

string

yes

spec.dataStorageSizeInGBs

Initial size of the data volume in GBs that will be created and attached. Keep in mind that this only specifies the size of the database data volume, the log volume for the database will be scaled appropriately with its shape.

int

yes

spec.isHighlyAvailable

Specifies if the DB System is highly available.

boolean

yes

spec.availabilityDomain

The availability domain on which to deploy the Read/Write endpoint. This defines the preferred primary instance.

string

yes

spec.faultDomain

The fault domain on which to deploy the Read/Write endpoint. This defines the preferred primary instance.

string

no

spec.configuration.id

The OCID of the Configuration to be used for this DB System. More info about Configurations

string

yes

spec.description

User-provided data about the DB System.

string

no

spec.hostnameLabel

The hostname for the primary endpoint of the DB System. Used for DNS.

string

no

spec.mysqlVersion

The specific MySQL version identifier.

string

no

spec.port

The port for primary endpoint of the DB System to listen on.

int

no

spec.portX

The TCP network port on which X Plugin listens for connections. This is the X Plugin equivalent of port.

int

no

spec.ipAddress

The IP address the DB System is configured to listen on. A private IP address of your choice to assign to the primary endpoint of the DB System. Must be an available IP address within the subnet's CIDR. If you don't specify a value, Oracle automatically assigns a private IP address from the subnet. This should be a "dotted-quad" style IPv4 address.

string

no

spec.freeformTags

Free-form tags for this resource. Each tag is a simple key-value pair with no predefined name, type, or namespace. For more information, see Resource Tags. Example: {"Department": "Finance"}

string

no

spec.definedTags

Defined tags for this resource. Each key is predefined and scoped to a namespace. For more information, see Resource Tags.

string

no

spec.adminUsername.secret.secretName

The username for the administrative user.

string

yes

spec.adminPassword.secret.secretName

The Kubernetes Secret Name that contains admin password for Mysql DbSystem. The password must be between 8 and 32 characters long, and must contain at least 1 numeric character, 1 lowercase character, 1 uppercase character, and 1 special (nonalphanumeric) character.

string

yes

 

After waiting for approximately 5 minutes, my new MDS run and I can see it from OKE using the following syntax:



 

 

 My new MDS is also showing running from OCI console:

 



 

C.    Connecting to my new MDS from OKE

 

Now, I can have our microservices connected to this new MDS by deploying using these additional environment variables assigned to the pod’s container:

               - name: ADMIN_PASSWORD
           valueFrom:
             secretKeyRef:
               name: <mds-secret>
               key: password
         - name: ADMIN_USERNAME
           valueFrom:
             secretKeyRef:
               name: <mds-secret>
               key: username
         - name: MYSQLDBSYSTEM_IP
           valueFrom:
             secretKeyRef:
               name: <name-of-mysqldbsystem-resource>
               key: PrivateIPAddress
         - name: PORT
           valueFrom:
             secretKeyRef:
               name: <name-of-mysqldbsystem-resource>
               key: MySQLPort


Sample:

 


 

D.    Summary

 

OSOK gives an another level to enhance experience of using MDS for Kubernetes-based microservices application. Now, integrating MDS into a total solution of cloud native is a reality which will benefit organization for embracing a fully DBaaS platform for cloud native environment.


= AAA =