Introduction
A common first step in cloud adoption is the "lift-and-shift" migration:
moving an existing application to the cloud with minimal changes to
reduce migration risk and preserve the original release cadence. In
this post, we walk through migrating a application with a hardcoded
localhost database dependency to Google Cloud, without modifying a
single line of application code — relying instead on infrastructure
and configuration to bridge the gap.
By the end of this walkthrough, you will have deployed a Compute Engine
instance connected to a Cloud SQL database over a private network path,
with no public database endpoint exposed.
Solution overview
The target architecture places the application on a Compute Engine VM
and the database on Cloud SQL, connected through the Cloud SQL Auth
Proxy running as a sidecar process on the VM. This preserves the
application's original localhost connection string while routing
traffic securely to the managed database.
┌─────────────────────────────┐
│ Compute Engine VM │
│ ┌────────┐ ┌───────────┐ │ ┌───────────────┐
│ │ App │──▶│ Cloud SQL │──┼───────▶│ Cloud SQL │
│ │ │ │Auth Proxy │ │Private │ (Private IP) │
│ └────────┘ └───────────┘ │ VPC └───────────────┘
└─────────────────────────────┘
Prerequisites
- A GCP project with the Compute Engine and Cloud SQL Admin APIs enabled
- A sample application (Node.js, Flask, or WordPress) that reads its
database host from a config file or environment variable set to
localhost - The application verified working in a local environment before migration begins
Walkthrough
Step 1: Provision the database and compute resources
gcloud services enable compute.googleapis.com sqladmin.googleapis.com
gcloud sql instances create app-db \
--database-version=MYSQL_8_0 \
--tier=db-f1-micro \
--region=asia-southeast1 \
--no-assign-ip \
--network=default
gcloud sql databases create appdb --instance=app-db
gcloud compute instances create app-vm \
--zone=asia-southeast1-a \
--machine-type=e2-small \
--image-family=debian-12 \
--image-project=debian-cloud
We disable the public IP on the Cloud SQL instance from the start
(--no-assign-ip), reflecting a common enterprise security requirement
that databases never be reachable over the public internet.
Step 2: Establish private connectivity
Cloud SQL private IP requires a VPC peering connection to Google's
managed services range:
gcloud compute addresses create google-managed-services-default \
--global --purpose=VPC_PEERING --prefix-length=16 --network=default
gcloud services vpc-peerings connect \
--service=servicenetworking.googleapis.com \
--ranges=google-managed-services-default \
--network=default
Step 3: Deploy the Cloud SQL Auth Proxy on the VM
gcloud compute ssh app-vm --zone=asia-southeast1-a
On the VM:
curl -o cloud-sql-proxy \
https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/v2.11.0/cloud-sql-proxy.linux.amd64
chmod +x cloud-sql-proxy
./cloud-sql-proxy --private-ip <PROJECT_ID>:asia-southeast1:app-db &
The proxy binds to 127.0.0.1:3306 by default, which is exactly the
endpoint the application already expects.
Step 4: Open the required firewall path
Applications frequently listen on ports other than 80/443. Configure
the firewall to allow only the specific port the application requires:
gcloud compute instances add-tags app-vm --tags=app-server --zone=asia-southeast1-a
gcloud compute firewall-rules create allow-app-port \
--allow=tcp:3000 \
--source-ranges=0.0.0.0/0 \
--target-tags=app-server
Common pitfall: a connection timeout at this stage can originate
from either a missing firewall rule or an application that binds to
127.0.0.1instead of0.0.0.0. Verify withcurl localhost:3000
from inside the VM before troubleshooting the network path.
Step 5: Attach a custom domain
gcloud dns managed-zones create app-zone \
--dns-name="yourdomain.com." \
--description="Lift and shift walkthrough"
Create an A record pointing to the VM's external IP through the
Cloud Console or gcloud dns record-sets create.
Validating the deployment
Confirm the following before considering the migration complete:
-
gcloud sql instances describe app-dbshows no public IP address - The application is reachable via the custom domain, not the raw IP
- No port other than 80/443 is exposed to
0.0.0.0/0
Clean up resources
gcloud compute instances delete app-vm --zone=asia-southeast1-a --quiet
gcloud sql instances delete app-db --quiet
gcloud compute firewall-rules delete allow-app-port --quiet
gcloud dns managed-zones delete app-zone --quiet
Conclusion
This walkthrough demonstrated that a lift-and-shift migration is
rarely "zero infrastructure change" even when it is "zero code change."
The Cloud SQL Auth Proxy pattern shown here is a common bridge for
applications that cannot be immediately refactored to use
cloud-native service discovery.
In Part 2, we build on this foundation with a highly available
three-tier architecture — and deliberately break it five different
ways to practice production diagnostics.
Top comments (0)