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 |
|
The Mysql DbSystem OCID. |
string |
no |
|
The user-friendly name for the Mysql DbSystem. The name does not have to be unique. |
string |
yes |
|
The OCID of the compartment of the Mysql DbSystem. |
string |
yes |
|
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 |
|
The OCID of the subnet the DB System is associated with. |
string |
yes |
|
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 |
|
Specifies if the DB System is highly available. |
boolean |
yes |
|
The availability domain on which to deploy the Read/Write endpoint. This defines the preferred primary instance. |
string |
yes |
|
The fault domain on which to deploy the Read/Write endpoint. This defines the preferred primary instance. |
string |
no |
|
The OCID of the Configuration to be used for this DB System. More info about Configurations |
string |
yes |
|
User-provided data about the DB System. |
string |
no |
|
The hostname for the primary endpoint of the DB System. Used for DNS. |
string |
no |
|
The specific MySQL version identifier. |
string |
no |
|
The port for primary endpoint of the DB System to listen on. |
int |
no |
|
The TCP network port on which X Plugin listens for connections. This is the X Plugin equivalent of port. |
int |
no |
|
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 |
|
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. |
string |
no |
|
Defined tags for this resource. Each key is predefined and scoped to a namespace. For more information, see Resource Tags. |
string |
no |
|
The username for the administrative user. |
string |
yes |
|
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 =