diff --git a/docs/examples/perconaxtradb/script-pxc.yaml b/docs/examples/perconaxtradb/script-pxc.yaml new file mode 100644 index 0000000000..22a3dbd221 --- /dev/null +++ b/docs/examples/perconaxtradb/script-pxc.yaml @@ -0,0 +1,21 @@ +apiVersion: kubedb.com/v1 +kind: PerconaXtraDB +metadata: + name: script-pxc + namespace: demo +spec: + version: "8.4.3" + replicas: 3 + storageType: Durable + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + init: + script: + configMap: + name: pxc-init-script + deletionPolicy: WipeOut \ No newline at end of file diff --git a/docs/examples/pgbouncer/initialization/init_script.yaml b/docs/examples/pgbouncer/initialization/init_script.yaml new file mode 100644 index 0000000000..73933f0562 --- /dev/null +++ b/docs/examples/pgbouncer/initialization/init_script.yaml @@ -0,0 +1,22 @@ +apiVersion: kubedb.com/v1 +kind: PgBouncer +metadata: + name: script-pgbouncer + namespace: demo +spec: + version: "1.24.0" + replicas: 1 + database: + syncUsers: true + databaseName: "postgres" + databaseRef: + name: "quick-postgres" + namespace: demo + connectionPool: + maxClientConnections: 20 + reservePoolSize: 5 + init: + script: + configMap: + name: pb-init-script + deletionPolicy: WipeOut \ No newline at end of file diff --git a/docs/guides/clickhouse/initialization/script_source.md b/docs/guides/clickhouse/initialization/script_source.md index 5ed93635f3..95db0dd8e5 100644 --- a/docs/guides/clickhouse/initialization/script_source.md +++ b/docs/guides/clickhouse/initialization/script_source.md @@ -47,10 +47,10 @@ Let's create a ConfigMap with the initialization script: ```bash $ kubectl create configmap -n demo ch-init-script \ ---from-literal=init.sql="$(curl -fsSL https://raw.githubusercontent.com/Bonusree/init_script/main/clickhouse_init.sql)" +--from-literal=init.sql="$(curl -fsSL https://raw.githubusercontent.com/kubedb/clickhouse-init-script/refs/heads/master/clickhouse_init.sql)" configmap/ch-init-script created ``` - +> **Note:** The initialization script above is provided only as an example. You can use your own initialization script as long as it performs the required setup for your environment. If your script connects to ClickHouse, make sure to include the appropriate ClickHouse credentials (such as the password) so the script can authenticate successfully. After deploying ClickHouse with this ConfigMap, the initialization script runs automatically, and any databases, users, tables, or other objects created by the script can be verified after the deployment completes. ## Create ClickHouse with Script Source Following YAML describes the ClickHouse object with `init.script`: @@ -214,7 +214,7 @@ Now let's connect to our ClickHouse instance to verify that the database has bee **Connection Information:** - Host name/address: you can use any of these - - Service: `script-clickhouse.demo` + - Service: `script-clickhouse` - Pod IP: (`$ kubectl get pods script-clickhouse-0 -n demo -o yaml | grep podIP`) - Port: `9000` (native TCP) or `8123` (HTTP) diff --git a/docs/guides/percona-xtradb/initialization/script_source.md b/docs/guides/percona-xtradb/initialization/script_source.md index 0be5302f46..294da82e5b 100644 --- a/docs/guides/percona-xtradb/initialization/script_source.md +++ b/docs/guides/percona-xtradb/initialization/script_source.md @@ -50,7 +50,7 @@ $ kubectl create configmap -n demo pxc-init-script \ --from-literal=init.sql="$(curl -fsSL https://raw.githubusercontent.com/kubedb/percona-xtradb-init-scripts/master/init.sql)" configmap/pxc-init-script created ``` - +>**Note:** The initialization script above is provided only as an example. You can use your own initialization script as long as it performs the required setup for your environment. If your script connects to Percona XtraDB, make sure to include the appropriate MySQL credentials (such as the password) so the script can authenticate successfully. After deploying Percona XtraDB with this ConfigMap, the initialization script runs automatically, and any databases, users, tables, or other objects created by the script can be verified after the deployment completes. ## Create PerconaXtraDB with Script Source Following YAML describes the PerconaXtraDB object with `init.script`: @@ -88,7 +88,7 @@ VolumeSource provided in `init.script` will be mounted in the Pod and will be ex Now, let's create the PerconaXtraDB CRD using the YAML shown above: ```bash -$ kubectl create -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/guides/percona-xtradb/initialization/yamls/script-pxc.yaml +$ kubectl create -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/perconaxtradb/script-pxc.yaml perconaxtradb.kubedb.com/script-pxc created ``` @@ -269,7 +269,7 @@ Now let's connect to our PerconaXtraDB cluster to verify that the database has b **Connection Information:** - Host name/address: you can use any of these - - Service: `script-pxc.demo` + - Service: `script-pxc` - Pod IP: (`$ kubectl get pods script-pxc-0 -n demo -o yaml | grep podIP`) - Port: `3306` @@ -284,7 +284,7 @@ Now let's connect to our PerconaXtraDB cluster to verify that the database has b ```bash $ kubectl get secret -n demo script-pxc-auth -o jsonpath='{.data.password}' | base64 -d - nsTqGdVwR!~DA(t + nsTqGdVwR!~DA(ta ``` Now, connect to the PerconaXtraDB cluster and run the following query to confirm initialization: @@ -340,6 +340,20 @@ mysql: [Warning] Using a password on the command line interface can be insecure. | wsrep_streaming_log | +------------------------------------------------------+ + +$ kubectl exec -it -n demo script-pxc-0 -- \ + mysql -u root --password='nsTqGdVwR!~DA(ta' \ + -e "SELECT * FROM mysql.kubedb_table;" +Defaulted container "perconaxtradb" out of: perconaxtradb, px-coordinator, px-init (init) +mysql: [Warning] Using a password on the command line interface can be insecure. ++----+-------+ +| id | name | ++----+-------+ +| 1 | name1 | +| 2 | name2 | +| 3 | name3 | ++----+-------+ + ``` We can see the TABLE `kubedb_table` in `mysql` database which was created through initialization. diff --git a/docs/guides/pgbouncer/initialization/script_source.md b/docs/guides/pgbouncer/initialization/script_source.md index d47c0c16fc..6ee72a5527 100644 --- a/docs/guides/pgbouncer/initialization/script_source.md +++ b/docs/guides/pgbouncer/initialization/script_source.md @@ -165,5 +165,4 @@ $ kubectl delete ns demo ## Next Steps -- Learn about [backup and restore](/docs/guides/pgbouncer/backup/overview/index.md) PgBouncer using Stash. - Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). diff --git a/docs/guides/proxysql/initialization/examples/proxyops-add-users.yaml b/docs/guides/proxysql/initialization/examples/proxyops-add-users.yaml new file mode 100644 index 0000000000..a083c71305 --- /dev/null +++ b/docs/guides/proxysql/initialization/examples/proxyops-add-users.yaml @@ -0,0 +1,19 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: ProxySQLOpsRequest +metadata: + name: add-user + namespace: demo +spec: + type: Reconfigure + proxyRef: + name: proxy-init-inline + configuration: + mysqlUsers: + users: + - username: wolverine + active: 1 + default_hostgroup: 2 + - username: superman + active: 1 + default_hostgroup: 2 + reqType: add diff --git a/docs/guides/proxysql/initialization/examples/proxysql-init-inline.yaml b/docs/guides/proxysql/initialization/examples/proxysql-init-inline.yaml index ef3f118e6a..a5e5885c82 100644 --- a/docs/guides/proxysql/initialization/examples/proxysql-init-inline.yaml +++ b/docs/guides/proxysql/initialization/examples/proxysql-init-inline.yaml @@ -11,14 +11,6 @@ spec: configuration: init: inline: - mysqlUsers: - - username: wolverine - active: 1 - default_hostgroup: 2 - default_schema: marvel - - username: superman - active: 1 - default_hostgroup: 3 mysqlQueryRules: - rule_id: 1 active: 1 diff --git a/docs/guides/proxysql/initialization/script_source.md b/docs/guides/proxysql/initialization/script_source.md index 63675c85ad..2a80baa300 100644 --- a/docs/guides/proxysql/initialization/script_source.md +++ b/docs/guides/proxysql/initialization/script_source.md @@ -14,37 +14,37 @@ section_menu_id: guides # Initialize ProxySQL with Custom Configuration -ProxySQL needs a bootstrap configuration file, `proxysql.cnf`, to set up its `mysql_users`, `mysql_query_rules`, `mysql_variables` and `admin_variables` tables at the very first startup. KubeDB lets you provide this bootstrap configuration in two ways under `spec.configuration.init`: +ProxySQL reads a bootstrap configuration file, `proxysql.cnf`, on first start to populate its in-memory configuration tables — `mysql_users`, `mysql_query_rules`, `mysql_variables`, and `admin_variables`. KubeDB lets you supply this bootstrap configuration through `spec.configuration.init`, in one of two ways: -- **`spec.configuration.init.secretName`** - point to a Secret holding the raw `proxysql.cnf` snippets. The values are patched into the config file verbatim, so you are responsible for the exact ProxySQL config syntax (and for supplying user passwords yourself). -- **`spec.configuration.init.inline`** - describe the same four sections in structured YAML. The operator renders this into `proxysql.cnf` for you, and for `mysqlUsers`, it automatically fetches the password from the backend server instead of asking you to write it in plaintext. +- **`spec.configuration.init.secretName`** — reference a Secret that holds raw `proxysql.cnf` fragments. The values are written into the generated configuration verbatim, so you own the exact ProxySQL syntax and must supply user passwords yourself. +- **`spec.configuration.init.inline`** — describe the same sections as structured YAML. The operator renders them into `proxysql.cnf` for you and, for `mysqlUsers`, automatically retrieves each user's password from the backend server so you never store it in plaintext. -If both are set, `init.inline` always takes precedence over `init.secretName`. This tutorial will show you how to use both. +If both are set, `init.inline` takes precedence over `init.secretName`. This guide demonstrates both approaches and then shows how to add users after initialization with a `ProxySQLOpsRequest`. -> Note: `spec.initConfig` and `spec.configSecret` are older, deprecated equivalents of `spec.configuration.init.inline` and `spec.configuration.init.secretName` respectively. Use the `spec.configuration.init` fields for any new ProxySQL object. +> Note: `spec.initConfig` and `spec.configSecret` are the deprecated equivalents of `init.inline` and `init.secretName` respectively. Use `spec.configuration.init` for all new ProxySQL objects. ## Before You Begin -At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). +You will need a Kubernetes cluster and the `kubectl` command-line tool configured to communicate with it. If you do not already have a cluster, you can create one with [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). -Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/README.md). +Install the KubeDB CLI on your workstation and the KubeDB operator in your cluster by following the [setup instructions](/docs/setup/README.md). -To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. +This guide uses a dedicated namespace called `demo` to keep the resources isolated. ```bash -$ kubectl create ns demo +$ kubectl create namespace demo namespace/demo created -$ kubectl get ns demo -NAME STATUS AGE -demo Active 5s +$ kubectl get namespace demo +NAME STATUS AGE +demo Active 5s ``` -> Note: YAML files used in this tutorial are stored in [docs/guides/proxysql/initialization/examples](https://github.com/kubedb/docs/tree/{{< param "info.version" >}}/docs/guides/proxysql/initialization/examples) folder in GitHub repository [kubedb/docs](https://github.com/kubedb/docs). +> Note: The YAML files used in this guide are stored under [docs/guides/proxysql/initialization/examples](https://github.com/kubedb/docs/tree/{{< param "info.version" >}}/docs/guides/proxysql/initialization/examples) in the [kubedb/docs](https://github.com/kubedb/docs) repository. ## Prepare MySQL Backend -ProxySQL acts as a proxy in front of MySQL servers. Before deploying ProxySQL, you need a running MySQL Group Replication backend. Apply the following YAML to create one: +ProxySQL sits in front of one or more MySQL servers. Before deploying ProxySQL, create a MySQL backend running in Group Replication mode: ```yaml apiVersion: kubedb.com/v1 @@ -73,7 +73,7 @@ $ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" > mysql.kubedb.com/mysql-server created ``` -Wait for the MySQL cluster to be `Ready`: +Wait for the MySQL cluster to become `Ready`: ```bash $ kubectl get mysql -n demo mysql-server @@ -81,9 +81,22 @@ NAME VERSION STATUS AGE mysql-server 8.4.8 Ready 5m ``` -## Option 1: Bootstrap using a raw configuration Secret +## Option 1: Bootstrap from a raw configuration Secret -`spec.configuration.init.secretName` refers to a Secret with up to four keys - `MySQLUsers.cnf`, `MySQLQueryRules.cnf`, `MySQLVariables.cnf` and `AdminVariables.cnf`. Each key's value must already be in valid `proxysql.cnf` syntax; the operator copies it into the config file exactly as-is. +`spec.configuration.init.secretName` points to a Secret that may contain up to four optional keys: `MySQLUsers.cnf`, `MySQLQueryRules.cnf`, `MySQLVariables.cnf`, and `AdminVariables.cnf`. Each key must hold valid **ProxySQL (`proxysql.cnf`) syntax**. During initialization, KubeDB mounts the Secret into the ProxySQL pod and copies each fragment verbatim into the generated `proxysql.cnf` — it does not validate, translate, or merge them. ProxySQL then loads the file at startup and applies it to its in-memory configuration database. + +Because the fragments are applied as-is, review the syntax carefully before applying it. + +The supported Secret keys are: + +| Key | ProxySQL table | +| --------------------- | ---------------------------------- | +| `MySQLUsers.cnf` | Frontend users (`mysql_users`) | +| `MySQLQueryRules.cnf` | Query routing rules (`mysql_query_rules`) | +| `MySQLVariables.cnf` | MySQL module variables (`mysql_variables`) | +| `AdminVariables.cnf` | Admin module variables (`admin_variables`) | + +The following Secret defines frontend users, query rules, MySQL variables, and admin variables: ```yaml apiVersion: v1 @@ -142,7 +155,11 @@ stringData: restapi_enabled="true" restapi_port="6090" } ---- +``` + +Deploy a ProxySQL instance that consumes the Secret: + +```yaml apiVersion: kubedb.com/v1 kind: ProxySQL metadata: @@ -159,10 +176,11 @@ spec: deletionPolicy: WipeOut ``` -Here, +Here: -- `configuration.init.secretName` points to the `proxysql-init-raw` Secret above. Since `MySQLUsers.cnf` sets each user's `password` explicitly, this path does **not** auto-fetch credentials from the backend the way `init.inline` does. -- Unlike `init.inline`, values under `init.secretName` are not merged with anything - only what you put in the Secret (plus KubeDB's internal defaults for things like cluster auth and TLS) ends up in `proxysql.cnf`, so double-check the syntax before applying. +- `configuration.init.secretName` references the `proxysql-init-raw` Secret that holds the raw configuration fragments. +- Because `MySQLUsers.cnf` supplies each user's `password` explicitly, KubeDB does **not** fetch credentials from the backend — unlike `init.inline`. +- Each fragment is copied directly into the generated `proxysql.cnf` and loaded by ProxySQL at startup. The resulting users, query rules, and variables are then visible through the ProxySQL admin interface. Apply the Secret and the ProxySQL object: @@ -172,7 +190,7 @@ secret/proxysql-init-raw created proxysql.kubedb.com/proxy-init-secret created ``` -Wait until ProxySQL goes into the `Ready` state: +Wait until ProxySQL reaches the `Ready` state: ```bash $ kubectl get proxysql -n demo proxy-init-secret @@ -182,54 +200,58 @@ proxy-init-secret 3.0.1-debian Ready 2m ### Verify -Get the admin credentials and connect to the ProxySQL admin interface (port `6032`): +KubeDB stores the ProxySQL cluster-admin credentials in the `{ProxySQL-name}-auth` Secret (the username defaults to `cluster`, and the password is auto-generated). Read them and connect to the admin interface on port `6032`: ```bash -$ kubectl get secret -n demo proxy-init-secret-auth -o jsonpath='{.data.username}' | base64 -d -cluster - -$ kubectl get secret -n demo proxy-init-secret-auth -o jsonpath='{.data.password}' | base64 -d -S3cur3P@ssw0rd +$ ADMIN_USER=$(kubectl get secret -n demo proxy-init-secret-auth -o jsonpath='{.data.username}' | base64 -d) +$ ADMIN_PASS=$(kubectl get secret -n demo proxy-init-secret-auth -o jsonpath='{.data.password}' | base64 -d) +$ kubectl exec -it -n demo proxy-init-secret-0 -- mysql -u"$ADMIN_USER" -p"$ADMIN_PASS" -h 127.0.0.1 -P 6032 +Welcome to the MariaDB monitor. Commands end with ; or \g. +Your MySQL connection id is 110 +Server version: 8.0.27 (ProxySQL Admin Module) + +Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. + +Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. + +MySQL [(none)]> SELECT variable_name, variable_value + -> FROM global_variables + -> WHERE variable_name IN + -> ('mysql-max_connections', 'mysql-threads', 'mysql-default_query_timeout'); ++-----------------------------+----------------+ +| variable_name | variable_value | ++-----------------------------+----------------+ +| mysql-default_query_timeout | 1234567 | +| mysql-max_connections | 4096 | +| mysql-threads | 8 | ++-----------------------------+----------------+ +3 rows in set (0.00 sec) + +MySQL [(none)]> SELECT username, active, default_hostgroup, default_schema + -> FROM mysql_users; ++-----------+--------+-------------------+----------------+ +| username | active | default_hostgroup | default_schema | ++-----------+--------+-------------------+----------------+ +| wolverine | 1 | 2 | secret_schema | +| superman | 1 | 3 | NULL | ++-----------+--------+-------------------+----------------+ +2 rows in set (0.00 sec) ``` -```bash -$ kubectl exec -it -n demo proxy-init-secret-0 -- mysql -u cluster -pS3cur3P@ssw0rd -h 127.0.0.1 -P 6032 \ - -e "SELECT username, active, default_hostgroup, default_schema FROM mysql_users;" -+-----------+--------+-------------------+------------------+ -| username | active | default_hostgroup | default_schema | -+-----------+--------+-------------------+------------------+ -| wolverine | 1 | 2 | secret_schema | -| superman | 1 | 3 | | -+-----------+--------+-------------------+------------------+ - -$ kubectl exec -it -n demo proxy-init-secret-0 -- mysql -u cluster -pS3cur3P@ssw0rd -h 127.0.0.1 -P 6032 \ - -e "SELECT rule_id, match_pattern, destination_hostgroup FROM mysql_query_rules;" -+---------+---------------+------------------------+ -| rule_id | match_pattern | destination_hostgroup | -+---------+---------------+------------------------+ -| 100 | ^INSERT | 2 | -| 101 | ^SELECT | 3 | -+---------+---------------+------------------------+ - -$ kubectl exec -it -n demo proxy-init-secret-0 -- mysql -u cluster -pS3cur3P@ssw0rd -h 127.0.0.1 -P 6032 \ - -e "SELECT variable_name, variable_value FROM global_variables WHERE variable_name IN ('mysql-max_connections','mysql-threads','mysql-default_query_timeout','admin-restapi_enabled','admin-restapi_port','admin-refresh_interval');" -+------------------------------+----------------+ -| variable_name | variable_value | -+------------------------------+----------------+ -| mysql-max_connections | 4096 | -| mysql-threads | 8 | -| mysql-default_query_timeout | 1234567 | -| admin-restapi_enabled | true | -| admin-restapi_port | 6090 | -| admin-refresh_interval | 3500 | -+------------------------------+----------------+ -``` +The global variables from `MySQLVariables.cnf` and the frontend users from `MySQLUsers.cnf` are reflected exactly as written in the `proxysql-init-raw` Secret. -The `mysql_users`, `mysql_query_rules` and the global variables all reflect exactly what was written in the `proxysql-init-raw` Secret. +## Option 2: Bootstrap from inline structured configuration -## Option 2: Bootstrap using inline structured configuration +`spec.configuration.init.inline` lets you initialize ProxySQL with structured Kubernetes YAML instead of raw `proxysql.cnf` syntax. At initialization, KubeDB translates the inline YAML into the corresponding ProxySQL configuration, merges it with the operator-managed defaults (monitor credentials, cluster authentication, and other required internal settings), and generates the final `proxysql.cnf`. ProxySQL loads this file at startup into its in-memory configuration database. -`spec.configuration.init.inline` describes the same four sections (`mysqlUsers`, `mysqlQueryRules`, `mysqlVariables`, `adminVariables`) in structured YAML instead of raw config syntax. The operator renders these into `proxysql.cnf`, merging them with KubeDB's own defaults (like monitor and cluster-auth variables). +The inline configuration supports the same four sections: + +- **`mysqlUsers`** — frontend users (`mysql_users`). Passwords are fetched automatically from the backend server. +- **`mysqlQueryRules`** — query routing rules (`mysql_query_rules`). +- **`mysqlVariables`** — MySQL module variables (`mysql_variables`). +- **`adminVariables`** — admin module variables (`admin_variables`). + +The example below configures query rules, MySQL variables, and admin variables. Users are intentionally omitted here so that the `mysql_users` table starts empty; the [Reconfigure mysql_users](#reconfigure-mysql_users) section that follows adds users to this same instance with a `ProxySQLOpsRequest`, demonstrating how KubeDB retrieves passwords from the backend. ```yaml apiVersion: kubedb.com/v1 @@ -245,14 +267,6 @@ spec: configuration: init: inline: - mysqlUsers: - - username: wolverine - active: 1 - default_hostgroup: 2 - default_schema: marvel - - username: superman - active: 1 - default_hostgroup: 3 mysqlQueryRules: - rule_id: 1 active: 1 @@ -278,21 +292,20 @@ spec: deletionPolicy: WipeOut ``` -Here, +Here: -- `configuration.init.inline.mysqlUsers` does not take a `password` field - KubeDB fetches each user's password from the backend MySQL server automatically, so no credential is ever written in plaintext YAML. -- `configuration.init.inline.mysqlQueryRules`, `.mysqlVariables` and `.adminVariables` accept the same keys as their raw `proxysql.cnf` counterparts, just in YAML key-value form. +- `configuration.init.inline` provides a Kubernetes-native way to configure ProxySQL without writing raw `proxysql.cnf` syntax. +- `mysqlQueryRules`, `mysqlVariables`, and `adminVariables` are expressed as structured YAML, which is easier to read, diff, and maintain. +- At initialization, KubeDB renders these sections into `proxysql.cnf`, merges them with its own defaults, and lets ProxySQL load the result at startup. -See the [Declarative Configuration](/docs/guides/proxysql/concepts/declarative-configuration/index.md) concept page for the full field-by-field reference. - -Apply the YAML: +Apply the configuration: ```bash $ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/guides/proxysql/initialization/examples/proxysql-init-inline.yaml proxysql.kubedb.com/proxy-init-inline created ``` -Wait until ProxySQL goes into the `Ready` state: +Wait until ProxySQL reaches the `Ready` state: ```bash $ kubectl get proxysql -n demo proxy-init-inline @@ -302,63 +315,193 @@ proxy-init-inline 3.0.1-debian Ready 2m ### Verify +Connect to the admin interface and confirm that the query rules and global variables were applied: + +```bash +$ ADMIN_USER=$(kubectl get secret -n demo proxy-init-inline-auth -o jsonpath='{.data.username}' | base64 -d) +$ ADMIN_PASS=$(kubectl get secret -n demo proxy-init-inline-auth -o jsonpath='{.data.password}' | base64 -d) +$ kubectl exec -it -n demo proxy-init-inline-0 -- mysql -u"$ADMIN_USER" -p"$ADMIN_PASS" -h 127.0.0.1 -P 6032 +Welcome to the MariaDB monitor. Commands end with ; or \g. +Your MySQL connection id is 61 +Server version: 8.4.8 (ProxySQL Admin Module) + +Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. + +Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. + +MySQL [(none)]> SELECT rule_id, active, match_pattern, destination_hostgroup, apply + -> FROM mysql_query_rules + -> ORDER BY rule_id; ++---------+--------+------------------------+-----------------------+-------+ +| rule_id | active | match_pattern | destination_hostgroup | apply | ++---------+--------+------------------------+-----------------------+-------+ +| 1 | 1 | ^SELECT .* FOR UPDATE$ | 2 | 1 | +| 2 | 1 | ^SELECT | 3 | 1 | ++---------+--------+------------------------+-----------------------+-------+ +2 rows in set (0.00 sec) + +MySQL [(none)]> SELECT variable_name, variable_value + -> FROM global_variables + -> WHERE variable_name IN + -> ('mysql-max_connections', 'mysql-connect_timeout_server', + -> 'mysql-threads', 'mysql-server_version', 'mysql-default_query_timeout'); ++------------------------------+----------------+ +| variable_name | variable_value | ++------------------------------+----------------+ +| mysql-connect_timeout_server | 10000 | +| mysql-default_query_timeout | 36000000 | +| mysql-max_connections | 2048 | +| mysql-server_version | 8.4.8 | +| mysql-threads | 4 | ++------------------------------+----------------+ +5 rows in set (0.00 sec) +``` + +The query rules and global variables match the values defined under `mysqlQueryRules`, `mysqlVariables`, and `adminVariables`, confirming that KubeDB rendered them into the generated configuration and ProxySQL loaded them at startup. The `mysql_users` table is empty, since no users were configured inline. + +## Reconfigure mysql_users + +After initialization, you can manage the `mysql_users` table with a `ProxySQLOpsRequest` — adding, updating, or removing users without re-deploying ProxySQL. As with `init.inline`, you do **not** supply passwords: KubeDB fetches each user's password from the backend MySQL server, so every user you reference must already exist there. + +To reconfigure `mysql_users`, set `.spec.type` to `Reconfigure`, point `.spec.proxyRef.name` at your ProxySQL instance, list the users under `.spec.configuration.mysqlUsers.users`, and set `.spec.configuration.mysqlUsers.reqType` to `add`, `update`, or `delete`. + +### Create the users in the MySQL backend + +First, create the users in the backend MySQL server. The example below creates `wolverine` and `superman`: + ```bash -$ kubectl get secret -n demo proxy-init-inline-auth -o jsonpath='{.data.username}' | base64 -d -cluster +$ kubectl exec -it -n demo mysql-server-0 -- bash +Defaulted container "mysql" out of: mysql, mysql-coordinator, mysql-init (init) +root@mysql-server-0:/# mysql -uroot -p$MYSQL_ROOT_PASSWORD +Welcome to the MySQL monitor. Commands end with ; or \g. +Your MySQL connection id is 50594 +Server version: 8.4.3 MySQL Community Server - GPL + +Copyright (c) 2000, 2024, Oracle and/or its affiliates. -$ kubectl get secret -n demo proxy-init-inline-auth -o jsonpath='{.data.password}' | base64 -d -S3cur3P@ssw0rd +Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. + +mysql> CREATE USER 'wolverine'@'%' IDENTIFIED BY 'wolverine-pass'; +Query OK, 0 rows affected (0.01 sec) + +mysql> CREATE USER 'superman'@'%' IDENTIFIED BY 'superman-pass'; +Query OK, 0 rows affected (0.01 sec) ``` +### Inspect the current mysql_users table + +Confirm that the `mysql_users` table is empty on `proxy-init-inline`. This requires that `spec.syncUsers` was **not** enabled on the ProxySQL object — otherwise ProxySQL would automatically import every backend user and the table would not be empty. + ```bash -$ kubectl exec -it -n demo proxy-init-inline-0 -- mysql -u cluster -pS3cur3P@ssw0rd -h 127.0.0.1 -P 6032 \ - -e "SELECT username, active, default_hostgroup, default_schema FROM mysql_users;" -+-----------+--------+-------------------+------------------+ -| username | active | default_hostgroup | default_schema | -+-----------+--------+-------------------+------------------+ -| wolverine | 1 | 2 | marvel | -| superman | 1 | 3 | | -+-----------+--------+-------------------+------------------+ - -$ kubectl exec -it -n demo proxy-init-inline-0 -- mysql -u cluster -pS3cur3P@ssw0rd -h 127.0.0.1 -P 6032 \ - -e "SELECT rule_id, match_pattern, destination_hostgroup FROM mysql_query_rules;" -+---------+----------------------------+------------------------+ -| rule_id | match_pattern | destination_hostgroup | -+---------+----------------------------+------------------------+ -| 1 | ^SELECT .* FOR UPDATE$ | 2 | -| 2 | ^SELECT | 3 | -+---------+----------------------------+------------------------+ - -$ kubectl exec -it -n demo proxy-init-inline-0 -- mysql -u cluster -pS3cur3P@ssw0rd -h 127.0.0.1 -P 6032 \ - -e "SELECT variable_name, variable_value FROM global_variables WHERE variable_name IN ('mysql-max_connections','mysql-threads','admin-restapi_enabled','admin-restapi_port');" -+------------------------+----------------+ -| variable_name | variable_value | -+------------------------+----------------+ -| mysql-max_connections | 2048 | -| mysql-threads | 4 | -| admin-restapi_enabled | true | -| admin-restapi_port | 6070 | -+------------------------+----------------+ +$ kubectl exec -it -n demo proxy-init-inline-0 -- mysql -u"$ADMIN_USER" -p"$ADMIN_PASS" -h 127.0.0.1 -P 6032 +... +MySQL [(none)]> SELECT username FROM mysql_users; +Empty set (0.00 sec) ``` -Since `wolverine` and `superman` also exist on the MySQL backend, ProxySQL was able to log in and fetch their passwords automatically - you can verify a client can actually connect through ProxySQL using those credentials without ever having put a password in the YAML. +### Add users -## Cleaning up +Submit an ops request to add `wolverine` and `superman`. Because no password is supplied, KubeDB retrieves it from the backend — if a user does not exist there, the request fails. + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: ProxySQLOpsRequest +metadata: + name: add-user + namespace: demo +spec: + type: Reconfigure + proxyRef: + name: proxy-init-inline + configuration: + mysqlUsers: + users: + - username: wolverine + active: 1 + default_hostgroup: 2 + - username: superman + active: 1 + default_hostgroup: 2 + reqType: add +``` -To cleanup the Kubernetes resources created by this tutorial, run: +Apply it: ```bash -$ kubectl patch -n demo proxysql/proxy-init-secret -p '{"spec":{"deletionPolicy":"WipeOut"}}' --type="merge" -$ kubectl delete -n demo proxysql/proxy-init-secret +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/guides/proxysql/initialization/examples/proxyops-add-users.yaml +proxysqlopsrequest.ops.kubedb.com/add-user created +``` + +Wait for the ops request to succeed: + +```bash +$ kubectl get proxysqlopsrequest -n demo add-user +NAME TYPE STATUS AGE +add-user Reconfigure Successful 20s +``` + +### Verify + +Back in the admin interface, the two users now appear with the passwords KubeDB fetched from the backend (stored as hashes), the `active` flag, and the `default_hostgroup` from the ops request: -$ kubectl patch -n demo proxysql/proxy-init-inline -p '{"spec":{"deletionPolicy":"WipeOut"}}' --type="merge" -$ kubectl delete -n demo proxysql/proxy-init-inline +```bash +kubectl exec -it -n demo proxy-init-inline-0 -- bash +proxysql@proxy-init-inline-0:/$ mysql -uadmin -padmin -h127.0.0.1 -P6032 --prompt "ProxySQLAdmin > " +Welcome to the MariaDB monitor. Commands end with ; or \g. +Your MySQL connection id is 90 +Server version: 8.4.8 (ProxySQL Admin Module) + +Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. + +Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. + +ProxySQLAdmin > select * from mysql_users; ++-----------+------------------------------------------------------------------------------------------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+------------+---------+ +| username | password | active | use_ssl | default_hostgroup | default_schema | schema_locked | transaction_persistent | fast_forward | backend | frontend | max_connections | attributes | comment | ++-----------+------------------------------------------------------------------------------------------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+------------+---------+ +| wolverine | $A$005$7GF&7o.%\x10;.%jP5Ui??\\KmKM45B50Xt3wzJ2fmWo9FHAi2Yt7mhhCa8wlZpHZ/1 | 1 | 0 | 2 | NULL | 0 | 1 | 0 | 1 | 1 | 10000 | | | +| superman | $A$005$\t!MR\x18p{\x12\x06TE\x1e\t\\,\x1bI8\x15\x1bcxpfFLuOBmbfiLF9rs8MTeYQ3yJVQghmaM4/evor/XC | 1 | 0 | 2 | NULL | 0 | 1 | 0 | 1 | 1 | 10000 | | | ++-----------+------------------------------------------------------------------------------------------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+------------+---------+ +2 rows in set (0.001 sec) + +ProxySQLAdmin > SELECT rule_id, match_pattern, destination_hostgroup FROM mysql_query_rules; ++---------+------------------------+-----------------------+ +| rule_id | match_pattern | destination_hostgroup | ++---------+------------------------+-----------------------+ +| 1 | ^SELECT .* FOR UPDATE$ | 2 | +| 2 | ^SELECT | 3 | ++---------+------------------------+-----------------------+ +2 rows in set (0.002 sec) + +ProxySQLAdmin > SELECT variable_name, variable_value FROM global_variables WHERE variable_name IN ('mysql-max_connections','mysql-threads','admin-restapi_enabled','admin-restapi_port'); ++-----------------------+----------------+ +| variable_name | variable_value | ++-----------------------+----------------+ +| admin-restapi_enabled | true | +| admin-restapi_port | 6070 | +| mysql-max_connections | 2048 | +| mysql-threads | 4 | ++-----------------------+----------------+ +4 rows in set (0.002 sec) + +ProxySQLAdmin > exit +Bye + + +``` -$ kubectl patch -n demo mysql/mysql-server -p '{"spec":{"deletionPolicy":"WipeOut"}}' --type="merge" -$ kubectl delete -n demo mysql/mysql-server +> To change a user's attributes later, submit another ops request with `reqType: update` (`username` is the key). To remove a user, use `reqType: delete` and list only the username. The [Reconfigure ProxySQL](/docs/guides/proxysql/reconfigure/cluster/index.md) guide covers the full set of operations, including query rules and global variables. -$ kubectl delete -n demo secret/proxysql-init-raw -$ kubectl delete ns demo +## Cleaning up + +To remove the resources created in this guide, run: + +```bash +$ kubectl delete -n demo proxysqlopsrequest --all +$ kubectl delete -n demo proxysql proxy-init-secret proxy-init-inline +$ kubectl delete -n demo mysql mysql-server +$ kubectl delete -n demo secret proxysql-init-raw +$ kubectl delete namespace demo ``` ## Next Steps