Friday, September 3, 2021

Provisioning Azure Database for MySQL - Single Server from AKS

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. The v2 beta version, planned for release by the end of September 2021, will offer support for Azure Database for MySQL - Flexible Server. For production environments, consider waiting to use the v2 beta release.


To address the issue of cluster resources 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.


AKS blog.png


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.


  1.  Open the Cloud Shell, and then connect to your AKS cluster by running the following command:
    az aks get-credentials --resource-group RGNAME --name CLUSTERNAME​
  2.  Add cert-manager to the cluster by running the following command:
    kubectl apply -f​
  3.  Create a Helm repository and charts for ASO by running the following command:
    helm repo add aso​
  4.  Create an Azure service principal by running the following command:
    az ad sp create-for-rbac --name "azure-service-operator" --role contributor --scopes /subscriptions/<AZURE_SUBSCRIPTION_ID>​
      "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"
  5.  Install ASO on your Kubernetes cluster by running the following command:
    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>
  6.  Verify that the ASO is operating properly by running the following command:
    kubectl get pods -n azureoperator-system​
    The results will appear as shown in the following diagram.


  7. Create a YAML file named myfile.yml by running the following command:
    code myfile.yml​
  8. In the newly created myfile.yml, insert the desired configuration for the MySQL server and databases, along with the server firewall rule to allow access to the server after deployment. Sample contents of the file myfile.yml are shown in the following diagram. The content sample of YAML file can also be accessed at this repository. Save the YAML configuration file.
    # Azure Database for MySQL deployment
    kind: MySQLServer
        name: mysqlappdbserver
        location: westeurope
        resourceGroup: resourcegroupname
        serverVersion: "5.7"
        sslEnforcement: Enabled
        createMode: Default # Could also be Replica
            name: GP_Gen5_4 
            tier: GeneralPurpose # possible values - 'Basic', 'GeneralPurpose', 'MemoryOptimized'
            family: Gen5
            size: "51200"
            capacity: 4
    kind: MySQLFirewallRule
        name: mysqlfirewallrule-azureservices
        resourceGroup: resourcegroupname
        server: mysqlappdbserver
    kind: MySQLDatabase
        name: mydatabase
        resourceGroup: resourcegroupname
        server: mysqlappdbserver
  9.  Deploy MySQL server by running the following command:
    kubectl appy -f myfile.yml​
  10.  Check the deployment status by running the following command:
    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
    name: mysqlapp
    replicas: 4
	   - name: MYSQL_USER
			name: mysqlserver-mysqlappdbserver
			key:	fullyQualifiedUsername
         - name: MYSQL_PASSWORD
			name: mysqlserver-mysqlappdbserver
			key:	password
         - name: MYSQL_SERVICE_HOST
			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.

Posted at