Skip to content

Latest commit

 

History

History
343 lines (269 loc) · 8.12 KB

File metadata and controls

343 lines (269 loc) · 8.12 KB

Quick Start: Add nginx TCP Proxy to Existing Setup

Use Case: You have AlloyDB (Project A) and Cloud Run (Project B) with VPC peering, but need to add the nginx proxy to enable connectivity.

Time Required: ~15 minutes


Prerequisites

✅ You already have:

  • AlloyDB cluster running in Project A (with Private Service Access)
  • Cloud Run service in Project B
  • VPC peering between Project A and Project B VPCs
  • AlloyDB IP address (internal/private IP)

❓ Need to find your AlloyDB IP:

gcloud alloydb instances describe YOUR-INSTANCE-NAME \
  --cluster=YOUR-CLUSTER-NAME \
  --region=YOUR-REGION \
  --project=YOUR-PROJECT-A-ID \
  --format="value(ipAddress)"

Step 1: Create the Proxy VM

# Set variables
export PROJECT_A_ID="your-project-a-id"
export REGION="us-central1"
export ZONE="${REGION}-a"
export ALLOYDB_IP="10.170.0.2"  # Replace with your AlloyDB IP
export PROXY_VM_NAME="alloydb-proxy"
export VPC_NETWORK="project-a-vpc"  # Your Project A VPC name
export SUBNET_NAME="project-a-subnet"  # Your Project A subnet name

# Create the VM
gcloud compute instances create $PROXY_VM_NAME \
  --project=$PROJECT_A_ID \
  --zone=$ZONE \
  --machine-type=e2-micro \
  --network-interface=subnet=$SUBNET_NAME,no-address \
  --tags=alloydb-proxy \
  --metadata=startup-script='#!/bin/bash
# Install nginx with stream module
apt-get update
apt-get install -y nginx libnginx-mod-stream

# Create nginx configuration
cat > /etc/nginx/nginx.conf <<'"'"'EOF'"'"'
user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;

# Load dynamic modules
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 1024;
}

# TCP proxy for PostgreSQL
stream {
    upstream alloydb_backend {
        server '"$ALLOYDB_IP"':5432 max_fails=3 fail_timeout=30s;
    }

    server {
        listen 5432;
        proxy_pass alloydb_backend;
        proxy_connect_timeout 5s;
        proxy_timeout 300s;
        proxy_buffer_size 16k;
    }

    log_format postgres '"'"'$remote_addr [$time_local] $protocol $status $bytes_sent $bytes_received $session_time "$upstream_addr"'"'"';
    access_log /var/log/nginx/postgres_access.log postgres;
    error_log /var/log/nginx/postgres_error.log;
}
EOF

# Start nginx
systemctl enable nginx
systemctl restart nginx
'

Note: The startup-script will run automatically when the VM boots.


Step 2: Get the Proxy VM's Internal IP

export PROXY_IP=$(gcloud compute instances describe $PROXY_VM_NAME \
  --project=$PROJECT_A_ID \
  --zone=$ZONE \
  --format="value(networkInterfaces[0].networkIP)")

echo "Proxy VM IP: $PROXY_IP"

Save this IP - you'll need to configure your Cloud Run service to connect to it.


Step 3: Create Firewall Rules

Allow Project B VPC to access the proxy

# Set Project B variables
export PROJECT_B_VPC_CIDR="10.2.0.0/20"  # Replace with your Project B VPC CIDR
export VPC_CONNECTOR_CIDR="10.8.0.0/28"  # Replace with your VPC Connector CIDR

# Create firewall rule
gcloud compute firewall-rules create allow-from-project-b \
  --project=$PROJECT_A_ID \
  --network=$VPC_NETWORK \
  --direction=INGRESS \
  --priority=1000 \
  --action=ALLOW \
  --rules=tcp:5432 \
  --source-ranges=$PROJECT_B_VPC_CIDR,$VPC_CONNECTOR_CIDR \
  --target-tags=alloydb-proxy \
  --description="Allow Project B Cloud Run to access AlloyDB through proxy"

Important: Include both your Project B VPC CIDR and VPC Connector CIDR.


Step 4: Verify Proxy is Running

# SSH to the proxy VM and check nginx
gcloud compute ssh $PROXY_VM_NAME \
  --project=$PROJECT_A_ID \
  --zone=$ZONE \
  --tunnel-through-iap \
  --command="systemctl status nginx && ss -tlnp | grep 5432"

Expected output:

  • nginx is active (running)
  • Port 5432 shows LISTEN with nginx process

Step 5: Update Cloud Run to Use Proxy

Update your Cloud Run service with the proxy IP:

export PROJECT_B_ID="your-project-b-id"
export CLOUD_RUN_SERVICE="your-cloud-run-service-name"
export DB_USER="postgres"
export DB_PASSWORD="your-db-password"
export DB_NAME="postgres"

gcloud run services update $CLOUD_RUN_SERVICE \
  --project=$PROJECT_B_ID \
  --region=$REGION \
  --set-env-vars="PROXY_VM_IP=$PROXY_IP,DB_USER=$DB_USER,DB_PASSWORD=$DB_PASSWORD,DB_NAME=$DB_NAME,DB_PORT=5432"

Step 6: Test the Connection

# Get Cloud Run URL
export SERVICE_URL=$(gcloud run services describe $CLOUD_RUN_SERVICE \
  --project=$PROJECT_B_ID \
  --region=$REGION \
  --format="value(status.url)")

# Test health endpoint
curl $SERVICE_URL/health

# Test database connection
curl $SERVICE_URL/test

Expected response:

{
  "status": "success",
  "connection_time_ms": 40,
  "read_test": { "status": "passed" },
  "write_test": { "status": "passed" }
}

Troubleshooting

❌ Connection timeout

Check 1: Verify VPC peering is ACTIVE

gcloud compute networks peerings list \
  --network=$VPC_NETWORK \
  --project=$PROJECT_A_ID

Check 2: Verify firewall rule exists

gcloud compute firewall-rules describe allow-from-project-b \
  --project=$PROJECT_A_ID

Check 3: Test from proxy VM to AlloyDB

gcloud compute ssh $PROXY_VM_NAME \
  --project=$PROJECT_A_ID \
  --zone=$ZONE \
  --tunnel-through-iap \
  --command="nc -zv $ALLOYDB_IP 5432"

❌ nginx not running

Check nginx status and logs:

gcloud compute ssh $PROXY_VM_NAME \
  --project=$PROJECT_A_ID \
  --zone=$ZONE \
  --tunnel-through-iap \
  --command="systemctl status nginx && tail -20 /var/log/nginx/error.log"

Restart nginx:

gcloud compute ssh $PROXY_VM_NAME \
  --project=$PROJECT_A_ID \
  --zone=$ZONE \
  --tunnel-through-iap \
  --command="sudo systemctl restart nginx"

❌ Database authentication errors

Verify credentials:

# Test with psql from proxy VM
gcloud compute ssh $PROXY_VM_NAME \
  --project=$PROJECT_A_ID \
  --zone=$ZONE \
  --tunnel-through-iap \
  --command="apt-get install -y postgresql-client && PGPASSWORD='$DB_PASSWORD' psql -h $ALLOYDB_IP -U $DB_USER -d $DB_NAME -c 'SELECT version()'"

Configuration Reference

Find Your VPC Connector CIDR

gcloud compute networks vpc-access connectors describe YOUR-CONNECTOR-NAME \
  --region=$REGION \
  --project=$PROJECT_B_ID \
  --format="value(ipCidrRange)"

Find Your VPC CIDR Ranges

# Project A VPC CIDR
gcloud compute networks subnets describe YOUR-SUBNET-NAME \
  --region=$REGION \
  --project=$PROJECT_A_ID \
  --format="value(ipCidrRange)"

# Project B VPC CIDR
gcloud compute networks subnets describe YOUR-SUBNET-NAME \
  --region=$REGION \
  --project=$PROJECT_B_ID \
  --format="value(ipCidrRange)"

What This Does

┌─────────────────┐
│   Cloud Run     │ Your application in Project B
│   (Project B)   │
└────────┬────────┘
         │ Connects to PROXY_VM_IP:5432
         │
    VPC Peering
         │
         ▼
┌─────────────────┐
│  nginx Proxy VM │ Port 5432 → Forwards to AlloyDB
│   (Project A)   │
└────────┬────────┘
         │ Connects to ALLOYDB_IP:5432
         │
         ▼
┌─────────────────┐
│    AlloyDB      │ Your database in Project A
│   (Project A)   │
└─────────────────┘

Key Benefits:

  • ✅ No AlloyDB downtime or migration
  • ✅ Works with existing Private Service Access
  • ✅ Bypasses transitive VPC peering limitation
  • ✅ Low latency (~40ms)
  • ✅ Cost-effective (~$5/month for e2-micro)

Cleanup (if needed)

# Delete firewall rule
gcloud compute firewall-rules delete allow-from-project-b \
  --project=$PROJECT_A_ID

# Delete VM
gcloud compute instances delete $PROXY_VM_NAME \
  --project=$PROJECT_A_ID \
  --zone=$ZONE

Alternative: Use Terraform

If you prefer infrastructure as code, see terraform/project-a/proxy-vm.tf for the equivalent Terraform configuration.

The gcloud commands above are functionally identical to the Terraform deployment.