From a758e8c0d56051f574625ef3f784721dfcee0c67 Mon Sep 17 00:00:00 2001 From: Nikolai Rodionov Date: Tue, 17 Feb 2026 14:53:41 +0100 Subject: [PATCH] Add docs about databases Signed-off-by: Nikolai Rodionov --- docs/database.md | 245 ++++++++++++++++++++++++- docs/{dbinstances.md => dbinstance.md} | 0 docs/index.md | 2 +- 3 files changed, 245 insertions(+), 2 deletions(-) rename docs/{dbinstances.md => dbinstance.md} (100%) diff --git a/docs/database.md b/docs/database.md index f96455c..578c948 100644 --- a/docs/database.md +++ b/docs/database.md @@ -1,3 +1,246 @@ # Database -WIP +**Database** might be considered the most important resource in the operator. It should be used to manage the lifecycle of databases and a users associated with them on the server. + +## How to create and use a database + +To create a `Database`, you first would need to have a running `DbInstance`. You can read about the `DbInstances` [here](dbinstance.md). + +After you have a working `DbInstance` you can start creating a database. + +Let's start by defining an instance on which the database should be deployed. Let's assume you have an instance called `cloudnative-pg` + +```yaml +apiVersion: kinda.rocks/v1beta1 +kind: Database +metadata: + name: my-database +spec: + instance: cloudnative-pg +``` + +Then we need to define a name that is going to be used by the operator to create a `ConfigMap` and a `Secret`. If a secret with this name already exists, db-operator will try to use it, but let's talk about it [later](#reusing-an-existing-secret). + +```yaml +apiVersion: kinda.rocks/v1beta1 +kind: Database +metadata: + name: my-database +spec: + instance: cloudnative-pg + secretName: my-database-creds +``` + +And this is already enough to start using a database, after applying this manifest, operator will create a database and a user on a server, assign required permissions, and create a Secret and a ConfigMap in Kubernetes. Let's check + +```sh +$ kubectl get db my-database +NAME STATUS PROTECTED DBINSTANCE OPERATORVERSION AGE +my-database true false cloudnative-pg 2.19.0 3m33s + +$ kubectl get secret my-database-creds +NAME TYPE DATA AGE +my-database-creds Opaque 4 4m44s + +$ kubectl get cm my-database-creds +NAME DATA AGE +my-database-creds 4 4m46s +``` + +The Secret should contain credentials to connect to the database generated by operator. + +For postgres, +```YAML +apiVersion: v1 +kind: Secret +metadata: + labels: + app.kubernetes.io/managed-by: db-operator + kinda.rocks/used-by-kind: Database + kinda.rocks/used-by-name: my-database + name: my-database-creds +type: Opaque +data: + POSTGRES_DB: << base64 encoded database name (generated by db operator) >> + POSTGRES_PASSWORD: << base64 encoded password (generated by db operator) >> + POSTGRES_USER: << base64 encoded user name (generated by db operator) >> + CONNECTION_STRING: << base64 encoded database connection string >> +``` + +For mysql, +```YAML +apiVersion: v1 +kind: Secret +metadata: + labels: + app.kubernetes.io/managed-by: db-operator + kinda.rocks/used-by-kind: Database + kinda.rocks/used-by-name: my-database + name: my-database-creds +type: Opaque +data: + DB: << base64 encoded database name (generated by db operator) >> + PASSWORD: << base64 encoded password (generated by db operator) >> + USER: << base64 encoded user name (generated by db operator) >> + CONNECTION_STRING: << base64 encoded database connection string >> +``` + + +And the ConfigMap should contain connection information for database server access. + +```YAML +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/managed-by: db-operator + kinda.rocks/used-by-kind: Database + kinda.rocks/used-by-name: my-database + name: my-database-creds +data: + DB_CONN: << database server address >> + DB_PORT: << database server port >> + DB_PUBLIC_IP: << database server public ip >> + ... +``` + +By default, ConfigMap and Secret are created without owner references, so they won't be removed once the `Database` resource is removed. If you want them to be deleted too, you need to turn on the cleanup feature. + +```YAML +apiVersion: "kinda.rocks/v1beta1" +kind: "Database" +metadata: + name: "example-db" +spec: + cleanup: true +``` + +If ArgoCD is used to manage Databases and the `cleanup` is set to `true`, please make sure that the `PrunePropagationPolicy` is not set to `foreground`, because db-operator is using secrets to understand which Database must be removed, and with the `foreground` policy the secret is removed before the Database, that makes it impossible for the operator to finish the reconciliation. + +If this feature is enabled, then `Database` becomes an owner of Secrets and ConfigMaps, and by removing a database, you'll also remove them. + +With the Secret and the ConfigMap, we can connect to the database. Let's create a PostgreSQL Pod to test the connection. + +``` +apiVersion: v1 +kind: Pod +metadata: + name: my-app +spec: + containers: + - name: postgres-create-table + image: postgres + command: + - psql + args: + - -c + - "CREATE TABLE array_int (vector int[][]);" + env: + - name: PGPASSWORD + valueFrom: + secretKeyRef: + name: my-database-creds + key: POSTGRES_PASSWORD + - name: PGUSER + valueFrom: + secretKeyRef: + name: my-database-creds + key: POSTGRES_USER + - name: PGDATABASE + valueFrom: + secretKeyRef: + name: my-database-creds + key: POSTGRES_DB + - name: PGHOST + valueFrom: + configMapKeyRef: + name: my-database-creds + key: DB_CONN + imagePullPolicy: IfNotPresent + restartPolicy: Never +``` + +## Generic additional options + +For production databases you might want to set `.spec.deletionProtected` to `true`. With this setting, db-operator will not remove the database from the server, if a Kubernetes resource is deleted. + +DB operator is capable of generating custom connections strings using the information it has about a database, [here](templates.md) you can read more about templates. + +It is possible to apply extra grants to databases, when it's enabled on the db-instance level. +To enable it, one must set `.spec.allowExtraGrants` to `true` on an instance. + +We have two types of access defined in the code: + - readOnly + - readWrite + +It reflects the `DbUser` types of access. + +The idea behind the extra grants is that there might be a database user that must have access to certain databases, that is not necessarily managed by the operator. Let's say the user is called `database-admin`. + +Now for whatever reason, we want to let the admin access a database with readOnly permissions. In the db definition we need to add the following: +```yaml +kind: Database +spec: + extraGrants: + - user: database-admin + accessType: readOnly +``` + +Now the `database-admin` should have enough permissions for reading data from this database. If access needs to be revoked or changed to `readWrite`, it should be enough to remove the entry from the spec or modify it. + + +## Additional PostgreSQL options + +PostgreSQL database can be additionally configured using the `.spec.postgres{}` section. + +It's possible to drop ensure that the **public** schema is dropped by setting `.spec.postgres.dropPublicSchema`, and you can also create additional schemas that will be granted to the database user, managed by the operator, to do so, set the `.spec.postgres.schemas[]` + +```YAML +postgres: + dropPublicSchema: true # Do not set it, or set to false if you don't want to drop the public schema + schemas: # The user that's going to be created by db-operator, will be granted all privileges on these schemas + - schema_1 + - schema_2 +``` + +If you initialize a database with `dropPublicSchema: false` and then later change it to `true`, or add schemas with the `schemas` field and later try to remove them by updating the manifest, you may be unable to do that. Because `db-operator` won't use `DROP CASCADE` for removing schemas, and if there are objects depending on a schema, someone with admin access will have to remove these objects manually. + +There is a support for [Postgres Database Templates](https://www.postgresql.org/docs/current/manage-ag-templatedbs.html). To create a database from template, you need to set `.spec.postgres.template`. It's referencing to a database on the Postgres server, but not to the k8s Database resource that is created by operator, so there is no validation on the db-operator side that a template exists. + +## Reusing an existing secret + +It's possible to connect DB Operator to an existing database. To do so you'll need to point the operator to an existing secret. It’s important that the secret follows the format expected by the operator. + +For postgres: +```YAML +POSTGRES_DB: << base64 encoded database name (generated by db operator) >> +POSTGRES_PASSWORD: << base64 encoded password (generated by db operator) >> +POSTGRES_USER: << base64 encoded user name (generated by db operator) >> +``` + +For mysql: +```YAML +DB: << base64 encoded database name (generated by db operator) >> +PASSWORD: << base64 encoded password (generated by db operator) >> +USER: << base64 encoded user name (generated by db operator) >> +``` + +Then DB Operator will connect to an existing database and set up a user for it. + +## Experimantal features + +Experimantal features are added via annotations, the following features are available for `Databases` + + +This annotation should be used, when a DbUser is not allowed to log in with password, should be used on the RDS instances, when the SSO is used for authentication. + +For more info see this issue: https://github.com/db-operator/db-operator/issues/125 +```yaml +kinda.rocks/rds-iam-impersonate: "true" +``` + +Delete a postgres database with present connectins, might be useful when pgbouncer is used + +```yaml +kinda.rocks/postgres-force-delete-db: "true" +``` diff --git a/docs/dbinstances.md b/docs/dbinstance.md similarity index 100% rename from docs/dbinstances.md rename to docs/dbinstance.md diff --git a/docs/index.md b/docs/index.md index 2f42c42..626b6eb 100644 --- a/docs/index.md +++ b/docs/index.md @@ -102,7 +102,7 @@ instance1 Running true If `.status.Status` is `true`, it means that you can create Databases on this instance. -You can read more about DbInstances [here](dbinstances.md) +You can read more about DbInstances [here](dbinstance.md) ## Create a Database