This Terraform module creates:
- a custom VPC, regional subnet, and firewall rules
- Compute Engine instances and persistent disks for MongoDB and optional supporting services
- a Cloud Storage backup bucket and lifecycle rule
- a PBM service account, HMAC key, and bucket IAM binding
- generated Ansible inventory and SSH configuration files
- Terraform 1.9 or newer
- Ansible and OpenSSH
- an existing SSH key pair
- a Google Cloud project with billing enabled
- a project administrator who can enable APIs, create service accounts and keys, and grant project IAM roles
Install the local tools and Google Cloud CLI from the repository root:
./scripts/install-prerequisites.sh --gcpRun the following bootstrap commands as a project administrator. Replace the project ID and choose a unique service-account name if necessary.
- Select the project and enable the APIs used by the Terraform resources:
export PROJECT_ID=my-gcp-project
export DEPLOY_SA=mongodb-terraform-deployer
gcloud config set project "$PROJECT_ID"
gcloud services enable \
compute.googleapis.com \
storage.googleapis.com \
iam.googleapis.com \
--project "$PROJECT_ID"- Create the deployment service account:
gcloud iam service-accounts create "$DEPLOY_SA" \
--display-name="MongoDB Terraform deployer" \
--project "$PROJECT_ID"
export DEPLOY_SA_EMAIL="${DEPLOY_SA}@${PROJECT_ID}.iam.gserviceaccount.com"- Grant the project roles required by the resources in this module:
for role in \
roles/browser \
roles/compute.admin \
roles/storage.admin \
roles/iam.serviceAccountAdmin \
roles/storage.hmacKeyAdmin
do
gcloud projects add-iam-policy-binding "$PROJECT_ID" \
--member="serviceAccount:${DEPLOY_SA_EMAIL}" \
--role="$role"
doneThese roles let Terraform inspect the project; create networks, firewalls, instances, and disks; create the backup bucket and IAM binding; and create the separate PBM service account and HMAC key. If organizational policy prohibits service-account keys or requires custom roles, use an approved workload identity with equivalent permissions for manual Terraform runs. The Web UI currently requires a service-account JSON key.
- Create a JSON key in a protected location and authenticate:
gcloud iam service-accounts keys create "$HOME/.config/gcloud/mongodb-terraform.json" \
--iam-account="$DEPLOY_SA_EMAIL" \
--project "$PROJECT_ID"
export GOOGLE_APPLICATION_CREDENTIALS="$HOME/.config/gcloud/mongodb-terraform.json"
gcloud auth activate-service-account "$DEPLOY_SA_EMAIL" \
--key-file="$GOOGLE_APPLICATION_CREDENTIALS" \
--project="$PROJECT_ID"
gcloud auth list --filter=status:ACTIVE
gcloud auth print-access-token >/dev/nullFor the Web UI, upload this JSON key and enter PROJECT_ID in Settings. The
UI stores the key under ui-go/secrets/cloud/gcp/, uses an isolated Cloud SDK
configuration, and sets GOOGLE_APPLICATION_CREDENTIALS for Terraform.
For an interactive manual deployment, Application Default Credentials also work:
gcloud auth application-default loginChange into the GCP Terraform directory:
cd terraform/gcpReview variables.tf, then put overrides in terraform.tfvars or another tfvars
file. At minimum, review:
project_id,prefix,region,clusters, andreplsetsgce_ssh_users,ssh_private_key_path, andmy_ssh_user- machine types, image, disk sizes, and
use_spot_instances - backup bucket naming and retention
source_rangesfor inbound access- optional PMM, CA/TLS, LDAP, and YCSB settings
The checked-in minimum.tfvars is the smallest standalone
replica-set example. The SSH user must match a key in gce_ssh_users. Supply
GCP credentials through Application Default Credentials or the provider
environment, not this file.
project_id = "my-gcp-project"
prefix = "myenv"
my_ssh_user = "ubuntu"
gce_ssh_users = { ubuntu = "/absolute/path/to/id_ed25519.pub" }
ssh_private_key_path = "/absolute/path/to/id_ed25519"
clusters = {}
enable_pmm = false
replsets = {
rs01 = {
enable_pmm = false
enable_pbm = false
}
}Save the example as minimum.tfvars or use the checked-in file and pass
-var-file=minimum.tfvars to Terraform commands.
Resource names must be unique in the project. Some firewall names are fixed, so
deploying multiple copies of this Terraform root in one project can cause naming
collisions even when prefix differs.
Initialize and review the Terraform plan before applying it:
terraform init
terraform plan
terraform applyWhen using a non-default variable file, pass it consistently:
terraform plan -var-file=my-deployment.tfvars
terraform apply -var-file=my-deployment.tfvarsTerraform creates one inventory and SSH config per topology:
<prefix>_inventory_<cluster-or-replset><prefix>_ssh_config_<cluster-or-replset>
Optionally append a generated SSH configuration to your local configuration:
cat myenv_ssh_config_cl01 >> ~/.ssh/configRun Ansible directly against the generated inventory from this directory:
ansible-playbook -i myenv_inventory_cl01 ../../ansible/main.ymlTypical provisioning takes about 1 minute for the infrastructure and about 15 minutes for Ansible to configure a 2-shard cluster.
If you appended the generated SSH configuration, connect by host alias:
ssh my-cluster-name-mongodb-cfg01Percona ClusterSync is disabled by default. Set enable_pcsm=true to create one dedicated e2-small VM in the environment VPC. Only SSH is allowed inbound; API port 2242 is not exposed. Terraform never receives PCSM connection URIs or passwords. The package version defaults to pcsm_version="0.9.0".
Set source and target kinds to cluster or replset; they must match and the names must differ. Terraform writes one normal inventory per topology plus <prefix>_inventory_pcsm. Run Ansible for each selected topology, then run pcsm.yml against that PCSM inventory. Store the required PCSM URIs and passwords in an owner-only environment file. See the Ansible ClusterSync instructions for the complete procedure.
For example, after applying the Terraform configuration, run Ansible for both
selected topologies and create a controller-side environment file with mode
0600:
ansible-playbook -i myenv_inventory_rs-source ../../ansible/main.yml
ansible-playbook -i myenv_inventory_rs-target ../../ansible/main.yml
umask 077
cat > /secure/myenv/pcsm.env <<'EOF'
PCSM_SOURCE_URI=...
PCSM_TARGET_URI=...
PCSM_SOURCE_PASSWORD=...
PCSM_TARGET_PASSWORD=...
EOF
ansible-playbook -i myenv_inventory_pcsm ../../ansible/pcsm.yml \
-e pcsm_env_file_source=/secure/myenv/pcsm.envThis minimal example creates two PSMDB replica sets and a PCSM VM. prefix must start with a lowercase letter, contain only lowercase letters and digits, and be at most 14 characters. The key in gce_ssh_users must match my_ssh_user. GCP credentials are supplied through the Google provider environment or application-default credentials, not this file.
Save it as pcsm.tfvars and pass -var-file=pcsm.tfvars to terraform plan and terraform apply.
project_id = "my-gcp-project"
prefix = "myenv"
my_ssh_user = "ubuntu"
gce_ssh_users = { ubuntu = "/absolute/path/to/id_ed25519.pub" }
ssh_private_key_path = "/absolute/path/to/id_ed25519"
clusters = {}
enable_pmm = false
replsets = {
"rs-source" = { enable_pmm = false, enable_pbm = false }
"rs-target" = { enable_pmm = false, enable_pbm = false }
}
enable_pcsm = true
pcsm_source_kind = "replset"
pcsm_source_name = "rs-source"
pcsm_target_kind = "replset"
pcsm_target_name = "rs-target"Terraform creates a separate PBM service account named
<prefix>-mongo-backup-sa, grants it access to the created bucket, and creates
an HMAC key. This is not the deployment service account. Inspect outputs with:
terraform output -jsonThe JSON deployment key and PBM HMAC secret are sensitive. The PBM secret is stored in Terraform state and generated inventory files. Keep keys, state, tfvars, inventories, SSH configuration, and UI secret directories out of source control and restrict their filesystem permissions.
Instances receive public IP addresses. The default source_ranges value is
0.0.0.0/0, and ICMP is publicly allowed. Before deployment, restrict SSH source
ranges to trusted addresses and review all firewall rules. The defaults are
intended for disposable test environments, not production.
Destroy with the same variables used for the apply:
terraform destroy
# Or: terraform destroy -var-file=my-deployment.tfvarsThe backup bucket uses force_destroy, so destroying the deployment also deletes
its backup objects. Remove generated inventory and SSH files after destruction if
they are no longer needed.
Supported scale-out changes are additive only:
- Increase
shard_countto add shards to an existing sharded cluster. - Increase
data_nodes_per_replsetto add data-bearing members to a standalone replica set. - Add a new sharded cluster or standalone replica set.
After editing variables, run terraform apply to create the new instances and
regenerate inventory files. Then run the matching Ansible scale-out playbook from
the repository root:
ansible-playbook -i terraform/gcp/myenv_inventory_cl01 ansible/add_shard.yml \
--extra-vars "new_shard_group=shard3"
ansible-playbook -i terraform/gcp/myenv_inventory_rs01 ansible/add_replset_member.yml \
--extra-vars "target_replset=rs01"For an entirely new cluster or replica set, run ansible/main.yml against its
generated inventory. Reducing topology size, changing configsvr_count, changing
shardsvr_replicas, and changing arbiter counts are not implemented.