1. Introduction
This codelab demonstrates AlloyDB Omni high availability (HA) cluster deployment on Google Compute Engine (GCE) Virtual Machines (VMs). At the end of this codelab, you will provision a HA reference architecture consisting of 3 Database nodes and 2 HAProxy nodes, along with a control node for management operations.
Prerequisites
- Access to a Google Cloud Project and Cloud Shell from Cloud Console.
- Google Cloud SDK (
gcloud) installed and configured. For details on installing gcloud, refer to gcloud-install - Terraform v1.9.8 installed.
What you'll learn
- How to create and prepare GCE VMs for AlloyDB Omni.
- How to install and run AlloyDB Omni RPM Orchestrator.
- How to install and configure AlloyDB Omni RPMs for HA reference architecture.
What you'll need
- Obtain URL link to AlloyDB Omni RPMs and RPM orchestrator. For this, you need to fill the alloydb omni signup form. The links are sent to your email which repository URL server. Initialize following environment variables to keep the URLs handy which will be used during the codelab.
export ORCHESTRATOR_ANSIBLE_COLLECTION_PATH="..." export ALLOYDB_OMNI_REPOSITORY_URL="..." export ALLOYDB_OMNI_ORCHESTRATOR_REPOSITORY_URL="..." export ALLOYDB_OMNI_COMMON_REPOSITORY_URL=.... export ETCD_REPOSITORY_URL="..." - A working terminal with access to the AlloyDB Omni deployment stack. You can use cloud shell for this purpose.
2. Setup and Requirements
Project setup
Create a Google Cloud Project
- In the Google Cloud Console, on the project selector page, select or create a Google Cloud project.
- Make sure that billing is enabled for your Cloud project. Learn how to check if billing is enabled on a project.
Start Cloud Shell
While Google Cloud can be operated remotely from your laptop, in this codelab you will be using Google Cloud Shell, a command line environment running in the Cloud.
From the Google Cloud Console, click the Cloud Shell icon on the top right toolbar:

Alternatively you can press G then S. This sequence will activate Cloud Shell if you are within the Google Cloud Console or use this link.
It should only take a few moments to provision and connect to the environment. When it is finished, you should see something like this:

This virtual machine is loaded with all the development tools you'll need. It offers a persistent 5GB home directory, and runs on Google Cloud, greatly enhancing network performance and authentication. All of your work in this codelab can be done within a browser. You don't need to install anything.
3. Create Google Cloud Compute Engine Virtual Machines
Prepare Terraform scripts
- Define environment variables for your project ID and desired cluster name. You will use these throughout the codelab.
Note: Google Cloud project ID should be between 6 to 30 characters length only. For more information, refer to https://docs.cloud.google.com/resource-manager/docs/creating-managing-projects#before_you_beginexport PROJECT="your-project-id" export CLUSTER="your-cluster-name" - Ensure that you have logged in with google cloud account user.
gcloud auth login - Create a working directory for your deployment and copy the required Terraform configuration files from your repository source.
mkdir -p ~/alloydb-omni/$PROJECT/$CLUSTER cd ~/alloydb-omni/$PROJECT/$CLUSTER gcloud storage cp gs://alloydb-omni-install/rpm-orchestrator/gce/terraform/*.tf . - Create a
terraform.tfvarsfile to specify the required parameters as per the reference architecture as per the following contents:cat > terraform.tfvars <<EOF # Required instance counts for reference architecture db_instance_count = 3 haproxy_instance_count = 2 control_instance_count = 1 # Optional: Customize if needed with the below variables # os_image = "rocky-linux-cloud/rocky-linux-9" # zone = "us-west4-c" # region_1 = "us-west4" # db_instance_type = "c4-highmem-4" # db_disk_type = "hyperdisk-balanced" # db_data_size = "50" # GB # data_dir = "/data" EOF
Execute Terraform scripts and Validate
- You can now provision the VMs.
terraform init - Before you create VMs, ensure that you have the required access to create VMs and other resources. In summary you will need the following permissions.
roles/compute.admin roles/iam.roleAdmin roles/compute.osAdminLogin roles/iam.serviceAccountCreator roles/iam.serviceAccountUser roles/artifactregistry.repoAdmin roles/storage.objectUser roles/resourcemanager.projectIamAdmin roles/serviceusage.serviceUsageAdmin - Validate the configuration and apply the configuration to provision the resources.
Note: Ensure you are using Terraform v1.9.8 as expected by the deployment configuration.terraform validate terraform apply --auto-approve - Once Terraform completes, verify that the virtual machines have been successfully created by listing the created instances using
gcloud. You should see instances corresponding to your 3 DB nodes, 2 HAProxy nodes, and the control VM and corresponding zones. Record the ZONE for the control node. We will need this during this codelab, later.gcloud compute instances list --filter="name~$CLUSTER" --project=$PROJECTexport ZONE=$(gcloud compute instances list \ --filter="name=$CLUSTER-control" \ --format="value(zone)" --project=$PROJECT)
4. Prepare the VMs for the deployment
You need to create a SSH session to the control node and perform steps to enable SSH access to all the VMs (also termed as nodes).
- Ensure that the environment variables for your project and cluster are defined.
export PROJECT="your-project-id" export CLUSTER="your-cluster-name" - Create SSH key and add the same for logging onto the control VM.
# Replace values with your specific GCP project, cluster and zone details ssh-keygen -t ed25519 -f $HOME/.ssh/google_compute_engine gcloud compute os-login ssh-keys add --key-file=$HOME/.ssh/google_compute_engine.pub --project=$PROJECT - Create firewall rule to allow SSH connections and also allow VRRP traffic.
gcloud compute config-ssh --project=$PROJECT gcloud compute firewall-rules create $CLUSTER-allow-ssh --network=$CLUSTER --project=$PROJECT --direction=INGRESS --action=allow --rules=tcp:22 --source-ranges="0.0.0.0/0" gcloud compute firewall-rules create $CLUSTER-allow-vrrp --network=$CLUSTER --project=$PROJECT --allow=112 --source-ranges="0.0.0.0/0" - Connect to the control VM over SSH:
gcloud compute ssh "$CLUSTER-control" --zone=$ZONE --project=$PROJECT - Create Linux group on the control node with the same name as the username:
sudo groupadd $(id -un) sudo usermod -aG $(id -un) $(id -un) - Terraform setup creates a few configuration scripts and stage them in the
/tmp/directory of the control VM which includes things like cluster name, service account, project name, etc.Create password less ssh access from control nodes to all the cluster nodes using setup scripts on the control node. Important: Note down service_account user. We will be using this as SSH_USER later in this codelab./tmp/setup-ssh-for-cluster.sh - For this codelab, we can disable SELinux on all the nodes. Terraform script adds ‘/tmp/run-all.sh' which can be used for this purpose.
/tmp/run-all.sh sudo setenforce 0 - If you have signed up for AlloyDB Omni and obtained the links, it is time to add those URLS to environment variables as well.
Decide on a virtual IP for your environment from the cidr_range input variable in the filecat >> ~/.codelab.env <<EOF export ORCHESTRATOR_ANSIBLE_COLLECTION_PATH="..." export ALLOYDB_OMNI_REPOSITORY_URL="..." export ALLOYDB_OMNI_ORCHESTRATOR_REPOSITORY_URL="..." export ALLOYDB_OMNI_COMMON_REPOSITORY_URL=.... export ETCD_REPOSITORY_URL="..." EOFterraform/variables.tfsuch that it does not conflict with the other nodes, as shown in the following example:cat >> ~/.codelab.env <<EOF export VIRTUAL_IP="10.1.0.50" EOF
5. Install required software components on all the VMs
Next step is to install required SW components on the VMs. This can be coordinated on the control node. All the following commands need to be executed on the control node.
- Connect to the control VM over SSH, if not already on the control node.
Once you are on the control VM ssh prompt, source environment file.gcloud compute ssh "$CLUSTER-control" --zone=$ZONE --project=$PROJECTsource ~/.codelab.env - On the control node, install Ansible and the required Python libraries.
sudo dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm -y sudo dnf install -y ansible sudo dnf install -y python3-grpcio python3-protobuf python3-googleapis-common-protos python3-grpcio-status - Next, download the RPM Orchestrator Ansible collection tar file, and install the same.
Note: Ensure ORCHESTRATOR_ANSIBLE_COLLECTION_PATH variable has "/" in the end.gcloud storage cp "gs://${ORCHESTRATOR_ANSIBLE_COLLECTION_PATH#https://storage.googleapis.com/}google-alloydbomni_orchestrator-*.tar.gz" . ansible-galaxy collection install google-alloydbomni_orchestrator-0.1.0-6.tar.gz ansible-galaxy collection list | grep alloydbomni_orchestrator - The orchestrator uses a deployment specification file in Ansible inventory format to understand your cluster topology. Create a file named deployment_spec.yaml with your node details on the control node.
Note: Review the generated file to ensure it refers to valid values.cat > deployment_spec.yaml <<EOF alloydbomni: vars: cluster_manager: name: "$CLUSTER" etcd: setup: true config_forcewrite: true alloydbomni: major_version: "18" repo_url: $ALLOYDB_OMNI_REPOSITORY_URL alloydbomni_monitor: repo_url: $ALLOYDB_OMNI_COMMON_REPOSITORY_URL alloydbomni_cluster_manager: repo_url: $ALLOYDB_OMNI_ORCHESTRATOR_REPOSITORY_URL alloydbomni_node_manager: repo_url: $ALLOYDB_OMNI_ORCHESTRATOR_REPOSITORY_URL pgbouncer: repo_url: $ALLOYDB_OMNI_COMMON_REPOSITORY_URL pgbackrest: repo_url: $ALLOYDB_OMNI_COMMON_REPOSITORY_URL children: primary_instance_nodes: hosts: $CLUSTER-db1: $CLUSTER-db2: $CLUSTER-db3: load_balancer_nodes: hosts: $CLUSTER-haproxy1: $CLUSTER-haproxy2: EOF - Create a playbook named install.yaml that references the install role from the orchestrator collection.
Note: Review the generated file to ensure it refers to valid values.cat > install.yaml <<EOF - name: Install AlloyDB Omni cluster components hosts: all vars: ansible_become: true ansible_user: $SSH_USER ansible_ssh_private_key_file: $HOME/ssh-key-cluster-sa roles: - role: google.alloydbomni_orchestrator.install EOF - Execute the playbook using your inventory file to download and install the RPMs across all specified nodes.
ansible-playbook -i deployment_spec.yaml install.yaml
6. Bootstrap AlloyDB Omni Cluster
At this stage, we have installed all the required components on all the nodes. We are ready to bootstrap AlloyDB Omni cluster.
- Connect to the control VM over SSH, if not already on the control node.
Once you are on the control VM ssh prompt, source environment file.gcloud compute ssh "$CLUSTER-control" --zone=$ZONE --project=$PROJECTsource ~/.codelab.env - Generate a hash for your password and note down the same.
encoded_password=$(echo -n "your unique password" | base64) - To create cluster, AlloyDB Omni must know how to configure it. Create a filename dbcluster.yaml for the DB cluster specifications.
cat > dbcluster.yaml <<EOF Secret: metadata: name: db-pw-$CLUSTER spec: type: Opaque data: $CLUSTER: $encoded_password --- DBCluster: metadata: name: $CLUSTER spec: databaseVersion: 18.1.0 mode: "" availability: numberOfStandbys: 2 enableAutoFailover: true enableAutoHeal: true autoFailoverTriggerThreshold: 2 autoHealTriggerThreshold: 2 healthcheckPeriodSeconds: 5 replayReplicationSlotsOnStandbys: false primarySpec: adminUser: passwordRef: name: db-pw-$CLUSTER resources: cpu: 4 memory: 32Gi disks: - name: DataDisk path: $PGDATA dbLoadBalancerOptions: gcp: loadBalancerIP: "$VIRTUAL_IP" loadBalancerType: "internal" loadBalancerInterface: "eth0" EOF - Create a playbook named bootstrap.yaml, which will refer to the bootstrap ansible role for creating AlloyDB Omni Cluster.
cat > bootstrap.yaml <<EOF - name: Create DBCluster hosts: localhost vars: ansible_become: true ansible_user: $SSH_USER ansible_ssh_private_key_file: $HOME/ssh-key-cluster-sa roles: - role: google.alloydbomni_orchestrator.bootstrap EOF - Run your playbook to create cluster
ansible-playbook bootstrap.yaml -i deployment_spec.yaml -e resource_spec=dbcluster.yaml
7. (Optional) Configure PgBouncer Connection Pooler
AlloyDB Omni supports lightweight connection pooling using PgBouncer. You can configure and bootstrap PgBouncer right after your cluster is provisioned.
- Create a resource specification file named pgbouncer.yaml that associates the connection pooler with your database cluster:
cat > pgbouncer.yaml <<EOF PgBouncer: metadata: name: pgbouncer-pooler spec: dbclusterRef: $CLUSTER allowSuperUserAccess: true accessMode: "rw" port: 6432 EOF - Bootstrap the PgBouncer pooler using the same bootstrap.yaml playbook created earlier, passing the new specification file:
ansible-playbook bootstrap.yaml -i deployment_spec.yaml -e resource_spec=pgbouncer.yaml
8. Verify the AlloyDB Omni Cluster
To verify that your cluster is functioning correctly and accessible using the load balancer, you can connect to it using the standard PostgreSQL client from the control node.
- Install the PostgreSQL 18 client repository and package on the control node:
sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm sudo dnf install -y postgresql18 - Connect to the cluster using the virtual IP reserved earlier. You will be prompted for the password you encoded in dbcluster.yaml:
/usr/pgsql-18/bin/psql -h $VIRTUAL_IP -U postgres -W - Once connected, you can run basic SQL queries to verify the cluster state, for example, checking the database version:
You should see output indicating PostgreSQL 18 running with AlloyDB Omni. Typepostgres=# SELECT version();\qto exit the prompt.
9. (Optional) Back up Data using pgBackRest
AlloyDB Omni integrates with pgBackRest to manage backups directly to Cloud Storage. You can configure a backup plan and trigger an on-demand backup to the GCS bucket created by your Terraform setup.
- Create a backup plan specification file named backup_plan.yaml pointing to your provisioned GCS bucket:
cat > backup_plan.yaml <<EOF BackupPlan: metadata: name: pgb-plan spec: dbclusterRef: $CLUSTER backupLocation: type: GCS gcsOptions: bucket: $CLUSTER-gcs-backups key: /backups EOF - Create an Ansible playbook named backup.yaml that references the backup management role:
cat > backup.yaml <<EOF - name: Manage AlloyDB Omni Backups hosts: localhost vars: ansible_become: true ansible_user: $SSH_USER ansible_ssh_private_key_file: $HOME/ssh-key-cluster-sa roles: - role: google.alloydbomni_orchestrator.backup EOF - Apply the backup plan using the backup.yaml playbook:
ansible-playbook backup.yaml -i deployment_spec.yaml -e resource_spec=backup_plan.yaml - Once the plan is successfully established, create an on-demand backup resource file named create_backup.yaml.
cat > create_backup.yaml <<EOF Backup: metadata: name: on-demand-backup spec: backupPlanRef: pgb-plan dbclusterRef: $CLUSTER EOF - Execute the playbook to initiate the backup:
ansible-playbook backup.yaml -i deployment_spec.yaml -e resource_spec=create_backup.yaml - To verify backup's status, create a status.yaml playbook:
- name: Fetch AlloyDB Omni Resource Status
hosts: localhost
vars:
ansible_become: true
ansible_user: $SSH_USER
ansible_ssh_private_key_file: $HOME/ssh-key-cluster-sa
roles:
- role: google.alloydbomni_orchestrator.status
EOF
- Run the playbook to list all backups:
ansible-playbook status.yaml -i deployment_spec.yaml -e resource_type=Backup
- Alternatively, to get detailed info on a specific backup created earlier, pass
-e resource_name=on-demand-backup:
ansible-playbook status.yaml -i deployment_spec.yaml \
-e resource_type=Backup \
-e resource_name=on-demand-backup
10. Cleanup Resources
When you are finished with the deployment, you can destroy the provisioned resources to avoid incurring charges.
- Create a playbook named teardown.yaml:
cat > teardown.yaml <<EOF - name: Tear down AlloyDB Omni cluster hosts: localhost vars: ansible_become: true ansible_user: $SSH_USER ansible_ssh_private_key_file: $HOME/ssh-key-cluster-sa roles: - role: google.alloydbomni_orchestrator.delete EOF - Execute the playbook using ansible-playbook. If you configured backups, delete the Backup and BackupPlan resources first:
If you configured PgBouncer, delete the connection pooler resource next:ansible-playbook teardown.yaml -i deployment_spec.yaml -e "resource_type=Backup" -e "resource_name=on-demand-backup" ansible-playbook teardown.yaml -i deployment_spec.yaml -e "resource_type=BackupPlan" -e "resource_name=pgb-plan" Then, specify DBCluster as the resource_type and delete the database cluster itself:ansible-playbook teardown.yaml -i deployment_spec.yaml -e "resource_type=PgBouncer" -e "resource_name=pgbouncer-pooler"ansible-playbook teardown.yaml -i deployment_spec.yaml -e "resource_type=DBCluster" -e "resource_name=$CLUSTER" - Once the cluster is deleted, log out from the control node, switch back to your terminal and navigate to your Terraform work directory.
Note: if you have freshly logged onto the cloud shell, then remember to set these:export PROJECT="your-project-id" export CLUSTER="your-cluster-name" - Delete the VRRP firewall rule and destroy the resources managed by Terraform:
gcloud compute firewall-rules delete -q "$CLUSTER-allow-vrrp" --project="$PROJECT" gcloud compute firewall-rules delete -q "$CLUSTER-allow-ssh" --project="$PROJECT" terraform destroy - Confirm the destruction when prompted. Since lingering network resources or routes might occasionally prevent complete teardown, run the following safe cleanup commands to ensure all associated firewall rules, NAT gateways, routers, routes, subnets, and networks are fully removed. Replace
REGIONwith your specific deployment region, such as ‘us-central1':# Delete any remaining firewall rules associated with the cluster gcloud compute firewall-rules list --project=$PROJECT 2> /dev/null | grep ^$CLUSTER- | cut -f1 -d' ' | \ while read rule; do gcloud compute firewall-rules delete --project=$PROJECT --quiet $rule; done # Delete the Cloud NAT gateway and router if they still exist gcloud compute routers nats describe $CLUSTER-nat-gw --router=$CLUSTER-router --region=REGION --project=$PROJECT 2>/dev/null \ && gcloud compute routers nats delete $CLUSTER-nat-gw --router=$CLUSTER-router --region=REGION --project=$PROJECT --quiet gcloud compute routers describe $CLUSTER-router --region=REGION --project=$PROJECT 2>/dev/null \ && gcloud compute routers delete $CLUSTER-router --region=REGION --project=$PROJECT --quiet # Delete any remaining custom routes gcloud compute routes list --project=$PROJECT --filter="network:$CLUSTER" --format="value(name)" 2>/dev/null | \ while read route; do gcloud compute routes delete --project=$PROJECT --quiet $route 2>/dev/null || true; done # Delete the subnet and network if they still exist gcloud compute networks subnets describe $CLUSTER --region=REGION --project=$PROJECT 2>/dev/null \ && gcloud compute networks subnets delete $CLUSTER --region=REGION --project=$PROJECT --quiet gcloud compute networks describe $CLUSTER --project $PROJECT 2> /dev/null \ && gcloud compute networks delete $CLUSTER --project $PROJECT --quiet
11. Congratulations
Congratulations for completing the codelab.
What we've covered
- How to create and prepare GCE VMs for AlloyDB Omni.
- How to install and run AlloyDB Omni RPM Orchestrator.
- How to install and configure AlloyDB Omni RPMs for HA reference architecture.
You can read more about AlloyDB Omni in the documentation.