Skip to content

Quick Start

This tutorial walks you through creating a PostgreSQL database with a user in 5 minutes.

Prerequisites

  • DB Provision Operator installed in your cluster
  • A PostgreSQL server accessible from your cluster

No PostgreSQL server?

You can deploy a test PostgreSQL server:

kubectl apply -f https://raw.githubusercontent.com/panteparak/db-provision-operator/main/test/e2e/fixtures/testdata/postgresql.yaml

Step 1: Create Admin Credentials

First, create a Secret with the credentials to connect to your PostgreSQL server:

apiVersion: v1
kind: Secret
metadata:
  name: postgres-admin-credentials
  namespace: default
type: Opaque
stringData:
  username: postgres
  password: your-admin-password

Apply:

kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: postgres-admin-credentials
  namespace: default
type: Opaque
stringData:
  username: postgres
  password: postgres
EOF

Step 2: Create a DatabaseInstance

A DatabaseInstance represents the connection to your database server:

apiVersion: dbops.dbprovision.io/v1alpha1
kind: DatabaseInstance
metadata:
  name: postgres-primary
  namespace: default
spec:
  engine: postgres
  connection:
    host: postgresql.default.svc.cluster.local  # Adjust to your server
    port: 5432
    database: postgres
    secretRef:
      name: postgres-admin-credentials
  healthCheck:
    enabled: true
    intervalSeconds: 30

Apply and verify:

kubectl apply -f instance.yaml

# Check status
kubectl get databaseinstance postgres-primary

Wait for the instance to become Ready:

NAME               ENGINE     PHASE   HOST                                      PORT   AGE
postgres-primary   postgres   Ready   postgresql.default.svc.cluster.local      5432   30s

Step 3: Create a User

Create a user first — the operator auto-generates a password and stores it in a Kubernetes Secret:

apiVersion: dbops.dbprovision.io/v1alpha1
kind: DatabaseUser
metadata:
  name: myapp-user
  namespace: default
spec:
  instanceRef:
    name: postgres-primary
  username: myapp_user
  passwordSecret:
    generate: true
    length: 24
    secretName: myapp-user-credentials

Apply:

kubectl apply -f user.yaml

# Check the generated credentials
kubectl get secret myapp-user-credentials -o jsonpath='{.data.password}' | base64 -d

Step 4: Create a Database with an Owner

Now create a database and assign the user as its owner. The owner field references the username of a DatabaseUser (or any existing role):

apiVersion: dbops.dbprovision.io/v1alpha1
kind: Database
metadata:
  name: myapp-database
  namespace: default
spec:
  instanceRef:
    name: postgres-primary
  name: myapp
  owner: myapp_user
  deletionPolicy: Retain

Apply:

kubectl apply -f database.yaml

# Verify
kubectl get database myapp-database

Why create the user first?

The owner field references a database role that must already exist. By creating the DatabaseUser before the Database, the role is ready when the database is created.

Step 5: Customize Credentials with Secret Templates (Optional)

The DatabaseUser's secret provides raw credentials by default. Use secretTemplate to format them as a connection string your application can consume directly:

# Patch the user to add a DATABASE_URL key
spec:
  passwordSecret:
    secretTemplate:
      data:
        DATABASE_URL: "postgresql://{{ urlEncode .Username }}:{{ urlEncode .Password }}@{{ .Host }}:{{ .Port }}/myapp?sslmode=prefer"

See the DatabaseUser docs for the full list of template variables and functions.

Step 6: Grant Permissions

Grant the user access to the database:

apiVersion: dbops.dbprovision.io/v1alpha1
kind: DatabaseGrant
metadata:
  name: myapp-user-grants
  namespace: default
spec:
  userRef:
    name: myapp-user
  databaseRef:
    name: myapp-database
  postgres:
    grants:
      - database: myapp
        schema: public
        tables: ["*"]
        privileges: [SELECT, INSERT, UPDATE, DELETE]

Apply:

kubectl apply -f grant.yaml

Verify Everything

Check all resources:

kubectl get databaseinstance,database,databaseuser,databasegrant

Expected output:

NAME                                               ENGINE     PHASE   AGE
databaseinstance.dbops.dbprovision.io/postgres-primary   postgres   Ready   5m

NAME                                        ENGINE     PHASE   DATABASE   AGE
database.dbops.dbprovision.io/myapp-database   postgres   Ready   myapp      4m

NAME                                         ENGINE     PHASE   USERNAME     AGE
databaseuser.dbops.dbprovision.io/myapp-user   postgres   Ready   myapp_user   3m

NAME                                               PHASE   AGE
databasegrant.dbops.dbprovision.io/myapp-user-grants   Ready   2m

Connect to the Database

Use the generated credentials to connect:

# Get credentials
export PGHOST=postgresql.default.svc.cluster.local
export PGPORT=5432
export PGDATABASE=myapp
export PGUSER=myapp_user
export PGPASSWORD=$(kubectl get secret myapp-user-credentials -o jsonpath='{.data.password}' | base64 -d)

# Connect (from a pod with psql)
kubectl run -it --rm psql --image=postgres:16 --restart=Never -- psql

Credentials lifecycle

The DatabaseUser's Secret is owned by the operator. If the Secret is deleted, the operator automatically generates a new password and recreates it. See Password Rotation for scheduled rotation.

Clean Up

To remove all resources:

kubectl delete databasegrant myapp-user-grants
kubectl delete databaseuser myapp-user
kubectl delete database myapp-database
kubectl delete databaseinstance postgres-primary
kubectl delete secret postgres-admin-credentials myapp-user-credentials

Next Steps