Redis with Shared VPC and Private Service Access

Neil Kolban
Google Cloud - Community
6 min readJun 24, 2020

Imagine that we wish a Memorystore redis managed instance to be available to a number of our projects. How might we achieve this?

One answer is to leverage Shared VPC and Private Service Access. Let us now look at a high level topology diagram and then we will explain its parts followed by the recipe to create it.

Our goal is to create a Cloud Memorystore instance. We will create that in a project called data-tier which owns our data service components. Cloud Memorystore is a managed service so although we create it in the data-tier project, we still need to consider its networking considerations. Since we want the service to be reachable by multiple projects, we need a routing story that allows such. This is where we bring in Shared VPC. We create a Shared VPC Network that we call “shared-networking” and within that create a subnet called “data-tier-us-central1”. In the shared-networking Shared VPC, we add two Service Projects called “app-tier” and “service-tier”.

  1. Create three projects
  • shared-networking
  • data-tier
  • app-tier

2. In Console, open each of the three new projects and enable Compute Engine.

3. Open cloud console to the shared-networking project.

4. Delete the Default network (we don’t need it)

5. Create a VPC network called shared-networking with a subnet called data-tier-us-central1 in region us-central1. Specify an IP address range of 10.0.0.0/16.

The end result will be:

6. Enable Private Service connection

Drill down into the shared-networking … VPC network. Click the Private service connection:

Enable the Service Networking API:

Allocate an IP range

Select Automatic to allow Google to choose the range.

Create Private connections to services:

7. Create a firewall rule to open port 22 on the network to allow incoming SSH.

8. Create a Shared VPC

9. Enable Service Networking API in the project called data-tier.

10. Open a Cloud Shell in the data-tier project.

11. Create a Memory store instance. Currently, Redis can only be configured to use Private Service Access by creating it through gcloud. There is not yet a Cloud Console mechanism to create it in this mode. We will need to find the project ids for the projects we called data-tier and shared-networking.

gcloud redis instances create myinst \
--size=5 \
--region=us-central1 \
--project=data-tier-XXX \
--network=projects/shared-networking-XXX/global/networks/shared-networking \
--connect-mode=private-service-access

You may be asked to enable the redis API. When completed, we can look at our Memorystore — Redis instances and see the new instance.

Notice that the instance’s IP address is taken from the allocated IP range for Private Service connections.

12. Switch to the app-tier project in Cloud Console.

13. Create a Compute Engine attached to the data-tier-us-central1 subnet.

We create a micro instance for testing:

We attach the micro instance to the data-tier-us-central1 subnet that is part of the Shared VPC in which we created the Redis instance.

14. SSH into the newly created Compute Engine. Our goal is to test that we have access to Redis.

15. Install telnet.

sudo apt-get install telnet

16. Telnet to the Redis instance:

telnet 10.96.0.3 6379

enter

INFO

You will now see the details of the Redis instance.

enter

QUIT

to exit from the Redis connection.

To further illustrate the story, here is a YouTube video showing all of the steps necessary to create the Redis instance in a Shared VPC:

Here is an example Terraform script that can be used as a basis for building the solution:

variable "billing_account" {
type = string
default = "XXXX"
}
variable "org-id" {
type = string
default = "XXXX"
}
output "redis_ip" {
description = "IP of redis"
value = google_redis_instance.cache.host
}
provider "google" {
}
resource "google_project" "shared-networking" {
name = "shared-networking"
project_id = "XXX-shared-networking"
org_id = var.org-id
billing_account = var.billing_account
}
resource "google_project" "data-tier" {
name = "data-tier"
project_id = "XXX-data-tier"
org_id = var.org-id
billing_account = var.billing_account
}
resource "google_project" "app-tier" {
name = "app-tier"
project_id = "XXX-app-tier"
org_id = var.org-id
billing_account = var.billing_account
}
resource "google_project_service" "compute-shared-networking" {
project = google_project.shared-networking.project_id
service = "compute.googleapis.com"
}
resource "google_project_service" "compute-data-tier" {
project = google_project.data-tier.project_id
service = "compute.googleapis.com"
}
resource "google_project_service" "redis-data-tier" {
project = google_project.data-tier.project_id
service = "redis.googleapis.com"
}
resource "google_project_service" "compute-app-tier" {
project = google_project.app-tier.project_id
service = "compute.googleapis.com"
}
resource "google_project_service" "enable-service-networking" {
project = google_project.shared-networking.project_id
service = "servicenetworking.googleapis.com"
}
resource "google_project_service" "enable-service-networking-data-tier" {
project = google_project.data-tier.project_id
service = "servicenetworking.googleapis.com"
}
resource "google_compute_network" "shared-networking" {
project = google_project.shared-networking.project_id
name = "shared-networking"
auto_create_subnetworks = false
}
resource "google_compute_subnetwork" "data-tier-us-central1" {
name = "data-tier-us-central1"
ip_cidr_range = "10.0.0.0/16"
region = "us-central1"
network = google_compute_network.shared-networking.id
project = google_project.shared-networking.project_id
}
resource "google_compute_global_address" "managed-data-services" {
name = "managed-data-services"
address_type = "INTERNAL"
purpose = "VPC_PEERING"
prefix_length = 16
network = google_compute_network.shared-networking.self_link
project = google_project.shared-networking.project_id
}
resource "google_service_networking_connection" "private-connection" {
network = google_compute_network.shared-networking.id
service = "servicenetworking.googleapis.com"
reserved_peering_ranges = [google_compute_global_address.managed-data-services.name]
}
resource "google_compute_firewall" "ssh" {
name = "allow-ingress-tcp-22-shared-networking"
network = google_compute_network.shared-networking.name
project = google_project.shared-networking.project_id
source_ranges = ["0.0.0.0/0"]
allow {
protocol = "tcp"
ports = ["22"]
}
}
resource "google_compute_shared_vpc_host_project" "host" {
project = google_project.shared-networking.project_id
}
resource "google_compute_shared_vpc_service_project" "service1" {
host_project = google_compute_shared_vpc_host_project.host.project
service_project = google_project.app-tier.project_id
}
resource "google_compute_shared_vpc_service_project" "service2" {
host_project = google_compute_shared_vpc_host_project.host.project
service_project = google_project.data-tier.project_id
}
resource "google_redis_instance" "cache" {
name = "memory-cache"
memory_size_gb = 5
project = google_project.data-tier.project_id
region = "us-central1"
authorized_network = google_compute_network.shared-networking.self_link
connect_mode = "PRIVATE_SERVICE_ACCESS"
}
resource "google_compute_instance" "client" {
name = "client"
machine_type = "f1-micro"
zone = "us-central1-a"
project = google_project.app-tier.project_id
boot_disk {
initialize_params {
image = "debian-cloud/debian-11"
}
}
network_interface {
access_config {
// Ephemeral public IP
}
subnetwork = google_compute_subnetwork.data-tier-us-central1.self_link
}
}

--

--

Neil Kolban
Google Cloud - Community

IT specialist with 30+ years industry experience. I am also a Google Customer Engineer assisting users to get the most out of Google Cloud Platform.