Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
245 changes: 244 additions & 1 deletion docs/database.md
Original file line number Diff line number Diff line change
@@ -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"
```
File renamed without changes.
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Loading