GeassDatabase
A GeassDatabase is one database server for a project environment. It can run in your cluster (Postgres, MySQL, SQLite or Redis), or it can point at a database that runs somewhere else. The dashboard creates and edits it when you add a database to a project, and it is the normal way to work with one. You can also create it with kubectl. A GeassDatabase with no spec.project is the cluster-wide shared server that many projects use through GeassLogicalDatabase resources.
For the task-oriented view, see Databases, Backups and restore and Shared database servers.
Summary
Section titled “Summary”| Property | Value |
|---|---|
| API version | geass.geass.dev/v1alpha1 |
| Kind | GeassDatabase |
| Plural | geassdatabases |
| Scope | Namespaced. Create it in geass-system: the dashboard and the other controllers only look there. |
| Subresources | status |
Printer column Environment |
.spec.environment |
Printer column Engine |
.spec.engine |
Printer column Ready |
.status.conditions[?(@.type=="Ready")].status |
| Finalizer | geass.geass.dev/database |
The database itself runs in the project environment’s namespace, <project>-<environment>. A shared server has no project and runs in geass-system.
Examples
Section titled “Examples”Every example sets spec.deploy.enabled: true. The dashboard reads that field to tell a deployed database from a draft. The kubectl examples do not carry the geass.dev/deploy-workflow annotation, so Geass provisions them at once. See Drafts and the Deploy flow.
Postgres in the cluster, with backups
Section titled “Postgres in the cluster, with backups”apiVersion: geass.geass.dev/v1alpha1kind: GeassDatabasemetadata: name: orders-db namespace: geass-systemspec: project: storefront environment: production engine: Postgres version: "16" storageSize: 20Gi resources: requests: cpu: 500m memory: 1Gi limits: cpu: 500m memory: 1Gi backup: enabled: true retentionDays: 14 deploy: enabled: trueBackups only protect the database once the project has backup storage. See Backups.
Highly available Postgres
Section titled “Highly available Postgres”apiVersion: geass.geass.dev/v1alpha1kind: GeassDatabasemetadata: name: orders-db namespace: geass-systemspec: project: storefront environment: production engine: Postgres highAvailability: true storageSize: 20Gi deploy: enabled: trueGeass runs three instances. It holds the database back until a GeassHAReadiness report says the cluster has at least three healthy nodes.
Restore into a new database
Section titled “Restore into a new database”apiVersion: geass.geass.dev/v1alpha1kind: GeassDatabasemetadata: name: orders-db-restored namespace: geass-systemspec: project: storefront environment: production engine: Postgres version: "16" storageSize: 20Gi backup: enabled: true restoreFrom: archive: orders-db-1a2b3c4d time: "2026-10-11T09:30:00Z" deploy: enabled: truerestoreFrom.archive is the name of a GeassBackupArchive. The new database must match the original’s engine, Postgres version, database name and have at least its storage. See Restoring.
PlanetScale, created by Geass
Section titled “PlanetScale, created by Geass”apiVersion: geass.geass.dev/v1alpha1kind: GeassDatabasemetadata: name: orders-planetscale namespace: geass-systemspec: project: storefront environment: production engine: MySQL placement: External provider: PlanetScale mode: Create connectionRef: name: storefront-planetscale deploy: enabled: trueconnectionRef names a GeassCloudConnection for PlanetScale that is scoped to the same project. engine can be MySQL or Postgres: PlanetScale hosts only those two. externalPort is optional and defaults to the engine’s port. You can add clusterSize to choose the size PlanetScale creates the database with. See External databases.
An existing external database
Section titled “An existing external database”apiVersion: geass.geass.dev/v1alpha1kind: GeassDatabasemetadata: name: orders-external namespace: geass-systemspec: project: storefront environment: production engine: Postgres placement: External mode: Connect externalHost: db.example.com externalPort: 5432 username: orders databaseName: orders passwordSecretRef: name: orders-external-password key: password deploy: enabled: trueapiVersion: v1kind: Secretmetadata: name: orders-external-password namespace: geass-systemstringData: password: change-meThe Secret must be in geass-system, next to the GeassDatabase.
A shared server
Section titled “A shared server”apiVersion: geass.geass.dev/v1alpha1kind: GeassDatabasemetadata: name: cluster-postgres namespace: geass-systemspec: engine: Postgres serverRegion: eu storageSize: 20Gi deploy: enabled: trueWith no project, this is the cluster-wide server. Projects take databases on it with GeassLogicalDatabase.
Spec fields
Section titled “Spec fields”Defaults marked “CRD default” are filled in by the API server. Defaults marked “controller” are applied by the operator when the field is empty.
| Field | Type | Required or default | Validation | Meaning |
|---|---|---|---|---|
spec.project |
string | Optional | None | The owning project. Empty makes this the cluster-wide shared server, which runs in geass-system. |
spec.environment |
string | Optional. Required in practice for a project database. | Pattern ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$, max length 63 |
The project environment. It must be one of the project’s spec.environments. Empty for a shared server. |
spec.engine |
string | Required | Enum Postgres, MySQL, SQLite, Redis |
The database engine. SQLite runs rqlite, which serves SQLite over HTTP on port 4001. Redis runs without a volume. A PlanetScale database can be MySQL or Postgres. |
spec.placement |
string | CRD default InCluster |
Enum InCluster, External |
InCluster runs the database in the cluster. External connects to a database elsewhere. |
spec.provider |
string | Optional | Enum PlanetScale, AWS |
The external provider. Only meaningful with placement: External. PlanetScale with mode: Create makes Geass create the database on PlanetScale. AWS only labels the status message: Geass has no RDS client. |
spec.mode |
string | Optional | Enum Create, Connect |
Only Create with provider: PlanetScale changes behavior. Connect and an empty value behave the same: Geass uses the host, username and password you give it. |
spec.highAvailability |
boolean | false |
None | Asks for a multi-instance topology. In the cluster only. Needs a ready GeassHAReadiness report. Not supported for SQLite. |
spec.connectionRef |
LocalObjectReference | Optional | None | A GeassCloudConnection in geass-system. It must be scoped to the same project. |
spec.connectionRef.name |
string | CRD default "" |
None | Name of the connection. |
spec.databaseName |
string | Optional. The controller uses the resource name. | None | The database name. Used for Postgres (initdb), for MySQL, for the database key of the connection Secret, and as the PlanetScale database name. |
spec.externalHost |
string | Optional | None | Host of an external database. Used for placement: External. |
spec.externalPort |
integer (int32) | Optional. The controller uses the engine’s default port (5432, 3306, 6379 or 4001). | None | Port of an external database. |
spec.clusterSize |
string | Optional. Empty leaves the size to PlanetScale. | None in the CRD. The dashboard API rejects a size on a non-PlanetScale database, and a name PlanetScale does not offer for the engine when it can check | The PlanetScale cluster size, for example PS_10, that a database is created with. It is read only when Geass creates the database on PlanetScale (provider: PlanetScale, mode: Create). Changing it later does not resize the database, and the dashboard API refuses the change once the connection Secret exists. The dashboard API lists the sizes at GET /api/planetscale/cluster-sizes?project=<project>&connection=<connection>&engine=MySQL (or Postgres). The dashboard has no field for it. |
spec.username |
string | Optional | None | Login for an external database. |
spec.passwordSecretRef |
SecretKeySelector | Optional | None | Secret in geass-system that holds the external password. The key defaults to password when empty. |
spec.passwordSecretRef.name |
string | CRD default "" |
None | Secret name. |
spec.passwordSecretRef.key |
string | Required when passwordSecretRef is set |
None | Key inside the Secret. |
spec.passwordSecretRef.optional |
boolean | Optional | None | Standard Kubernetes field. Geass does not read it. |
spec.version |
string | CRD default "16" |
None | Postgres major version. Geass uses it as the image tag ghcr.io/cloudnative-pg/postgresql:<version>. MySQL, Redis and SQLite do not read it: their versions come from the chart or image Geass pins. |
spec.instances |
integer (int32) | CRD default 1 |
Minimum 1 | Number of instances. With highAvailability Geass uses at least 3. See the caution under Engines and high availability. |
spec.storageSize |
Quantity | Optional. The controller uses 10Gi, or 1Gi for SQLite. |
None | Disk size for each instance. Not used by Redis or external databases. The dashboard writes it explicitly. |
spec.resources |
ResourceRequirements | Optional. The controller uses 250m CPU and 512Mi memory (SQLite: 100m and 128Mi). | None | CPU and memory for each instance. Geass only reads it when requests is set. Set requests and limits together. |
spec.deploy.enabled |
boolean | false |
None | Gates provisioning, but only for resources that carry the geass.dev/deploy-workflow: "true" annotation. The API, the command line and the MCP server report a database with this field false as draft, whatever the annotation says. See Drafts and the Deploy flow. |
spec.backup |
object | Optional | None | Backups for in-cluster Postgres, MySQL and SQLite. Ignored for Redis and external databases. |
spec.backup.enabled |
boolean | Required when backup is set |
None | Turns backups on. |
spec.backup.retentionDays |
integer (int32) | CRD default 7 |
Minimum 1, maximum 365 | How many days back you can restore. |
spec.restoreFrom |
object | Optional | CEL: !(has(self.restorePoint) && has(self.time)), message “set either restorePoint or time, not both” |
Creates this database from another database’s backups. Read once, while the database is first provisioned. |
spec.restoreFrom.archive |
string | Required when restoreFrom is set |
Minimum length 1 | Name of the GeassBackupArchive to restore from. |
spec.restoreFrom.restorePoint |
string | Optional | Exclusive with time |
ID of a restore point listed on the archive. |
spec.restoreFrom.time |
date-time | Optional | Exclusive with restorePoint |
Restore to this moment. Postgres only. It must be inside the archive’s recovery window. |
spec.runOn.tags |
array of strings | Optional | Max 8 items, each matching ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ and at most 40 characters, set semantics |
Node tags the database must run on. A node needs all of them. The project’s spec.requiredTags apply as well, without being listed here. Read once, when the database is first provisioned. |
spec.serverRegion |
string | Optional | Pattern ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$, max length 40 |
Where a shared server runs. A database with a project follows its project’s region instead. |
Engines and high availability
Section titled “Engines and high availability”| Engine | What Geass runs | Host in status.host |
Backups |
|---|---|---|---|
Postgres |
A CloudNativePG Cluster named after the database. |
<name>-rw.<namespace>.svc |
Continuous. Restore to any moment. |
MySQL |
The Bitnami MySQL chart as the Helm release geass-mysql-<name>. |
geass-mysql-<name>.<namespace>.svc (-primary suffix with high availability) |
Daily snapshot. |
SQLite |
One rqlite pod (rqlite/rqlite:8.36.16) with a volume, as a Deployment. |
<name>.<namespace>.svc |
Daily snapshot. |
Redis |
The Bitnami Redis chart as the Helm release geass-redis-db-<name>. No volume: data does not survive the pod being replaced. |
geass-redis-db-<name>-master.<namespace>.svc |
None. |
With highAvailability: true Postgres runs three instances. When Longhorn is installed they use the single-replica storage class geass-single, because the instances replicate the data themselves. MySQL and Redis switch the chart to its replication architecture. SQLite refuses with the message SQLite does not support high availability.
External databases
Section titled “External databases”A database with placement: External is never created in your cluster. Geass reads the host, port, username and password from the spec, writes the connection Secret, and reports Ready. It does not test the connection.
For provider: PlanetScale with mode: Create, Geass calls the PlanetScale API with the token from the connection:
- It looks for a PlanetScale database named
spec.databaseName(or the resource name). If there is none, it creates one of the kind that matchesspec.engine,mysqlforMySQLandpostgresqlforPostgres, withspec.clusterSizewhen you set one. A database that already exists with the other kind is refused withPlanetScale database "<name>" already exists as <kind>, not <kind>. Any other engine is refused withPlanetScale hosts MySQL and Postgres databases, not <engine>. - A new database takes minutes to provision. Until PlanetScale reports it ready,
ReadyisFalsewith the messagePlanetScale database is starting, which does not count as a failure. After 30 minutes the message becomesPlanetScale database did not become ready within 30m0s; check the database in PlanetScaleand it counts as one. - Once the database is ready, Geass issues a login on the
mainbranch: a branch password for MySQL, and a role that inherits thepostgresrole for Postgres. PlanetScale shows the password only once, so Geass stores the host, username and password in<name>-connectionat once. If it cannot store them, it revokes the login again.
The port is spec.externalPort, or the engine’s default (3306 for MySQL, 5432 for Postgres). If you delete the connection Secret, Geass issues a new login. For Postgres the database key of the Secret is the database name PlanetScale gives the role.
Drafts and the Deploy flow
Section titled “Drafts and the Deploy flow”Resources the dashboard creates start as drafts:
- The dashboard sets
spec.deploy.enabled: falseand adds the annotationgeass.dev/deploy-workflow: "true", a pending-change counter (geass.dev/pending-updates) and the kind listgeass.dev/pending-changes. - While
spec.deploy.enabledisfalse, the controller removes any resources it created for the database and reportsReadyasFalsewith the messageResource is configured and waiting for deployment. - Deploy changes in the top bar sets
spec.deploy.enabled: trueon every pending resource of the environment, clears the pending markers and stores a copy of the spec in thegeass.dev/last-deployedannotation. - After the first deploy, edits you save in Settings are held back. The controller keeps running the last deployed copy while
geass.dev/pending-updatesis above zero. The one exception isspec.backup, which takes effect as soon as you save it.
The gate only applies when the annotation geass.dev/deploy-workflow is "true". A GeassDatabase without it provisions as soon as it is valid, whatever spec.deploy.enabled says. Set spec.deploy.enabled: true anyway: the dashboard uses it to decide whether volumes exist, whether storage can only grow, and whether the node choice is locked.
Status
Section titled “Status”| Field | Type | Meaning |
|---|---|---|
status.targetNamespace |
string | The namespace the database runs in. |
status.connectionSecret |
string | Name of the Secret with the connection details, <name>-connection. |
status.host |
string | Host of the database. Shown as Endpoint in the dashboard. |
status.restoredAt |
date-time | When a snapshot restore (MySQL or SQLite) finished. It stops the snapshot from being loaded a second time. |
status.backup |
object | Backup summary. Absent while backups are off. |
status.backup.state |
string | One of NeedsStorage, Starting, Protected, AtRisk. |
status.backup.message |
string | Plain-language explanation of the state. |
status.backup.archive |
string | Name of the GeassBackupArchive that holds this database’s backups. |
status.backup.lastBackupTime |
date-time | When the latest backup finished. |
status.backup.recoveryWindowStart |
date-time | The earliest moment you can restore to. |
status.reconcileRetry |
object | Counters for consecutive failures: reconcileFailures, reconcileFailureStarted, reconcileFailureGeneration. |
status.provision |
object | Deploy history. activeProvisionAttempt is the ID of the running attempt. provisionAttempts keeps the newest 8, each with id, startedAt, completedAt, phase (Running, Succeeded or Failed), summary and up to 12 errors (recordedAt, message). buildRef and deploymentRef are only used by services. |
status.conditions |
list | One condition: Ready. |
Ready condition and retries
Section titled “Ready condition and retries”Ready is the only condition. It has three reasons:
| Reason | Status | Meaning |
|---|---|---|
DatabaseReady |
True |
The database is running and the connection Secret exists. The message names the engine, for example Postgres database is ready. For an external database it is PlanetScale database is ready or AWS database is ready. |
ReconcileError |
False |
Not ready yet. The message says what Geass is waiting for or what failed. Geass checks again after 30 seconds. |
ProvisionFailed |
False |
Geass gave up. The message is always Provisioning failed after repeated errors. Update settings or platform configuration, then save or redeploy to try again. |
Messages that describe waiting do not count as failures. Everything else does. Geass moves to ProvisionFailed when it sees 5 counted failures in a row, when counted failures last 3 minutes, or at once for a permanent error (an unsupported engine, an access-denied error, or an invalid credential or configuration).
Once the reason is ProvisionFailed, the controller stops reconciling that database until you change its spec (any edit that raises metadata.generation) or press Retry. Retry resets the counters, sets Ready back to ReconcileError with the message Retrying provisioning, and starts a new entry in status.provision.
The Ready messages you can see, in the order Geass checks them:
| Message | Meaning |
|---|---|
Resource is configured and waiting for deployment |
A draft. Deploy it. |
resource has pending changes and no last deployed snapshot |
The database has saved edits but no geass.dev/last-deployed copy. Deploy again from the dashboard. |
project "<project>" does not exist, project "<project>" is not ready, project "<project>" has no <environment> environment |
The project or environment is missing or not ready. |
project "<project>" cluster "<cluster>" is not ready |
The project’s GeassCluster is not Ready. |
cloud connection "<name>" was not found, ... is scoped to project "<project>", ... must be scoped to a project |
spec.connectionRef is wrong. |
High availability requires a cluster with at least three healthy nodes |
See Troubleshooting. |
Storage is starting, Storage is unavailable |
Waiting for the Longhorn storage class. See Troubleshooting. |
Installing Postgres operator chart, Installing MySQL database chart, Installing Redis database chart |
Helm is installing a chart. |
PlanetScale database is starting |
PlanetScale is still creating the database. Waiting for it does not count as a failure, for up to 30 minutes. |
Postgres database is starting, Service is starting, Starting service |
Pods are starting. |
Service failed to start |
Every pod of the chart failed. |
Restoring database from backup |
A restore is running. |
What the dashboard writes
Section titled “What the dashboard writes”| Where | What it does to the GeassDatabase |
|---|---|
| + Add resource > Database > PostgreSQL, MySQL, Redis or SQLite | Creates a draft with a generated name such as falling-mist. It sets project, environment, engine, placement: InCluster, resources (250m and 512Mi, or 100m and 128Mi for SQLite), storageSize (10Gi, or 1Gi for SQLite, none for Redis) and, for Postgres, MySQL and SQLite, backup: {enabled: true, retentionDays: 7}. A runOn choice is saved only by a dashboard admin. |
| + Add resource > Database > PlanetScale or AWS RDS | Creates a draft with placement: External, provider, connectionRef and an engine (MySQL for PlanetScale, Postgres for AWS RDS). See the caution under External databases. |
+ Add resource > Database > Logical database, or the entry for a shared server (shown as <name> (shared)) |
Creates a GeassLogicalDatabase, not a GeassDatabase. |
| Resource panel, Settings tab, Database section | Version writes spec.version. Resources writes spec.resources (the sizes are 0.1, 0.25, 0.5, 1 or 2 CPU and 128 MB to 4 GB). Size under Storage writes spec.storageSize. These wait for a deploy. |
| Settings tab, Scale section, Run on | Writes spec.runOn.tags. It is only editable before the first deploy. After that the dashboard refuses with A database keeps its data on the nodes it was first deployed to, so which nodes it runs on cannot change after that. |
| Settings tab, Backups section (also the Backups tab) | Back up this database and Keep backups for write spec.backup. They apply at once. |
| Deploy changes in the top bar | Runs the deploy flow for every pending resource of the environment. It first checks that the cluster has room for the database (or three instances). The API deploys one database with POST /api/databases/<name>/deploy. |
| Retry | Resets a ProvisionFailed database. |
| Console tab, Run query | Runs your SQL in the database pod with psql -c, mysql -e, redis-cli or rqlite -e. It is not a field of the resource. |
| Restore buttons on the Backups tab | Creates a new database with spec.restoreFrom. It is deployed at once, without a draft. |
| Settings > Databases > Set up a server | Creates a shared server: no project, spec.deploy.enabled: true, highAvailability from the High availability switch (which also sets instances: 3), and serverRegion from Region. |
| Settings tab, Danger section | Deletes the database after you type its resource ID. |
The storage rules the dashboard enforces: at least 1Gi, only growth after the first deploy, and no change at all when the storage class cannot expand volumes. The messages are storage can be increased but not decreased once deployed (currently <size>) and this cluster's storage can't be resized, so a deployed database stays at <size>.
A viewer in the dashboard sees a redacted copy of each database: the engine, host, user, password reference and connection details are cleared. A token that cannot change things gets the same copy from the API.
From the command line and the API
Section titled “From the command line and the API”| To | Command | MCP tool |
|---|---|---|
| List databases | geass databases list |
list_databases |
Read resource, spec and status |
geass databases get NAME |
get_database |
Read host, port, database and username of the connection Secret |
geass databases connection NAME |
database_connection |
Also read password and uri |
geass databases connection NAME --reveal |
None: the tool never returns them |
They call GET /api/v1/databases, GET /api/v1/databases/{name} and GET /api/v1/databases/{name}/connection. The state they report is deleting once metadata.deletionTimestamp is set, then draft when spec.deploy.enabled is false, then ready when Ready is True, failed when its reason is ProvisionFailed, and pending otherwise. The connection call needs Full access, works once status.targetNamespace and status.connectionSecret are set, and a reveal is written to the operator log. See Databases.
Connection Secret
Section titled “Connection Secret”Once the database is ready, Geass writes a Secret named <name>-connection in the database’s namespace. It has these keys: host, port, database, username, password and uri.
| Engine | uri |
|---|---|
| Postgres | postgresql://<user>:<password>@<host>:5432/<database> |
| MySQL | mysql://<user>:<password>@<host>:3306/<database> |
| Redis | redis://:<password>@<host>:6379 |
| SQLite | http://<host>:4001 |
The login is app. Geass first writes the credentials to a Secret named <name>-bootstrap and the connection Secret copies them.
Backups
Section titled “Backups”spec.backup protects in-cluster databases only. The dashboard refuses to change it for Redis or external databases with Backups are not available for this kind of database.
- Postgres is archived continuously (CloudNativePG, Barman object store) and a base backup runs daily at about 02:00 UTC. You can restore to any moment in the recovery window.
- MySQL and SQLite are copied once a day by a CronJob named
<name>-backupat about 02:00 UTC. The copies are compressed SQL files, and a restore returns the data as of one of them. - The backups go to the project’s backup storage: an S3 bucket in the AWS account of a GeassCloudConnection. Geass creates the bucket (
geass-backups-<random>) and an IAM user scoped to it when the project’sspec.backupStorageis set. Until thenstatus.backup.stateisNeedsStorage. A shared server has no project, so it has nowhere to put backups. - Geass records each database’s backups in a GeassBackupArchive in
geass-system. - Backups are an add-on. If Geass cannot work out the backup plan, the database keeps running and Geass tries again after a minute.
- Deleting a database takes one last backup (waiting up to 10 minutes), then keeps the archive for 7 days.
- The Jobs that dump, restore and take the final backup of a MySQL or SQLite database run in the database’s region, on nodes that carry the project’s required tags when the database was placed with them. They do not use
spec.runOn.tags.
status.backup.state values:
| State | Meaning |
|---|---|
NeedsStorage |
Backups are on but the project has nowhere to put them, or the storage failed. The message is Choose where backups are stored to protect this database or Backup storage is not working: <AWS error>. |
Starting |
Storage works and the first backup has not finished. The message is Taking the first backup. |
Protected |
Backups are running. The message is Backups are running. |
AtRisk |
The message is Recent changes are not being saved to backup storage or The latest backup failed. |
Restoring
Section titled “Restoring”A restore always creates a new database next to the original. The original is not touched. Geass refuses a restore that cannot succeed, with these messages:
| Message | Cause |
|---|---|
These backups are no longer available |
The archive does not exist any more. |
Backups from another project cannot be restored here |
The archive belongs to a different project. |
A restored database must use the same engine as the original (<engine>) |
Wrong spec.engine. |
A restored database must use Postgres version <n>, the version of the backup |
Wrong spec.version. |
A restored database must keep the database name <name> |
Wrong spec.databaseName. |
A restored database needs at least <size> of storage, the size of the original |
spec.storageSize is too small. |
These backups have no restore points yet |
The first backup has not finished. |
The chosen restore point is not available |
restorePoint is not on the archive. |
The chosen time is earlier than the oldest restore point, The chosen time is later than the newest recoverable moment |
time is outside the recovery window. |
This database can only be restored to a restore point |
time on a MySQL or SQLite archive. |
Choose either a restore point or a time, not both |
Both fields are set. |
The backup storage is not available: <reason> |
Geass could not reach the bucket. |
The restore could not be completed. Check that the backups are still available, then restore again |
The restore Job failed. |
A restore only runs while the database is first provisioned. Postgres recovers while the cluster is created. For MySQL and SQLite a Job named <name>-restore loads the snapshot, then status.restoredAt is set so it never loads twice.
Editing by hand
Section titled “Editing by hand”You can create a GeassDatabase with kubectl and you can edit one. The dashboard shows it like any other. Keep these in mind.
- Geass writes the annotations
geass.dev/storage-classandgeass.dev/node-placementonce, when it first provisions the database. They pin the volume’s storage class and the nodes it runs on. Do not remove or edit them.geass.dev/node-placementis JSON with theregion, thetagsfromspec.runOn.tagsand therequiredtags of the project at that moment, for example{"region":"eu","tags":["storage"],"required":["hipaa"]}. An empty{}means the database runs anywhere. See Where a database runs. - The dashboard writes
geass.dev/display-name,geass.dev/deploy-workflow,geass.dev/pending-updates,geass.dev/pending-changesandgeass.dev/last-deployed. - The controller does not rewrite the spec of a
GeassDatabase. Status is the controller’s. spec.restoreFrom,spec.runOnand the storage class are read once. Changing them later has no effect.- A volume’s size can grow but not shrink.
Setting spec.deploy.enabled back to false on a resource that carries the geass.dev/deploy-workflow annotation makes Geass treat it as a draft again. It deletes the resources it built for it. For Postgres and SQLite the data volume goes with them.
To delete a database, delete the GeassDatabase. The finalizer first takes a final backup if backups are on, then removes the resources below. The dashboard refuses to delete a shared server while logical databases still use it. kubectl does not stop you.
What happens under the hood
Section titled “What happens under the hood”Geass keeps the resource in geass-system. The workloads live in <project>-<environment>. Because they are in a different namespace, Geass cannot use owner references, so it deletes them itself when you delete the resource. Objects Geass creates carry these labels: geass.dev/managed-by=geass, geass.dev/kind=GeassDatabase, geass.dev/name=<name>, geass.dev/system-namespace=geass-system, geass.dev/project and geass.dev/environment.
Common to every in-cluster engine:
- Secret
<name>-bootstrapand Secret<name>-connectionin the database’s namespace. - Optionally, Secrets
<name>-backup-credentialsand<name>-restore-credentials, which hold credentials scoped to the backup bucket. - Annotations
geass.dev/storage-classandgeass.dev/node-placementon theGeassDatabase.
Per engine:
- Postgres: a HelmChart
geass-cloudnative-pginkube-systeminstalls the CloudNativePG operator intocnpg-system. Then a CNPGCluster<name>runs in the database’s namespace, with pods<name>-1,<name>-2, a volume per pod and the Services<name>-rw,<name>-roand<name>-r. With backups there is aScheduledBackup<name>. On delete, aBackupnamed<name>-final. A Postgres database that hosts logical databases also gets a<name>-superuserSecret. - MySQL: a HelmChart
geass-mysql-<name>inkube-systeminstalls a Helm release into the database’s namespace. - Redis: a HelmChart
geass-redis-db-<name>inkube-systemdoes the same. - SQLite: a Deployment
<name>, a Service<name>on port 4001 and a PVC<name>-sqlite. - External: only the connection Secret.
Inspect them:
# The resource and its statuskubectl -n geass-system get geassdatabaseskubectl -n geass-system get geassdatabase orders-db -o yaml
# Where it runsNS=$(kubectl -n geass-system get geassdatabase orders-db -o jsonpath='{.status.targetNamespace}')
# Everything Geass labelled for itkubectl -n "$NS" get all,pvc,secrets -l geass.dev/name=orders-db
# Postgreskubectl -n "$NS" get clusters.postgresql.cnpg.io orders-dbkubectl -n "$NS" get pods -l cnpg.io/cluster=orders-dbkubectl -n cnpg-system get pods
# MySQL or Redis (the chart and its install job)kubectl -n kube-system get helmchartskubectl -n "$NS" get pods -l app.kubernetes.io/instance=geass-mysql-orders-db
# Backupskubectl -n "$NS" get scheduledbackups,backupskubectl -n geass-system get geassbackuparchives
# Read the connection detailskubectl -n "$NS" get secret orders-db-connection -o jsonpath='{.data.uri}' | base64 -dTroubleshooting
Section titled “Troubleshooting”The database stays in Draft or says it is waiting for deployment
Section titled “The database stays in Draft or says it is waiting for deployment”The message is Resource is configured and waiting for deployment. The resource carries the geass.dev/deploy-workflow: "true" annotation and spec.deploy.enabled is false. Press Deploy changes in the top bar, or set spec.deploy.enabled: true. Saved edits wait for a deploy too: the dashboard shows the pending count in the top bar.
High availability requires a cluster with at least three healthy nodes
Section titled “High availability requires a cluster with at least three healthy nodes”Geass looks for a GeassHAReadiness in geass-system whose Ready condition is True and whose status.healthyNodes is at least 3. If none exists, the database waits. Open Settings > Usage > HA readiness and press Run readiness check, which creates the report. Nothing else creates it. Add nodes if the cluster has fewer than three healthy ones. Once the report exists the operator works it out again when a node, a storage class or the Geass cluster changes, and a waiting database checks again every 30 seconds.
Storage is starting, then Storage is unavailable
Section titled “Storage is starting, then Storage is unavailable”New volumes wait for the Longhorn storage classes geass-replicated or geass-single (or the regional geass-replicated-<region>, or geass-tagged-<hash> in a project that requires node tags). If Longhorn is enabled and still installing, the database waits up to 15 minutes, then reports Storage is unavailable and counts it as a failure. Check the GeassCluster AddonsReady condition and the pods in longhorn-system. Once Geass picks a class it pins it, so installing Longhorn later does not change an existing volume.
One wait has no limit. When Longhorn is serving the global class but the regional or tagged class a database needs has not been made, the message stays Storage is starting. The cluster controller makes the class once at least one schedulable node is in its scope and every such node has a ready Longhorn manager. See Storage.
Capacity messages
Section titled “Capacity messages”This <engine> database needs about <cpu> CPU and <memory> memory. The cluster currently has ... available means no node has room. Add nodes or lower spec.resources. For There is no ready node in <place> to run this ... and ... reserved for other work, see Scaling and placement and GeassNode. <place> names the region and every tag the database needs, the project’s required tags included. Geass only checks capacity when it first creates the database.
project "<project>" is not ready or has no <environment> environment
Section titled “project "<project>" is not ready or has no <environment> environment”The database waits for its project and the project’s cluster to be Ready, and for the environment to be listed in the project’s spec.environments.
The reason is ProvisionFailed and you cannot see why
Section titled “The reason is ProvisionFailed and you cannot see why”Press Retry and watch the Ready message:
kubectl -n geass-system get geassdatabase orders-db -w \ -o custom-columns=NAME:.metadata.name,READY:.status.conditions[0].status,MESSAGE:.status.conditions[0].messageGeass keeps trying for up to 5 failures or 3 minutes, and the message names the real problem. Also read the events and status of the objects in What happens under the hood.
A PlanetScale or external database is not ready
Section titled “A PlanetScale or external database is not ready”external database host, username, and password are required: setexternalHost,usernameandpasswordSecretRef, or usemode: Createwith a PlanetScale connection.external password secret "<name>" is unavailable: the Secret is missing fromgeass-system.a PlanetScale connection is required:spec.connectionRefis empty.connection "<name>" is not a PlanetScale connection: the connection’s provider isAWS.PlanetScale token and organization are required: the connection’s Secret lackstoken, or neither the connection’sspec.organizationnor the Secret’sorganizationkey is set.PlanetScale API <status>: ...: PlanetScale refused the call. Check the token’s permissions, the organization name and, if you setspec.clusterSize, that PlanetScale offers that size for the engine.PlanetScale hosts MySQL and Postgres databases, not <engine>:spec.engineisRedisorSQLite. UseMySQLorPostgres.PlanetScale database "<name>" already exists as <kind>, not <kind>: a database with that name exists in the organization with the other engine. Choose anotherspec.databaseName.PlanetScale database is startingfor a long time, thenPlanetScale database did not become ready within 30m0s: PlanetScale did not finish creating the database. Check it in PlanetScale, then press Retry.
Backups are NeedsStorage or AtRisk
Section titled “Backups are NeedsStorage or AtRisk”NeedsStorage means the project has no backup storage or Geass cannot reach it. Choose an AWS connection under Choose where backups are stored, then check the AWS error in status.backup.message. AtRisk means the last backup failed or the change log is not reaching the bucket. Check the CloudNativePG Cluster conditions or the <name>-backup Jobs in the database’s namespace.
A restore does not start
Section titled “A restore does not start”Read the message against the table in Restoring. Postgres reports Restoring database from backup while the new cluster recovers. A recovery that cannot finish shows as a database that stays in that state, so check the pods <name>-1 and their logs.
Deleting a database takes a while
Section titled “Deleting a database takes a while”Geass takes a final backup first and waits up to 10 minutes for it. If the database is not running, or the backup fails, Geass skips the wait. The finalizer is released when the resources are gone.
MySQL volumes remain after deletion
Section titled “MySQL volumes remain after deletion”Geass deletes the HelmChart object and does not delete persistent volume claims the chart created. Check kubectl -n <namespace> get pvc after you delete a MySQL database.