Deploy and Manage AlloyDB Omni on Kubernetes (GKE or Bring-Your-Own Cluster)

1. Introduction

In this codelab, you will learn how to install the AlloyDB Omni Kubernetes operator (the container orchestrator) on either a Google Kubernetes Engine (GKE) Autopilot cluster or your own Kubernetes cluster, and manage complete end-to-end database lifecycle workflows and Critical User Journeys (CUJs).

AlloyDB Omni is a downloadable edition of AlloyDB designed to run anywhere—from on-premises environments to Google Cloud or edge computing. With the container orchestrator, AlloyDB Omni automates high availability, automatic failovers, self-healing, rolling maintenance with minimal downtime, connection pooling, automated backups, and point-in-time recovery.

Choose Your Environment Path

You can complete this codelab using either of the following two paths:

  1. Path 1: Have a Google Cloud Account (GKE Autopilot) — Provision a fully managed GKE Autopilot cluster using Google Cloud Shell or the Google Cloud Console.
  2. Path 2: Do Not Have a Google Cloud Account (Bring Your Own Kubernetes Cluster) — Use an existing Kubernetes cluster (v1.21 or later) with kubectl and helm configured on your workstation. No Google Cloud account or gcloud CLI is required.

Prerequisites

  • Basic familiarity with Kubernetes concepts (kubectl, Helm, Custom Resource Definitions).
  • For Path 1 (Google Cloud / GKE Autopilot):
    • A Google Cloud project with billing enabled.
    • Access to Google Cloud Shell or a workstation configured with gcloud, kubectl, and helm.
  • For Path 2 (Bring Your Own Kubernetes Cluster):
    • A Kubernetes cluster running version 1.21 or later with a default StorageClass for dynamic PersistentVolume provisioning.
    • Worker nodes running Linux kernel 4.18+ with cgroup v2 enabled (x86-64/AMD64) and at least 8 vCPUs and 24 GiB of allocatable RAM across the cluster.
    • A workstation configured with kubectl and helm connected to your cluster.

What you'll learn

  • How to provision a GKE Autopilot cluster (Path 1) or validate an existing Kubernetes cluster (Path 2).
  • How to install cert-manager and the AlloyDB Omni Kubernetes operator via Helm.
  • How to deploy a single-instance AlloyDB Omni DBCluster.
  • How to scale to High Availability (HA) with synchronous standbys and enable read-only standby capability.
  • How to configure scheduled automated backups to local repository storage (and optionally Google Cloud Storage on Path 1).
  • How to perform on-demand backups and verify data restoration to a prior state.
  • How to perform Point-in-Time Recovery (PITR) to a new cloned database cluster.
  • How to deploy PgBouncer connection pooling for client connection scaling.
  • How to deploy pgAdmin4 to visually manage and query the database.
  • How to execute Low Downtime Maintenance (LDTM) for CPU and memory resource scaling.

What you'll need

  • Path 1: Google Cloud Shell with pre-installed gcloud, kubectl, and helm utilities.
  • Path 2: A terminal with kubectl and helm connected to your Kubernetes cluster.
  • For reference documentation, see the official AlloyDB Omni deployment guide.

2. Setup and Requirements

Choose Path 1 if you are using a Google Cloud account to create a GKE Autopilot cluster, or Path 2 if you are using your own Kubernetes cluster without a Google Cloud account.

Path 1: Google Cloud Project Setup (GKE Autopilot)

  1. In the Google Cloud console, select or create a Google Cloud project.
  2. Confirm that billing is enabled for your project. Learn how to verify billing status.
  3. Open Google Cloud Shell by clicking the Activate Cloud Shell icon in the upper-right corner of the Google Cloud Console, or by visiting shell.cloud.google.com. Cloud Shell provisions a compute environment loaded with gcloud, kubectl, and helm.
  4. Set your project ID as an environment variable and configure gcloud:
export PROJECT_ID="<YOUR_PROJECT_ID>"
export REGION="us-central1"
export CLUSTER_NAME="omni-autopilot-cluster"

gcloud config set project ${PROJECT_ID}
gcloud config set compute/region ${REGION}
  1. Enable the required Google Cloud APIs for GKE and Cloud Storage:
gcloud services enable container.googleapis.com \
    storage.googleapis.com \
    cloudresourcemanager.googleapis.com

Path 2: Bring-Your-Own Cluster Setup (No Google Cloud Account)

If you do not have a Google Cloud account and are using your own Kubernetes cluster, verify the following prerequisites from your terminal before continuing:

  1. Verify that kubectl and helm can reach your cluster and that your nodes are Ready:
kubectl get nodes
helm version
  1. Verify that your cluster has a default StorageClass marked (default). The DBCluster and BackupPlan manifests dynamically provision PersistentVolumeClaims using the cluster's default StorageClass:
kubectl get storageclass

If no StorageClass is marked (default), designate one as the default before proceeding:

kubectl patch storageclass <YOUR_STORAGE_CLASS_NAME> \
  -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
  1. Confirm that your worker nodes meet the operator's hardware and OS requirements:
    • OS and Kernel: Linux kernel 4.18 or later with cgroup v2 enabled on x86-64/AMD64 nodes.
    • Cluster Capacity: At least 8 vCPUs and 24 GiB of allocatable memory across your worker nodes to run the HA database instances (scaled to 2 vCPUs and 8 GiB each in Step 12), the PITR cloned instance, PgBouncer, and pgAdmin4 concurrently.
    • Network Access: Outbound internet access to pull container images from gcr.io/alloydb-omni, quay.io/jetstack, and docker.io.

3. Provision or Connect to Your Kubernetes Cluster

If you are following Path 1 (Google Cloud Account), GKE Autopilot provides a hands-off, fully managed Kubernetes mode where Google manages the cluster infrastructure, node provisioning, and autoscaling. You can create your GKE Autopilot cluster using the Google Cloud CLI or Google Cloud Console.

Option A: Create GKE Autopilot Cluster via CLI (Path 1)

Execute the following gcloud command in Cloud Shell:

gcloud container clusters create-auto ${CLUSTER_NAME} \
    --region=${REGION} \
    --project=${PROJECT_ID}

Option B: Create GKE Autopilot Cluster via Console (Path 1)

  1. Open Kubernetes Engine in the Google Cloud Console.
  2. In the left navigation pane, click Clusters.
  3. Click Create.
  4. In the GKE Autopilot section, click Configure.
  5. Specify your cluster name (for example, omni-autopilot-cluster) and select your preferred region (us-central1).
  6. Click Create.

Verify Cluster Connectivity (Path 1 and Path 2)

If you created a GKE Autopilot cluster in Path 1, configure your kubectl credentials:

gcloud container clusters get-credentials ${CLUSTER_NAME} --region=${REGION} --project=${PROJECT_ID}

For both Path 1 and Path 2, verify connectivity to your Kubernetes cluster:

kubectl get nodes

4. Install Operator Prerequisites and Operator

The AlloyDB Omni Kubernetes operator requires cert-manager for managing admission webhook TLS certificates.

1. Install cert-manager

Install cert-manager using its official Helm chart:

helm install \
  cert-manager oci://quay.io/jetstack/charts/cert-manager \
  --version v1.21.2 \
  --namespace cert-manager \
  --create-namespace \
  --set crds.enabled=true \
  --set global.leaderElection.namespace=cert-manager

Verify that cert-manager pods are running:

kubectl wait --namespace cert-manager \
  --for=condition=ready pod \
  --selector=app.kubernetes.io/instance=cert-manager \
  --timeout=120s

2. Install the AlloyDB Omni Operator

Deploy the AlloyDB Omni Kubernetes operator into the alloydb-omni-system namespace using Helm:

helm install alloydbomni-operator oci://gcr.io/alloydb-omni/alloydbomni-operator \
  --version 1.8.2 \
  --create-namespace \
  --namespace alloydb-omni-system \
  $(helm install --help | grep -q -- '--rollback-on-failure' && echo '--rollback-on-failure' || echo '--atomic') \
  --timeout 5m

Verify that the operator pods are healthy and running:

kubectl get pods -n alloydb-omni-system

5. Create a Single-Instance Database Cluster

In this step, you will create a dedicated application namespace and deploy a single-instance AlloyDB Omni DBCluster.

1. Create Namespace and Admin Credentials Secret

Create a namespace omni-demo for database workloads:

kubectl create namespace omni-demo

Create a Kubernetes Secret storing the password for the default postgres database administrator user:

kubectl apply -n omni-demo -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: db-pw-adbo
type: Opaque
data:
  adbo: "Q2hhbmdlTWUxMjM=" # Base64 for "ChangeMe123"
EOF

2. Deploy Single-Instance DBCluster

Create a single-instance DBCluster manifest:

kubectl apply -n omni-demo -f - <<EOF
apiVersion: alloydbomni.dbadmin.goog/v1
kind: DBCluster
metadata:
  name: adbo
spec:
  databaseVersion: "18.3.0"
  primarySpec:
    adminUser:
      passwordRef:
        name: db-pw-adbo
    resources:
      cpu: 1
      memory: 4Gi
      disks:
      - name: DataDisk
        size: 10Gi
EOF

3. Verify Cluster Readiness

Monitor the cluster status until DBCLUSTERPHASE reaches DBClusterReady. Initial provisioning can take several minutes: the operator must create the persistent volume and pull the database image, and on GKE Autopilot a new node may need to be provisioned first.

kubectl get dbcluster -n omni-demo -w

Press Ctrl+C to exit watch mode once DBCLUSTERPHASE reaches DBClusterReady.

Sample output:

NAME   PRIMARYENDPOINT   PRIMARYPHASE   DBCLUSTERPHASE   HAREADYSTATUS   HAREADYREASON
adbo   10.128.0.45       Ready          DBClusterReady

Note the PRIMARYENDPOINT IP address, which is the ClusterIP of the read-write Kubernetes Service al-adbo-rw-ilb. AlloyDB Omni listens on default PostgreSQL port 5432.

Inspect the resources that the operator reconciled from the single DBCluster manifest—the database Pod, the DataDisk PersistentVolumeClaim, and the al-adbo-rw-ilb Service:

kubectl get pods,svc,pvc -n omni-demo

6. Upgrade to High Availability (HA) and Enable Read-Only Standby

AlloyDB Omni provides built-in High Availability (HA) with streaming replication, automatic health monitoring, automated failover, and read-replica serving.

1. Enable HA and Read Replica Ability

Update the DBCluster specification to configure 1 standby instance and enable read-only standby routing:

kubectl patch dbcluster adbo -n omni-demo --type=merge -p '{
  "spec": {
    "availability": {
      "numberOfStandbys": 1,
      "enableStandbyAsReadReplica": true
    }
  }
}'

2. Verify HA Stabilization

Wait for the standby instance to provision and reach healthy streaming replication (HAREADYSTATUS reaches True and HAREADYREASON reaches Ready), then press Ctrl+C to exit watch mode:

kubectl get dbcluster adbo -n omni-demo -w

Check the HAReady status condition:

kubectl get dbcluster.alloydbomni.dbadmin.goog adbo -n omni-demo -o jsonpath='{.status.conditions[?(@.type == "HAReady")]}'

Verify that both read-write and read-only endpoints are published:

kubectl describe dbcluster adbo -n omni-demo | grep -A 8 "Endpoints:"

Sample output:

Endpoints:
  Name: Read-Write
  Value: 10.128.0.45:5432
  Name: Read-Only
  Value: 10.128.0.46:5432

The Read-Write endpoint (al-adbo-rw-ilb Service) routes to the primary database, while the Read-Only endpoint (al-adbo-ro-ilb Service) distributes read queries across standby instances.

7. Configure Automated BackupPlans (Local and GCS)

AlloyDB Omni provides physical backups and WAL archiving through the BackupPlan Custom Resource. You can configure backup retention, automated cron schedules, and backup targets (local persistent volumes or Google Cloud Storage).

1. Create Local BackupPlan

Create a BackupPlan that writes backups to local Kubernetes storage attached to the database instances:

kubectl apply -n omni-demo -f - <<EOF
apiVersion: alloydbomni.dbadmin.goog/v1
kind: BackupPlan
metadata:
  name: backupplan-local
spec:
  dbclusterRef: adbo
  backupSchedules:
    full: "0 2 * * *" # Daily at 02:00 UTC
    incremental: "0 */4 * * *" # Every 4 hours
  backupRetainDays: 7
EOF

Verify that the local BackupPlan is ready:

kubectl get backupplan backupplan-local -n omni-demo

Wait until PHASE reports Ready and NEXTBACKUPTIME is scheduled.

2. Create GCS BackupPlan (Path 1: Google Cloud Only — Optional)

To store backups externally in a Google Cloud Storage bucket, create a GCS bucket, configure a service account key secret, and apply a cloud BackupPlan.

  1. Create a Cloud Storage bucket:
export BUCKET_NAME="${PROJECT_ID}-omni-backups"
gcloud storage buckets create gs://${BUCKET_NAME} --location=${REGION}
  1. Create a service account with Storage Object Admin permissions, and create a key for it:

export SA_NAME="omni-backup-sa"
gcloud iam service-accounts create ${SA_NAME} --display-name="AlloyDB Omni Backup SA"

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member="serviceAccount:${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \
  --role="roles/storage.objectAdmin"

gcloud iam service-accounts keys create /tmp/gcs-key.json \
  --iam-account="${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
  1. Create the secret in your Kubernetes namespace:
kubectl create secret generic gcs-backup-secret \
  --from-file=key.json=/tmp/gcs-key.json \
  -n omni-demo
rm /tmp/gcs-key.json
  1. Apply the GCS BackupPlan manifest. The key field is the folder in the bucket that the operator writes backups to. It must start with /.
kubectl apply -n omni-demo -f - <<EOF
apiVersion: alloydbomni.dbadmin.goog/v1
kind: BackupPlan
metadata:
  name: backupplan-gcs
spec:
  dbclusterRef: adbo
  backupSchedules:
    full: "0 1 * * *"
    incremental: "0 */6 * * *"
  backupRetainDays: 14
  backupLocation:
    type: GCS
    gcsOptions:
      bucket: ${BUCKET_NAME}
      key: /omni-backups/adbo
      secretRef:
        name: gcs-backup-secret
        namespace: omni-demo
EOF

Verify the GCS BackupPlan status:

kubectl get backupplan backupplan-gcs -n omni-demo

Wait until PHASE reports Ready and NEXTBACKUPTIME is scheduled.

8. Insert Data, Trigger Backup, and Test Restore

In this step, you will populate initial data into the primary database, trigger an on-demand manual backup, add subsequent data, and restore from the backup to prove data rollback.

1. Populate Initial Data

Run a temporary PostgreSQL client pod to connect to the database through its read-write Service al-adbo-rw-ilb as the postgres user:

kubectl run pg-client --rm -i --tty --image=postgres:16 --restart=Never -n omni-demo -- \
  psql -h al-adbo-rw-ilb -U postgres -d postgres -c "
    CREATE TABLE customers (id SERIAL PRIMARY KEY, name TEXT, created_at TIMESTAMPTZ DEFAULT pg_catalog.now());
    INSERT INTO customers (name) VALUES ('Alpha Co'), ('Beta LLC');
    SELECT * FROM customers;
  "

When prompted for the password, enter ChangeMe123. This is the password you base64-encoded in the db-pw-adbo Secret in Step 5.

2. Trigger an On-Demand Backup

Create a manual Backup custom resource referencing your local BackupPlan:

kubectl apply -n omni-demo -f - <<EOF
apiVersion: alloydbomni.dbadmin.goog/v1
kind: Backup
metadata:
  name: initial-customer-backup
spec:
  dbclusterRef: adbo
  backupPlanRef: backupplan-local
  manual: true
EOF

Monitor the backup progress:

kubectl get backup initial-customer-backup -n omni-demo -w

Wait until PHASE transitions to Succeeded.

3. Mutate Data (Add New Records)

Insert additional records after the backup:

kubectl run pg-client --rm -i --tty --image=postgres:16 --restart=Never -n omni-demo \
  --env="PGPASSWORD=ChangeMe123" -- \
  psql -h al-adbo-rw-ilb -U postgres -d postgres -c "
    INSERT INTO customers (name) VALUES ('Gamma Inc'), ('Delta Corp');
    SELECT * FROM customers;
  "

The database now contains 4 rows.

4. Restore from Backup

Trigger a restore back to the state captured in initial-customer-backup:

kubectl apply -n omni-demo -f - <<EOF
apiVersion: alloydbomni.dbadmin.goog/v1
kind: Restore
metadata:
  name: restore-to-initial
spec:
  sourceDBCluster: adbo
  backup: initial-customer-backup
EOF

Monitor the restore operation:

kubectl get restore restore-to-initial -n omni-demo -w

Wait until PHASE reaches ProvisionSucceeded, and verify that the DBCluster returns to DBClusterReady:

kubectl get dbcluster adbo -n omni-demo -w

5. Verify Restored Data State

Query the customers table to verify only the pre-backup records exist:

kubectl run pg-client --rm -i --tty --image=postgres:16 --restart=Never -n omni-demo \
  --env="PGPASSWORD=ChangeMe123" -- \
  psql -h al-adbo-rw-ilb -U postgres -d postgres -c "
    SELECT * FROM customers;
  "

Output confirms only 2 rows (Alpha Co and Beta LLC) are present, verifying that the database was restored to the exact backup state.

9. Point-in-Time Recovery (PITR) to a Cloned Database

Point-in-Time Recovery (PITR) allows restoring a database to any arbitrary second within the recovery window using base backups and WAL stream logs, provisioning the restored data into a new cloned database cluster.

Because the operator continuously archives the Write-Ahead Log (WAL), PITR lets you recover from accidental human or application errors—for example, an unintended DELETE or DROP TABLE at 2:15:00 PM—by cloning the database to the exact second before the mistake happened (2:14:59 PM), without touching the original cluster.

1. Record Current Timestamp and Mutate Data

Retrieve the current UTC timestamp:

export PITR_TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
echo "PITR Target Timestamp: ${PITR_TIMESTAMP}"

Insert a test record that represents an unwanted modification after this timestamp:

kubectl run pg-client --rm -i --tty --image=postgres:16 --restart=Never -n omni-demo \
  --env="PGPASSWORD=ChangeMe123" -- \
  psql -h al-adbo-rw-ilb -U postgres -d postgres -c "
    INSERT INTO customers (name) VALUES ('Unwanted Record Post-Timestamp');
    SELECT * FROM customers;
  "

2. Perform Point-in-Time Restore

Apply the Restore Custom Resource configuring pointInTime and clonedDBClusterConfig:

kubectl apply -n omni-demo -f - <<EOF
apiVersion: alloydbomni.dbadmin.goog/v1
kind: Restore
metadata:
  name: restore-pitr-clone
spec:
  sourceDBCluster: adbo
  pointInTime: "${PITR_TIMESTAMP}"
  clonedDBClusterConfig:
    dbclusterName: adbo-cloned
EOF

Monitor the restore operation until PHASE reaches ProvisionSucceeded:

kubectl get restore restore-pitr-clone -n omni-demo -w

3. Verify Cloned Database

Once the restore completes, wait for the new cloned DBCluster to reach DBClusterReady (press Ctrl+C to exit watch mode):

kubectl get dbcluster adbo-cloned -n omni-demo -w

Query the cloned database adbo-cloned through its read-write Service al-adbo-cloned-rw-ilb:

kubectl run pg-client --rm -i --tty --image=postgres:16 --restart=Never -n omni-demo \
  --env="PGPASSWORD=ChangeMe123" -- \
  psql -h al-adbo-cloned-rw-ilb -U postgres -d postgres -c "
    SELECT * FROM customers;
  "

Notice that Unwanted Record Post-Timestamp is absent in the cloned cluster, demonstrating accurate recovery to the exact target point in time.

10. Deploy PgBouncer Connection Pooler

Connection pooling reduces database memory overhead and connection latency. The operator manages PgBouncer instances natively via the PgBouncer Custom Resource.

PostgreSQL forks a separate operating-system process for every client connection, so hundreds of concurrent connections from web services, microservices, or AI agents can exhaust database memory. PgBouncer sits in front of the database and multiplexes many short-lived client connections (up to max_client_conn) onto a small pool of long-lived PostgreSQL server connections (default_pool_size per user/database pair, capped by max_db_connections).

1. Deploy PgBouncer

Deploy a 2-replica PgBouncer pooler linked to cluster adbo:

kubectl apply -n omni-demo -f - <<EOF
apiVersion: alloydbomni.dbadmin.goog/v1
kind: PgBouncer
metadata:
  name: omni-pgbouncer
spec:
  dbclusterRef: adbo
  allowSuperUserAccess: true
  replicaCount: 2
  parameters:
    pool_mode: transaction
    default_pool_size: "20"
    max_client_conn: "500"
    max_db_connections: "100"
  podSpec:
    resources:
      cpu: 1
      memory: 1Gi
    image: "gcr.io/alloydb-omni/operator/g-pgbouncer:1.4.0"
  serviceOptions:
    type: ClusterIP
EOF

2. Verify PgBouncer Status

Watch the PgBouncer status until PHASE is Ready:

kubectl get pgbouncer omni-pgbouncer -n omni-demo -w

Check the running PgBouncer pods and service:

kubectl get pods -n omni-demo
kubectl get svc al-omni-pgbouncer-pgb-svc -n omni-demo

3. Connect via PgBouncer

Connect a client through the PgBouncer service on port 6432:

kubectl run pg-client --rm -i --tty --image=postgres:16 --restart=Never -n omni-demo \
  --env="PGPASSWORD=ChangeMe123" -- \
  psql -h al-omni-pgbouncer-pgb-svc -p 6432 -U postgres -d postgres -c "
    SELECT pg_catalog.version();
    SELECT * FROM customers;
  "

PgBouncer proxies the query seamlessly to the primary AlloyDB Omni database.

11. Deploy pgAdmin4 to Access the Database

You can run pgAdmin4 directly inside the Kubernetes cluster to provide a web-based administration console for querying, managing, and inspecting AlloyDB Omni.

1. Install pgAdmin4 via Helm

Install pgadmin4 in the omni-demo namespace:

helm install my-pgadmin oci://docker.io/dpage/pgadmin4-helm \
  --namespace omni-demo \
  --set ingress.enabled=false \
  --set image.tag=latest \
  --set auth.email="admin@example.com" \
  --set auth.password="AdminPassword123"

This chart names its Kubernetes resources pgadmin4 (Deployment, Service, PersistentVolumeClaim) and labels its Pods with app=pgadmin4, regardless of the Helm release name (my-pgadmin).

Verify that the pgAdmin4 pod is running:

kubectl wait --namespace omni-demo \
  --for=condition=ready pod \
  --selector=app=pgadmin4 \
  --timeout=300s

2. Forward Port and Access Web UI

Port-forward pgAdmin4 to your local environment or Cloud Shell:

kubectl port-forward service/pgadmin4 5050:80 -n omni-demo

kubectl port-forward keeps running in the foreground for as long as you use the pgAdmin4 web UI. Open a second terminal (or a new Cloud Shell tab) for other commands, and press Ctrl+C in this terminal when you are ready to move on to the next step.

Open the pgAdmin4 web interface:

  • Path 1 (Google Cloud Shell): Click the Web Preview button in the top right menu, select Change port, enter 5050, and click Change and Preview.
  • Path 2 (Local Workstation): Open http://localhost:5050 in your browser while the kubectl port-forward command is running.

Log in using:

  • Email: admin@example.com
  • Password: AdminPassword123

3. Register AlloyDB Omni in pgAdmin4

  1. In pgAdmin4, right-click Servers > Register > Server....
  2. Under the General tab:
    • Name: AlloyDB Omni Primary
  3. Under the Connection tab:
    • Host name/address: al-adbo-rw-ilb.omni-demo.svc.cluster.local (or al-omni-pgbouncer-pgb-svc.omni-demo.svc.cluster.local for PgBouncer)
    • Port: 5432 (or 6432 for PgBouncer)
    • Maintenance database: postgres
    • Username: postgres
    • Password: ChangeMe123
  4. Click Save and verify the active database session and tables.

12. Scale CPU and Memory with Low Downtime Maintenance (LDTM)

When vertically scaling compute and memory on a production database, traditional updates cause database restart disruptions. AlloyDB Omni provides Low Downtime Maintenance (LDTM) to roll updates through replicas with minimal application disruption.

1. Enable LDTM Annotation

Annotate the DBCluster to enable LDTM for updates:

kubectl annotate dbclusters.alloydbomni.dbadmin.goog adbo -n omni-demo dbcluster.dbadmin.goog/enableLDTM=true --overwrite

2. Scale CPU and Memory Resources

Update the primary resources from cpu: 1, memory: 4Gi to cpu: 2, memory: 8Gi:

kubectl patch dbcluster adbo -n omni-demo --type=merge -p '{
  "spec": {
    "primarySpec": {
      "resources": {
        "cpu": 2,
        "memory": "8Gi"
      }
    }
  }
}'

3. Monitor LDTM Scaling Progress

Monitor the rolling update and standby-to-primary switchover conditions:

kubectl get dbcluster adbo -n omni-demo -o yaml | grep -A 5 -B 2 "LDTMScalingInProgress"

Observe the pods rolling gracefully:

kubectl get pods -n omni-demo -w

LDTM prepares the updated standby first, verifies streaming replication, executes a fast switchover, and updates the remaining instance without service interruptions.

Verify updated resource allocation:

kubectl get dbcluster adbo -n omni-demo -o jsonpath='{.spec.primarySpec.resources}'

13. Clean Up Resources

To free cluster capacity and prevent unnecessary charges to your Google Cloud account, clean up the resources provisioned during this codelab.

If you are running the cleanup in a new terminal session (Path 1), the environment variables from earlier steps are no longer set. Re-export them with the same values you used before:

export PROJECT_ID="<YOUR_PROJECT_ID>"
export REGION="us-central1"
export CLUSTER_NAME="omni-autopilot-cluster"
export BUCKET_NAME="${PROJECT_ID}-omni-backups"
export SA_NAME="omni-backup-sa"
gcloud config set project ${PROJECT_ID}

1. Delete Database Workloads (Path 1 and Path 2)

Mark both clusters as deleted to pass admission webhook checks, wait for the operator to remove the DBCluster resources, and then delete the namespace:

kubectl patch dbcluster adbo -n omni-demo --type=merge -p '{"spec":{"isDeleted":true}}'
kubectl patch dbcluster adbo-cloned -n omni-demo --type=merge -p '{"spec":{"isDeleted":true}}'
kubectl wait --for=delete dbcluster/adbo dbcluster/adbo-cloned -n omni-demo --timeout=300s
kubectl delete namespace omni-demo

If you used your own Kubernetes cluster (Path 2) and also want to remove the AlloyDB Omni operator and cert-manager:

helm uninstall alloydbomni-operator -n alloydb-omni-system
kubectl delete namespace alloydb-omni-system
helm uninstall cert-manager -n cert-manager
kubectl delete namespace cert-manager

2. Delete GCS Bucket and IAM Service Account (Path 1 Only)

If you created the Google Cloud Storage bucket and service account in Path 1:

gcloud storage rm --recursive gs://${BUCKET_NAME}
gcloud projects remove-iam-policy-binding ${PROJECT_ID} \
  --member="serviceAccount:${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \
  --role="roles/storage.objectAdmin"
gcloud iam service-accounts delete ${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com --quiet

3. Delete GKE Cluster (Path 1 Only)

If you provisioned a GKE Autopilot cluster in Path 1:

gcloud container clusters delete ${CLUSTER_NAME} --region=${REGION} --quiet

14. Congratulations

Congratulations! You have completed the AlloyDB Omni on Kubernetes codelab.

What we've covered

  • Provisioned a GKE Autopilot cluster (Path 1) or prepared an existing Kubernetes cluster (Path 2).
  • Deployed cert-manager and the AlloyDB Omni Kubernetes operator via Helm.
  • Deployed a single-instance AlloyDB Omni DBCluster.
  • Upgraded the cluster to High Availability (HA) with synchronous standbys and enabled read-only standby routing.
  • Created automated BackupPlan resources for both local persistent storage and Google Cloud Storage (GCS).
  • Performed on-demand backups and validated database restores.
  • Executed Point-in-Time Recovery (PITR) to a new cloned database cluster.
  • Deployed a PgBouncer connection pooler for scalable client connections.
  • Deployed and connected pgAdmin4 for database management.
  • Executed Low Downtime Maintenance (LDTM) to dynamically scale compute and memory resources.

Next Steps

15. Survey

How will you use this tutorial?

Only read through it Read it and complete the exercises