Validated Learning Experiment: Successfully proven nginx TCP proxy approach for cross-project AlloyDB connectivity, bypassing GCP's transitive VPC peering limitation.
β VALIDATED - PRODUCTION READY
This repository contains a complete validated learning experiment demonstrating cross-project AlloyDB connectivity using an nginx TCP proxy VM. The approach has been tested and validated with:
- β 100% success rate across all test scenarios
- β 40ms average database connection time
- β ~6ms read query latency
- β ~10ms write query latency
- β Zero downtime implementation
- β Cost-effective (~$10/month for proxy infrastructure)
π Full Results: See EXPERIMENT_RESULTS.md for comprehensive validation data and findings.
When AlloyDB is deployed with Private Service Access (PSA) in Project A, and you need to connect from Cloud Run in Project B, direct VPC peering fails due to GCP's transitive peering limitation.
β What Doesn't Work:
Cloud Run (Project B)
β VPC Connector
β Project B VPC
β [VPC Peering]
β Project A VPC
β [β Cannot traverse]
β Google-managed VPC (AlloyDB PSA)
Traffic cannot traverse multiple VPC peering connections.
Place an nginx proxy VM in Project A's VPC that has access to AlloyDB via PSA:
Cloud Run (Project B)
β VPC Connector (10.8.0.0/28)
β Project B VPC (10.2.0.0/20)
β [VPC Peering - ACTIVE]
β Project A VPC (10.1.0.0/20)
β nginx Proxy VM (10.1.0.2:5432) β
β AlloyDB (10.170.0.2:5432) β
Why It Works: The proxy VM terminates the connection in Project A, where it has direct PSA access to AlloyDB.
ββββββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββ
β PROJECT B β PROJECT A β
β β β
β ββββββββββββββββ β ββββββββββββββββ β
β β Cloud Run β β βnginx Proxy VMβ β
β β Flask App β β βPort 5432 β β
β ββββββββ¬ββββββββ β ββββββββ¬ββββββββ β
β β β β β
β βΌ β βΌ β
β ββββββββββββββββ β ββββββββββββββββ β
β βVPC Connector β β β AlloyDB β β
β β10.8.0.0/28 β β β10.170.0.2 β β
β ββββββββ¬ββββββββ β ββββββββββββββββ β
β β β β² β
β βΌ β β β
β ββββββββββββββββ β β β
β β Project B β VPC Peering β Private Service β
β β VPC ββββββββββββββββββΌββΊ Access (PSA) β
β β10.2.0.0/20 β β β
β ββββββββββββββββ β β
ββββββββββββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββββ
Project A (Database):
- AlloyDB cluster (PostgreSQL 16.9)
- nginx TCP proxy VM (e2-micro)
- VPC with Private Service Access
- Firewall rules for cross-project access
Project B (Application):
- Cloud Run service with Flask test app
- Serverless VPC Connector
- VPC peered to Project A
Phase 3 (Connectivity):
- Bidirectional VPC peering
- Firewall rules for both VPC and Connector CIDRs
- Custom route export/import
| Document | Description |
|---|---|
| EXPERIMENT_RESULTS.md | Complete validation results, performance metrics, findings |
| USAGE.md | API reference, testing guide, load testing instructions |
| PROXY_SETUP_GUIDE.md | Quick guide to add proxy to existing infrastructure |
| ADR-001 | Architecture decision record explaining the approach |
- Two GCP projects (Project A for AlloyDB, Project B for Cloud Run)
- Terraform >= 1.0
- gcloud CLI
- Docker
1. Set up Project A (AlloyDB + Proxy)
cd terraform/project-a
cp terraform.tfvars.example terraform.tfvars
# Edit terraform.tfvars with your project ID
terraform init
terraform apply
# Save outputs
terraform output2. Build and push Flask app
cd ../../app
PROJECT_B_ID="your-project-b-id"
# Create Artifact Registry
gcloud artifacts repositories create alloydb-test \
--repository-format=docker \
--location=us-central1 \
--project=$PROJECT_B_ID
# Build and push
gcloud auth configure-docker us-central1-docker.pkg.dev
docker build --platform linux/amd64 \
-t us-central1-docker.pkg.dev/$PROJECT_B_ID/alloydb-test/test-app:latest .
docker push us-central1-docker.pkg.dev/$PROJECT_B_ID/alloydb-test/test-app:latest3. Set up Project B (Cloud Run)
cd ../terraform/project-b
cp terraform.tfvars.example terraform.tfvars
# Edit terraform.tfvars with Project B ID and proxy IP from step 1
terraform init
terraform apply4. Set up VPC Peering
cd ../phase-3-peering
cp terraform.tfvars.example terraform.tfvars
# Edit terraform.tfvars with both project IDs
terraform init
terraform apply5. Test the connection
# Get Cloud Run URL
cd ../project-b
SERVICE_URL=$(terraform output -raw cloud_run_url)
# Test health
curl $SERVICE_URL/health
# Test database connectivity
curl $SERVICE_URL/testExpected response:
{
"status": "success",
"connection_time_ms": 40.27,
"read_test": {
"status": "passed",
"query_time_ms": 5.24
},
"write_test": {
"status": "passed",
"query_time_ms": 8.62
}
}alloydb-connection-experiment/
βββ README.md # This file
βββ EXPERIMENT_RESULTS.md # Validation results and findings
βββ USAGE.md # API reference and usage guide
βββ PROXY_SETUP_GUIDE.md # Quick setup for existing infrastructure
β
βββ docs/
β βββ adr/
β βββ 0001-cross-project-alloydb-connectivity.md
β
βββ terraform/
β βββ project-a/ # AlloyDB + nginx proxy
β β βββ main.tf
β β βββ variables.tf
β β βββ outputs.tf
β β βββ vpc.tf
β β βββ alloydb.tf
β β βββ proxy-vm.tf
β β βββ firewall.tf
β β βββ scripts/nginx-setup.sh
β β βββ terraform.tfvars.example
β β
β βββ project-b/ # Cloud Run + VPC Connector
β β βββ main.tf
β β βββ variables.tf
β β βββ outputs.tf
β β βββ vpc.tf
β β βββ cloud-run.tf
β β βββ terraform.tfvars.example
β β
β βββ phase-3-peering/ # VPC peering configuration
β βββ main.tf
β βββ variables.tf
β βββ outputs.tf
β βββ peering.tf
β βββ terraform.tfvars.example
β
βββ app/
β βββ Dockerfile
β βββ requirements.txt
β βββ test_connection.py # Flask app with test endpoints
β
βββ load-test/
β βββ README.md # Load testing documentation
β βββ load_test.py # Python load testing tool
β βββ simple_load_test.sh # Bash load testing (no dependencies)
β βββ run_load_tests.sh # Comprehensive test suite
β βββ requirements.txt
β
βββ scripts/
βββ setup.sh # Automated setup
βββ test.sh # Run connectivity tests
βββ teardown.sh # Clean up resources
The Flask test application provides:
/health- Health check (no database required)/test- Comprehensive connectivity test (read + write)/query- Execute custom SELECT queries with statistics/config- Display configuration (debugging)
See USAGE.md for complete API documentation.
Multiple load testing options:
# Simple bash test (no dependencies)
cd load-test
./simple_load_test.sh https://your-cloud-run-url 10
# Python load test (advanced metrics)
python3 load_test.py --url https://your-cloud-run-url \
--test connection --requests 50 --concurrency 10
# Comprehensive test suite
./run_load_tests.shSee load-test/README.md for details.
Based on validated experiment (October 2025):
| Metric | Value | Notes |
|---|---|---|
| Success Rate | 100% | Zero failures across all tests |
| Connection Time | 40ms (avg) | Cloud Run β AlloyDB via proxy |
| Read Query | 6ms (avg) | Simple SELECT operations |
| Write Query | 10ms (avg) | INSERT operations |
| Total Latency | <100ms | Including HTTP overhead |
| Throughput | 10+ req/sec | With concurrency of 10 |
Infrastructure Cost: ~$10/month (e2-micro proxy + VPC Connector)
β nginx TCP proxy adds minimal latency (~2-5ms) β VPC peering established reliably β 100% success rate under concurrent load β Simple to monitor (nginx access/error logs) β Cost-effective solution
See EXPERIMENT_RESULTS.md for complete findings.
# 1. Verify VPC peering is ACTIVE
gcloud compute networks peerings list \
--network=project-a-vpc \
--project=YOUR-PROJECT-A-ID
# 2. Check nginx is listening on port 5432
gcloud compute ssh alloydb-proxy \
--project=YOUR-PROJECT-A-ID \
--zone=us-central1-a \
--tunnel-through-iap \
--command="ss -tlnp | grep 5432"
# 3. Test from Cloud Run
curl https://your-cloud-run-url/testSee USAGE.md for comprehensive troubleshooting guide.
# Destroy in reverse order
cd terraform/phase-3-peering && terraform destroy
cd ../project-b && terraform destroy
cd ../project-a && terraform destroyOr use the automated script:
./scripts/teardown.sh- AlloyDB with Private Service Access (cannot migrate to PSC)
- Cross-project connectivity requirements
- Low-to-medium connection volume (<1000 concurrent)
- Latency requirements <100ms acceptable
- Cost-sensitive projects avoiding PSC migration downtime
- Very high throughput (>10,000 concurrent connections)
- Ultra-low latency requirements (<10ms total)
- When PSC migration is feasible
- Compliance requires no intermediary components
This is a validated experiment repository. If you find issues or have improvements:
- Open an issue describing the problem
- Reference the specific component (terraform, app, docs)
- Include environment details and error messages
This experiment code is provided as-is for learning and validation purposes.
- GCP Documentation: VPC Peering, AlloyDB, Cloud Run
- nginx: Stream module for TCP proxying
- Lean Startup Methodology: Validated learning approach
For questions about this experiment:
- Review EXPERIMENT_RESULTS.md for validation details
- Check USAGE.md for usage and troubleshooting
- See PROXY_SETUP_GUIDE.md for retrofitting existing setups
- Review ADR in docs/adr/0001-cross-project-alloydb-connectivity.md
Experiment Status: β VALIDATED - PRODUCTION READY Date: October 27-28, 2025 Recommendation: Proceed with production implementation
π€ Generated with Claude Code