Create an internal load balancer across VPC networks Stay organized with collections Save and categorize content based on your preferences.
This page explains how to create aninternal passthrough Network Load Balancer onGoogle Kubernetes Engine (GKE) across VPC networks.
Before reading this page, ensure that you'refamiliar with the following concepts:
Before you begin
Before you start, make sure that you have performed the following tasks:
- Enable the Google Kubernetes Engine API. Enable Google Kubernetes Engine API
- If you want to use the Google Cloud CLI for this task,install and theninitialize the gcloud CLI. If you previously installed the gcloud CLI, get the latest version by running the
gcloud components updatecommand. Earlier gcloud CLI versions might not support running the commands in this document.Note: For existing gcloud CLI installations, make sure to set thecompute/regionproperty. If you use primarily zonal clusters, set thecompute/zoneinstead. By setting a default location, you can avoid errors in the gcloud CLI like the following:One of [--zone, --region] must be supplied: Please specify location. You might need to specify the location in certain commands if the location of your cluster differs from the default that you set.
Create an internal load balancer with Private Service Connect
As a service producer, you can use service attachments to make your servicesavailable to service consumers in other VPC networks usingPrivate Service Connect. You cancreate, manage, and delete service attachments using aServiceAttachmentcustom resource.
Requirements and limitations
- Limitations forPrivate Service Connectapply.
- You can create a service attachment in GKE versions1.21.4-gke.300 and later.
- Your cluster must have the
HttpLoadBalancingadd-onenabled. NewGKE clusters have theHttpLoadBalancingadd-on enabled bydefault. - You cannot use the same subnet in multiple service attachment configurations.
- You must create a GKE service that uses an internal passthrough Network Load Balancer.
- You cannot specify a subnet in a different project (Shared VPC) forGKE versions earlier than 1.22.4-gke.100. For Shared VPC,ensure allrequirements for Shared VPCare met.
- After you create a service attachment, you can't update the internal loadbalancer. To change your load balancer configurations, you must delete andrecreate the service attachment.
Create aServiceAttachment
Create a subnet.
You must create anew subnetfor each
ServiceAttachment.gcloudbetacomputenetworkssubnetscreateSUBNET_NAME\--projectPROJECT_ID\--networkNETWORK_NAME\--regionREGION\--rangeSUBNET_RANGE\--purposePRIVATE_SERVICE_CONNECTReplace the following:
SUBNET_NAME: the name of the new subnet. InGKE versions 1.22.4-gke.100 and later, you can specifya subnet in a different project by using the fully qualified resourceURL for this field. You can get the fully qualified resource URL usingthe commandgcloud compute networks subnets describe.PROJECT_ID: the ID of your Google Cloudproject.NETWORK_NAME: the name of the VPCnetwork for the subnet.REGION: the region for the new subnet. You must usethe same region as the service that you create.SUBNET_RANGE: the IP address range to use for thesubnet.
Deploy a workload.
The following manifest describes a Deployment that runs a sample webapplication container image. Save the manifest as
my-deployment.yaml:apiVersion:apps/v1kind:Deploymentmetadata:name:psc-ilbspec:replicas:3selector:matchLabels:app:psc-ilbtemplate:metadata:labels:app:psc-ilbspec:containers:-name:whereamiimage:us-docker.pkg.dev/google-samples/containers/gke/whereami:v1ports:-name:httpcontainerPort:8080readinessProbe:httpGet:path:/healthzport:8080scheme:HTTPinitialDelaySeconds:5timeoutSeconds:1Apply the manifest to your cluster:
kubectlapply-fmy-deployment.yamlCreate a service.The following manifest describes a service that creates an internal passthrough Network Load Balanceron TCP port 8080. Save the manifest as
my-service.yaml:apiVersion:v1kind:Servicemetadata:name:SERVICE_NAMEannotations:networking.gke.io/load-balancer-type:"Internal"spec:type:LoadBalancerselector:app:psc-ilbports:-port:80targetPort:8080protocol:TCPReplace the following:
SERVICE_NAME: the name of the new service.
Apply the manifest to your cluster:
kubectlapply-fmy-service.yamlCreate
ServiceAttachment.The following manifest describes a
ServiceAttachmentthat exposes theservice that you created to service consumers. Save the manifest asmy-psc.yaml: Note: For GKE versions earlier than 1.23.3-gke.900, useapiVersion:networking.gke.io/v1kind:ServiceAttachmentmetadata:name:SERVICE_ATTACHMENT_NAMEnamespace:defaultspec:connectionPreference:ACCEPT_AUTOMATICnatSubnets:-SUBNET_NAMEproxyProtocol:falseresourceRef:kind:Servicename:SERVICE_NAMEnetworking.gke.io/v1beta1instead ofnetworking.gke.io/v1.Replace the following:
SERVICE_ATTACHMENT_NAME: the name of the new serviceattachment.SUBNET_NAME: the name of the new subnet. InGKE versions 1.22.4-gke.100 and later, you can specifya subnet in a different project by using the fully qualified resourceURL for this field. You can get the fully qualified resource URL usingthe commandgcloud compute networks subnets describe.For a Shared VPC configuration, use the following format:projects/HOST_PROJECT_ID/regions/COMPUTE_REGION/subnetworks/SUBNET_NAME.
ServiceAttachmentresource will have error events until theGKE controller creates the internal passthrough Network Load Balancer that is definedby the service. After the internal passthrough Network Load Balancer is provisioned, the errors areno longer published.For more information about the manifest fields, see theservice attachment fields.
Apply the manifest to your cluster:
kubectlapply-fmy-psc.yamlVerify that the Private Service Connect controller created theservice attachment:
gcloudbetacomputeservice-attachmentslistThe output shows a service attachment with an automatically generated name:
NAME REGION PRODUCER_FORWARDING_RULE CONNECTION_PREFERENCEk8s1-sa-... REGION_NAME a3fea439c870148bdba5e59c9ea9451a ACCEPT_AUTOMATIC
View aServiceAttachment
You can view the details of aServiceAttachment using the following command:
kubectldescribeserviceattachmentSERVICE_ATTACHMENT_NAMEThe output is similar to the following:
Name: <sa-name>Namespace: defaultLabels: <none>Annotations: <none>API Version: networking.gke.io/v1beta1Kind: ServiceAttachmentMetadata: ...Status: Forwarding Rule URL: https://www.googleapis.com/compute/beta/projects/<project>/regions/<region>/forwardingRules/<fr-name> Last Modified Timestamp: 2021-07-08T01:32:39Z Service Attachment URL: https://www.googleapis.com/compute/beta/projects/<projects>/regions/<region>/serviceAttachments/<gce-service-attachment-name>Events: <none>Consume aServiceAttachment
To consume your service from another project, perform the following steps:
Get the URL of the
ServiceAttachment:kubectlgetserviceattachmentSERVICE_ATTACHMENT_NAME-o=jsonpath="{.status.serviceAttachmentURL}"The output is similar to the following:
serviceAttachmentURL: https://www.googleapis.com/compute/alpha/projects/<project>/region/<region>/serviceAttachments/k8s1-...my-saCreate a Private Service Connect endpointusing the URL of the
ServiceAttachment.Verify that you can connect to the Service that you deployed in the producerproject by using a
curlcommand from a VM in the consumer project:curlPSC_IP_ADDRESSReplace
PSC_IP_ADDRESSwith the IP address of theforwarding rule in the consumer project.The output is similar to the following:
{ "cluster_name":"cluster", "host_header":"10.128.15.200", "node_name":"gke-psc-default-pool-be9b6e0e-dvxg.c.gke_project.internal", "pod_name":"foo-7bf648dcfd-l5jf8", "pod_name_emoji":"👚", "project_id":"gke_project", "timestamp":"2021-06-29T21:32:03", "zone":"ZONE_NAME"}
Update aServiceAttachment
You can update aServiceAttachment using the following steps:
resourceRef field and you can only add subnets tothenatSubnets field. You cannot remove subnets. If you need to update theresourceRef field or remove subnets from thenatSubnets field, you mustdelete and then recreate theServiceAttachment.Edit the
ServiceAttachmentmanifest inmy-psc.yaml: Note: For GKE versions earlier than 1.23.3-gke.900, useapiVersion:networking.gke.io/v1kind:ServiceAttachmentmetadata:name:my-sanamespace:defaultspec:connectionPreference:ACCEPT_AUTOMATICnatSubnets:-my-nat-subnetproxyProtocol:falseresourceRef:kind:Servicename:ilb-servicenetworking.gke.io/v1beta1instead ofnetworking.gke.io/v1.Apply the manifest to your cluster:
kubectlapply-fmy-psc.yaml
Delete aServiceAttachment
You cannot delete an internal passthrough Network Load Balancer that is connected to a serviceattachment. You must delete the service attachment and GKEService separately.
Delete the service attachment:
kubectldeleteserviceattachmentSERVICE_ATTACHMENT_NAME--wait=falseThis command marks the service attachment for deletion, but the resourcecontinues to exist. You can also wait for the deletion to finish by omittingthe
--waitflag.Delete the Service:
kubectldeletesvcSERVICE_NAMEDelete the subnet:
gcloudcomputenetworkssubnetsdeleteSUBNET_NAME
ServiceAttachment fields
TheServiceAttachment has the following fields:
connectionPreference: the connection preference that determines howcustomers connect to the service. You can either use automatic projectapproval usingACCEPT_AUTOMATICor explicit project approval usingACCEPT_MANUAL. For more information, seePublishing services using Private Service Connect.natSubnets: a list of subnetwork resource names to use for the serviceattachment.proxyProtocol: when set to true, the consumer source IP andPrivate Service Connect connection ID are available in the requests.This field is optional and defaults to false if not provided.consumerAllowList: the list of consumer projects that are allowed toconnect to theServiceAttachment. This field can only be used whenconnectionPreferenceisACCEPT_MANUAL. For more information about thisfield, seePublishing services using Private Service Connect.project: the project ID or number for the consumer project.connectionLimit: the connection limit for the consumer project. Thisfield is optional.forceSendFields: the field names to send to include in API requests.This field is optional.nullFields: the field names to include in API requests with a nullvalue. This field is optional.
consumerRejectList: the list of consumer project IDs or numbers that arenot allowed to connect to theServiceAttachment. This field can only beused whenconnectionPreferenceisACCEPT_MANUAL. For more informationabout this field, seePublishing services using Private Service Connect.resourceRef: a reference to the Kubernetes resource.kind: the type of Kubernetes resource. You must useService.name: the name of the Kubernetes resource that must be in the samenamespace as the internal passthrough Network Load Balancer.
Troubleshooting
You can view error messages using the following command:
kubectlgetevents-nNAMESPACEReplaceNAMESPACE with the namespace of theinternal passthrough Network Load Balancer.
Error deleting internal passthrough Network Load Balancer
An error message similar to the following occurs if you try to delete aninternal passthrough Network Load Balancer that is being used by a service attachment. You must deletetheServiceAttachment before you can delete the internal passthrough Network Load Balancer.
Error syncing load balancer: failed to ensure load balancer: googleapi:Error 400: The forwarding_rule resource '<fwd-rule-URL>' is already being usedby '<svc-attachment-URL>', resourceInUseByAnotherResource.Error enabling global access
You might encounter an error when you enableglobalaccessfor an internal passthrough Network Load Balancer that uses a Private Service Connect serviceattachment.
Symptom:
When you enable global access by updating your GKE Servicemanifest and setting thenetworking.gke.io/internal-load-balancer-allow-global-access: "true"annotation, the update fails when you apply the manifest. You see thefollowing error message when you run thekubectl get events command:
Error syncing load balancer: failed to ensure load balancer: googleapi: Error 400: The forwarding_rule resource '...' is already being used by '...', resourceInUseByAnotherResourceReason:
This error occurs because the GKE control plane attempts tore-create the load balancer's forwarding rule to enable global access. However,because the forwarding rule is in use by aServiceAttachment, the rule cannotbe deleted and re-created, which results in the error.
Workaround:
To enable global access on the load balancer while minimizing downtime, youmust update the GKE Service configurationand manually updatethe forwarding rule:
Update the GKE Service manifest: update yourGKE Service manifest to include the
networking.gke.io/internal-load-balancer-allow-global-access: "true"annotation.Manually enable global access on the forwarding rule: follow the steps inEnable globalaccessto update the load balancer's forwarding rule by using either theGoogle Cloud console, theGoogle Cloud CLI, or the Compute Engine API.
What's next
- Read the GKE network overview.
- Learn more about Compute Engine load balancers.
- Learn how to create a VPC-native cluster.
- Learn about configuring authorized networks.
- Troubleshoot load balancing in GKE.
Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2025-12-15 UTC.