New to KubeDB? Please start here.

ProxySQL Declarative Configuration

What is ProxySQL Declarative Configuration

To bootstrap a native ProxySQL server with desired configuration we need to pass a configuration file named proxysql.cnf. Through the proxysql.cnf file we can pass some initial configuration for various tables and global variables with a specific format. You can check the link for a sample proxysql.cnf and its grammar here.

With kubedb proxysql we have eased this process with declarative yaml. We have scoped the CRD in a specific way so that you can provide the desired configuration in a yaml format.

How it works

User will provide the configuration under the .spec.initConfig section of the proxysql yaml. The operator parses the yaml and creates a configuration file. A secret is then created, holding that configuration file inside. Each time a new pod is created it is created with the configuration file inside that secret.

ProxySQL Declarative Configuration
Fig: ProxySQL Configuration Secret Lifecycle

At any time the user might need to change the configuration. To serve that purpose we have introduced ProxySQLOpsRequest. When an ops request is being created, the KubeDB Ops Manager updates the configuration secret and applies the changes to the proxysql cluster nodes. This is how the the configuration secret remains as a source of truth for the ProxySQL CRO and any changes are made in a declarative way.

User can exec into any proxysql pod and change any configuration from the admin panel anytime. But that won’t update the configuration secret. We recommend the ops-request to keep things declarative and keep the proxysql.cnf file always updated.

API Description

You can write the configuration in yaml format under the spec.initConfig section and the operator would do the rest. spec.initConfig section is devided into four sections : spec.initConfig.mysqlUsers , spec.initConfig.mysqlQueryRules, spec.initConfig.mysqlVariables, spec.initConfig.adminVariables. You can configure the mysql_users and mysql_query_rules tables and also the global variables under the corresponding fields. This is the api documentation. We will discuss in detail about each of the fields.

initConfig.mysqlUsers

This is an array field. Each of the array element should carry infos of users that you want to be present in the mysql_users table inside the proxysql server.

As per the official proxysql documentation, mysql_users table looks something like this. So with kubedb we have created this api to configure the table. Which basically means that you can configure everything through the yaml except the password. The password will be automatically fetched from the backend server. So you don’t need to mention this. This has been done keeping in mind the data sensitivity issue with yaml.

spec:
  ...
  initConfig:
    mysqlUsers:
    - username: wolverine
      active: 1
      default_hostgroup: 2 
      default_schema: marvel
    - username: superman
      active: 1 
      default_hostgroup: 3
    ...

initConfig.mysqlQueryRules

This is an array field. Each of the array element should carry infos of query rules that you want to set up for the proxysql server. With all these query rules you mention, operator will set up the mysql_query_rules table.

As per the official proxysql documentation, mysql_query_rules table looks something like this. With kubedb we are using an array of runtime.rawExtension for the mysqlQueryRules. You can configure all the column for a rule through this. In simple terms, just use this as a key-value yaml section.

spec:
    ...
    initConfig:
        ...
        mysqlQueryRules:
            - rule_id: 1
              active: 1
              match_pattern: "^SELECT .* FOR UPDATE$"
              destination_hostgroup: 2
              apply: 1
            - rule_id: 2
              active: 1
              match_pattern: "^SELECT"
              destination_hostgroup: 3
              apply: 1
        ...

initConfig.mysqlVariables

This is a runtime.rawExtension field. You can pass all the MySQL Variables you want to configure in a key-value format under this section. You can configure almost all the mysql variables except interfaces, monitor_username, monitor_password, ssl_p2s_cert, ssl_p2s_key, ssl_p2s_ca. We have protected the interface variable because a lot of our operator logic depends on it.

spec:
    ...
    initConfig:
        ...
        mysqlVariables:
            max_connections: 1024
            default_schema: "information_schema"    
            stacksize: 1048576
            default_schema: "information_schema"
            commands_stats: "true"
            sessions_sort: "true"
            server_version: "8.0.35"
            monitor_history: 60000
            ping_timeout_server: 200
            default_query_timeout: 36000000
            connect_timeout_server: 10000
            monitor_ping_interval: 200000
            poll_timeout: 2000
            max_connections: 2048
            default_query_delay: 0
            ping_interval_server_msec: 10000
            have_compress: "true"
            threads: 4
            monitor_connect_interval: 200000
        ...

initConfig.adminVariables

This is a runtime.rawExtension field. You can pass all the Admin Variables you want to configure in a key-value format under this section. You can configure almost all the admin variables except admin_credentials and mysql_interface . The default admin_credential is always admin:admin. If you pass any credential from the spec.authSecret our operator would add this too. And if you don’t do so, the operator will create one and add that as the cluster_admin. And as for the mysql_interface, we have protected this because our operator code logic depends on this in some case.

spec:
    ...
    initConfig:
        ...
        adminVariables:
            cluster_mysql_users_save_to_disk: "true"
            cluster_mysql_servers_save_to_disk: "true"
            cluster_proxysql_servers_diffs_before_sync: "3"
            restapi_enabled: "true"
            cluster_mysql_query_rules_diffs_before_sync: "3"
            cluster_mysql_servers_diffs_before_sync: "3"
            cluster_proxysql_servers_save_to_disk: "true"
            restapi_port: "6070"
            cluster_mysql_query_rules_save_to_disk: "true"
            cluster_check_status_frequency: "100"
            cluster_mysql_users_diffs_before_sync: "3"
            refresh_interval: "2000"
            cluster_check_interval_ms: "200"
        ...

Complete YAML

apiVersion: kubedb.com/v1
kind: ProxySQL
metadata:
  name: proxy-server
  namespace: demo
spec:
  version: "2.3.2-debian"  
  replicas: 3
  backend:
    name: mysql-server
  initConfig:
    mysqlUsers:
    - username: wolverine
      active: 1
      default_hostgroup: 2 
      default_schema: marvel
    - username: superman
      active: 1 
      default_hostgroup: 3
    mysqlQueryRules:
    - rule_id: 1
      active: 1
      match_pattern: "^SELECT .* FOR UPDATE$"
      destination_hostgroup: 2
      apply: 1
    - rule_id: 2
      active: 1
      match_pattern: "^SELECT"
      destination_hostgroup: 3
      apply: 1
    mysqlVariables:
      stacksize: 1048576
      default_schema: "information_schema"
      commands_stats: "true"
      sessions_sort: "true"
      server_version: "8.0.35"
      monitor_history: 60000
      ping_timeout_server: 200
      default_query_timeout: 36000000
      connect_timeout_server: 10000
      monitor_ping_interval: 200000
      poll_timeout: 2000
      max_connections: 2048
      default_query_delay: 0
      ping_interval_server_msec: 10000
      have_compress: "true"
      threads: 4
      monitor_connect_interval: 200000
    adminVariables:
      cluster_mysql_users_save_to_disk: "true"
      cluster_mysql_servers_save_to_disk: "true"
      cluster_proxysql_servers_diffs_before_sync: "3"
      restapi_enabled: "true"
      cluster_mysql_query_rules_diffs_before_sync: "3"
      cluster_mysql_servers_diffs_before_sync: "3"
      cluster_proxysql_servers_save_to_disk: "true"
      restapi_port: "6070"
      cluster_mysql_query_rules_save_to_disk: "true"
      cluster_check_status_frequency: "100"
      cluster_mysql_users_diffs_before_sync: "3"
      refresh_interval: "2000"
      cluster_check_interval_ms: "200"
  deletionPolicy: WipeOut