To gain the benefits of using a MySQL database in a Kubernetes application, a common strategy is to provision the database in a container running in a pod. In doing so, the database will use the cluster resources. Accessing the database from other pods in the same AKS cluster running client apps is possible via Kubernetes networking. However, if for some reason cluster resources become unavailable, both the application and the database will be unavailable, as both rely on cluster health.
Important: Provisioning from Azure Kubernetes Service (AKS) using Azure Service Operator (ASO) is currently tested with the v1 alpha version, which only supports Azure Database for MySQL - Single Server. For information about provisioning Azure Database for MySQL - Flexible Server, see the blog post Using Azure Service Operator to provision Azure DB for MySQL- Flexible Server from within Kubernetes.
To address the issue of cluster resources being shared between the application and database, you can substitute the local database in AKS with Azure Database for MySQL, which separates the database from the AKS cluster. Thus, cluster resources will remain focused on delivering infrastructure required to run the app and database availability will not be impacted by AKS availability. By making this change, the architecture will be updated as shown in the following diagram.
You can provision Azure Database for MySQL programmatically using Terraform, or you can integrate it with the Kubernetes services. This post provides the steps for provisioning from Kubernetes using ASO, which allows dynamic deployment of Azure services directly from AKS. This makes the resources accessible from pods within the AKS cluster.
ASO runs as a collection of pods (controller and manager pods) in your AKS cluster and requires a certificate and a Service Principal (SP) to create resources in the subscription. In the following steps, you'll use Helm to add ASO. Helm is an open-source packaging tool that helps you install and manage the lifecycle of Kubernetes applications. Similar to Linux package managers like APT and Yum, Helm manages Kubernetes charts, which are packages of pre-configured Kubernetes resources.
Deployment of Azure MySQL Database is performed via a YAML file that serves as the basis for Kubernetes deployment and configuration of the pods. In the YAML file, the description of the service is provided, and the service deployment is performed via kubectl. kubectl is the Kubernetes command-line client, used to manage a Kubernetes cluster and is already installed if you use Azure Cloud Shell.
To provision, perform the following steps.
az aks get-credentials --resource-group RGNAME --name CLUSTERNAME
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.5.3/cert-manager.yaml
helm repo add aso https://raw.githubusercontent.com/Azure/azure-service-operator/master/charts
az ad sp create-for-rbac --name "azure-service-operator" --role contributor --scopes /subscriptions/<AZURE_SUBSCRIPTION_ID>
Output:{
"appId": "2c0e1d61-1ac7-4710-9f60-d4844c47dd21",
"displayName": "azure-service-operator",
"name": "2c0e1d61-1ac7-4710-9f60-d4844c47dd21",
"password": "iBW-RKtsq.ScrVdUp2_4SSKgI0P_eMFbh-",
"tenant": "72f988bf-86f1-41af-91ab-2d7cd011db47"
}
helm upgrade --install aso aso/azure-service-operator \
--create-namespace \
--namespace=azureoperator-system \
--set azureSubscriptionID=<AZURE_SUBSCRIPTION_ID> \
--set azureTenantID=<TENANT> \
--set azureClientID=<APPID> \
--set azureClientSecret=<PASSWORD>
kubectl get pods -n azureoperator-system
The results will appear as shown in the following diagram.
code myfile.yml
# Azure Database for MySQL deployment
apiVersion: azure.microsoft.com/v1alpha2
kind: MySQLServer
metadata:
name: mysqlappdbserver
labels: # Provide tags to add to the KeyVault as labels
tag1: value1
tag2: value2
spec:
location: eastus
resourceGroup: MyResourceGroup
serverVersion: "5.7" # could also be 8.0
sslEnforcement: Enabled
createMode: Default # Possible values include: Default, Replica, PointInTimeRestore (not implemented), GeoRestore (not implemented)
# Optional admin secret name. If the admin secret is specified the `username` and `password` fields of the secret will be used to set
# the administrator username and password. If adminSecret is not provided, ASO will generate an administrator account
# and password.
# adminSecret: my-admin-secret
sku:
name: GP_Gen5_4
tier: GeneralPurpose # possible values - 'Basic', 'GeneralPurpose', 'MemoryOptimized'
family: Gen5
size: "51200"
capacity: 4
# Optional Backup Retention Config
# storageProfile:
# backupRetentionDays: 10
# geoRedundantBackup: Enabled # Disabled or Enabled
# storageMB: 5120 # max storage - minimum of 5120 MB and additional increments of 1024 MB up to maximum of 16777216 MB
# storageAutogrow: Enabled # Disabled or Enabled
---
apiVersion: azure.microsoft.com/v1alpha1
kind: MySQLFirewallRule
metadata:
name: mysqlfirewallrule-azureservices
spec:
resourceGroup: MyResourceGroup
server: mysqlappdbserver
startIpAddress: 0.0.0.0
endIpAddress: 0.0.0.0
---
apiVersion: azure.microsoft.com/v1alpha1
kind: MySQLDatabase
metadata:
name: mydatabasename
spec:
resourceGroup: MyResourceGroup
server: mysqlappdbserver
kubectl appy -f myfile.yml
kubectl get MySqlServer
The results will appear as shown in the following diagram.
The server is now accessible via the Azure portal as well.
Note: You can explicitly provide the username and password in the YAML config file, or you can use them as environmental variables to connect your application to the server. The server name, username, and password are stored as keys in the secret generated by Kubernetes. To view the encoded keys run the following command:
kubectl describe secrets mysqlserver-mysqlappdbserver
A similar output will appear:
You can reference the secret inside the YAML file for a pod that configures an app that needs to connect to the service in a deployment. The following example retrieves the values of the fullyQualifiedServerName, fullyQualifiedUsername, and password keys, and makes them available as environment variables inside a pod.
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysqlapp
spec:
replicas: 4
selector:
…
template:
…
spec:
…
containers:
…
env:
- name: MYSQL_USER
valueFrom:
secretKeyRef:
name: mysqlserver-mysqlappdbserver
key: fullyQualifiedUsername
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: mysqlserver-mysqlappdbserver
key: password
- name: MYSQL_SERVICE_HOST
valueFrom:
secretKeyRef:
name: mysqlserver-mysqlappdbserver
key: fullyQualifiedServerName
- name: MYSQL_SERVICE_PORT
value: '3306'
The application will retrieve environmental variables above and use them to construct a connector to the database server. The advantage of this approach is that connection credentials are not exposed to the app, reducing the chances of accidental disclosure.
Supportability note: This approach is also supported for Azure Database for PostgreSQL, Azure SQL Database, and Azure Cosmos DB. For more details and YAML code examples, please check the following repository. A list of ASO supported resources can be found here.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.