This tutorial describes how to register the private IP address of a Cloud Run worker pool instance within a Cloud DNS managed zone. In this tutorial, you use a startup script to dynamically detect the instance IP through the metadata server, and create a Node.js application to handle ingress directly within your VPC network.
Objectives
- Create a Cloud DNS managed zone to host the records for your worker pool.
- Create a Node.js application to handle ingress traffic over the VPC network.
- Deploy a worker pool with Direct VPC ingress to assign a private IP address from your subnet to your worker instance.
- Test your application to access the private IP address from a virtual machine (VM) instance on the same VPC network.
Costs
In this document, you use the following billable components of Google Cloud:
To generate a cost estimate based on your projected usage,
use the pricing calculator.
Before you begin
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
Roles required to select or create a project
- Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
-
Create a project: To create a project, you need the Project Creator role
(
roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
Roles required to select or create a project
- Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
-
Create a project: To create a project, you need the Project Creator role
(
roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
-
Enable the Cloud DNS, Cloud Run, Compute Engine, Artifact Registry, and Cloud Build APIs.
Roles required to enable APIs
To enable APIs, you need the Service Usage Admin IAM role (
roles/serviceusage.serviceUsageAdmin), which contains theserviceusage.services.enablepermission. Learn how to grant roles. - Install and initialize the gcloud CLI.
- Update components:
gcloud components update
- Set your project ID by running the following command:
Replace PROJECT_ID with the ID of your Google Cloud project.gcloud config set project PROJECT_ID
Required roles
To get the permissions that you need to complete the tutorial, ask your administrator to grant you the following IAM roles on your project:
-
Artifact Registry Repository Administrator (
roles/artifactregistry.repoAdmin) -
Cloud Build Editor (
roles/cloudbuild.builds.editor) -
Cloud Run Admin (
roles/run.admin) -
Create Service Accounts (
roles/iam.serviceAccountCreator) -
Cloud DNS Admin (
roles/dns.admin) -
Service Account User (
roles/iam.serviceAccountUser) -
Service Usage Consumer (
roles/serviceusage.serviceUsageConsumer)
For more information about granting roles, see Manage access to projects, folders, and organizations.
You might also be able to get the required permissions through custom roles or other predefined roles.
Create a Cloud DNS zone
Create a private Cloud DNS managed zone named test-wp to register your worker
pool's instance IP.
gcloud dns managed-zones create test-wp --description="new DNS zone for worker pools" --dns-name="workerpools.example.com." --visibility="private" --networks=default
Create a Node.js application
Create a Node.js application that retrieves the worker pool instance's IP address using the metadata server, and then registers it with Cloud DNS.
Create a folder named
workerand change the directory into it:mkdir worker cd workerCreate a file named
setup_dns.shand add the following script that runs when your worker pool instance starts:#!/bin/bash # --- Variables --- # The name of your Cloud DNS managed zone. ZONE_NAME="test-wp" # The base domain suffix for the DNS entry. Use the part *after* the hostname. # For example, for "testinstance.workerpools.example.com.", the suffix is ".workerpools.example.com." DNS_SUFFIX=".workerpools.example.com." # The Time-To-Live (TTL) in seconds. TTL="300" # The record type (A for IPv4). RECORD_TYPE="A" # ----------------- # 1. Dynamically generate DNS_NAME # Get the simple hostname (e.g., "testinstance") and append the defined suffix. # We use 'hostname -s' to get the short hostname. SHORT_HOSTNAME=$(hostname -s) DNS_NAME="${SHORT_HOSTNAME}${DNS_SUFFIX}" # 2. Dynamically assign NEW_IP # Get the IP address from metadata server using predefined key. NEW_IP=$(curl "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/ip" -H "Metadata-Flavor: Google") # --- Input Validation --- if [ -z "$NEW_IP" ]; then echo "❌ ERROR: Could not obtain a valid IP address from metadata server. Aborting." exit 1 fi echo "Starting DNS record update for ${DNS_NAME} in zone ${ZONE_NAME}..." echo "New IP detected on this instance: ${NEW_IP}" # 3. Get the current existing IP address (if any) # This is required to know what to put in the --rrdatas for the delete command. EXISTING_IP=$(gcloud dns record-sets list \ --zone="${ZONE_NAME}" \ --name="${DNS_NAME}" \ --type="${RECORD_TYPE}" \ --format="value(rrdatas[0])" 2>/dev/null) # --- Conditional Deletion/Skip Check --- if [ -n "$EXISTING_IP" ] && [ "$EXISTING_IP" != "$NEW_IP" ]; then echo "Found existing IP: ${EXISTING_IP}. It is different from the new IP." # Delete the existing record echo "Deleting old record..." gcloud dns record-sets delete "${DNS_NAME}" \ --zone="${ZONE_NAME}" \ --type="${RECORD_TYPE}" \ --quiet if [ $? -ne 0 ]; then echo "❌ ERROR: Failed to delete existing record. Aborting." exit 1 fi elif [ -n "$EXISTING_IP" ] && [ "$EXISTING_IP" == "$NEW_IP" ]; then echo "Existing IP (${EXISTING_IP}) matches the new IP. Skipping update." exit 0 else echo "No existing record found for ${DNS_NAME}. Proceeding with creation." fi # ---------------------------------------- # 4. Add the new record echo "Creating new record with IP: ${NEW_IP}..." gcloud dns record-sets create "${DNS_NAME}" \ --zone="${ZONE_NAME}" \ --type="${RECORD_TYPE}" \ --ttl="${TTL}" \ --rrdatas="${NEW_IP}" # Final status check if [ $? -eq 0 ]; then echo "✅ Successfully created/updated DNS record for ${DNS_NAME} to ${NEW_IP}." else echo "❌ ERROR: Failed to create the new DNS record." exit 1 fiCreate a
server.jsfile with the following code to handle the private IP address ingress:// server.js // 1. Import the built-in 'http' module console.log("hello from worker pool") const http = require('http'); // Define the port the server will listen on const PORT = 3000; // 2. Create the server instance const server = http.createServer((req, res) => { // Set the response HTTP header with status and type of content res.writeHead(200, {'Content-Type': 'text/plain'}); // Write the response body res.end('Hello World!\n'); }); // 3. Start the server and listen on the specified port server.listen(PORT, () => { console.log(`Server running at http://localhost:${PORT}/`); });Create a
start.shscript with the following code to perform the DNS setup first, before running your Node.js application:#!/bin/bash set -e # 1. Execute the setup script echo "Running setup_dns.sh..." /app/setup_dns.sh # 2. Run the main application echo "Starting server.js..." exec node /app/server.jsCreate the following Dockerfile to package the application in an image:
# Choose a base image. This image includes gcloud, kubectl, etc. FROM google/cloud-sdk:latest # Install Node.js on top of the Cloud SDK image. RUN apt-get update && \ apt-get install -y curl && \ curl -sL https://deb.nodesource.com/setup_lts.x | bash - && \ apt-get install -y nodejs && \ # Clean up to reduce image size apt-get clean && \ rm -rf /var/lib/apt/lists/* # Set the working directory inside the container. WORKDIR /app # Copy the application and scripts into the container. COPY setup_dns.sh . COPY server.js . COPY start.sh . # Make both scripts executable. RUN chmod +x setup_dns.sh start.sh # Define the entrypoint and default command. ENTRYPOINT ["/app/start.sh"] CMD []
Deploy a worker pool with Direct VPC ingress
Deploy a worker pool named test-cli-dns and attach it to a VPC network.
gcloud beta run worker-pools deploy test-cli-dns --network default --subnet default --region us-central1 --source . --project PROJECT_ID
Replace PROJECT_ID with your Google Cloud project ID.
Test your application
Cloud Run worker pools with Direct VPC ingress are designed for internal-only
traffic. They don't have a public IP. To verify ingress functionality, follow
these steps to run a request using curl from a Compute Engine VM hosted on
the same VPC network and subnet:
Create a test VM in the same network and region as your worker pool:
gcloud compute instances create wp-test-vm \ --zone=us-central1-a \ --network=default \ --subnet=defaultConnect to the test VM through SSH by running the following command:
gcloud compute ssh wp-test-vm --zone=us-central1-aFrom the VM terminal, invoke your service at the private IP address of the worker pool instance registered with Cloud DNS:
curl http://localhost.workerpools.example.com:3000You should see the output:
Hello World!
Success! You've successfully configured your Cloud Run worker pool with Direct VPC ingress using a private IP address and Cloud DNS.
Clean up
To avoid additional charges to your Google Cloud account, delete all the resources you deployed with this tutorial.
Delete the project
If you created a new project for this tutorial, delete the project. If you used an existing project and need to keep it without the changes you added in this tutorial, delete resources that you created for the tutorial.
The easiest way to eliminate billing is to delete the project that you created for the tutorial.
To delete the project:
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
Delete tutorial resources
Delete the Cloud Run service you deployed in this tutorial. Cloud Run services don't incur costs until they receive requests.
To delete your Cloud Run service, run the following command:
gcloud run services delete SERVICE-NAME
Replace SERVICE-NAME with the name of your service.
You can also delete Cloud Run services from the Google Cloud console.
Remove the
gclouddefault region configuration you added during tutorial setup:gcloud config unset run/regionRemove the project configuration:
gcloud config unset projectDelete other Google Cloud resources created in this tutorial:
- Delete the Cloud Run worker pool.
- Delete the worker pool container image from Artifact Registry.
- Delete a Cloud DNS managed zone.
What's next
- Learn more about configuring a Direct VPC with a VPC network.
- Learn more about Cloud Run worker pools.
- Explore other Cloud Run demos, tutorials, and samples.