"Network Tier" in GKE Service with type: LoadBalancer

Today I Learned series

About

Steps

Starting YAML:

---
apiVersion: v1
kind: Service
metadata:
  annotations:
    cloud.google.com/neg: '{"ingress":true}'
  name: lb
  namespace: tests
spec:
  allocateLoadBalancerNodePorts: false
  externalTrafficPolicy: Cluster
  internalTrafficPolicy: Cluster
  ipFamilies:
    - IPv4
  ipFamilyPolicy: SingleStack
  ports:
    - name: tcp-hello
      port: 9001
      protocol: TCP
      targetPort: hello
  selector:
    hello: "world"
  sessionAffinity: None
  type: LoadBalancer

It creates a GCP Load Balancer with IP with network tier: Premium even if default network tier (https://console.cloud.google.com/net-tier/tiers/details) is set to Standard.

Add annotation

metadata:
  annotations:
    cloud.google.com/network-tier: Standard
  • IP address converts to network tier Standard.

  • It takes around 1 minute.

  • It can be changed in both directions (Standard <-> Premium).

  • IP address changes every time.

Pre-configure IP address and use it

I assume that if cloud.google.com/network-tier is the same as the network tier of an IP address it works without any problems.

What if they are conflicted?

# Terraform
resource "google_compute_address" "my_ip" {
  name         = "my-ip"
  network_tier = "Standard"
}

Add to YAML:

metadata:
  annotations:
    cloud.google.com/network-tier: Premium
spec:
  loadBalancerIP: "a.b.c.d"

Result:

It fails with Error syncing load balancer: failed to ensure load balancer: requested IP "a.b.c.d" belongs to the Standard network tier; expected Premium

What if don't define "cloud.google.com/network-tier" and change the network tier of an IP?

1. Apply YAML without cloud.google.com/network-tier, but with specific IP (Premium).

2. Create another IP address with Standard network tier.

3. Change loadBalancerIP in YAML and apply.
For me it partially failed:

kubectl -n tests describe svc lb
...
Events:
  Type     Reason                  Age                   From                Message
  ----     ------                  ----                  ----                -------
  Normal   EnsuredLoadBalancer     10m                   service-controller  Ensured load balancer
  Normal   LoadbalancerIP          8m26s                 service-controller  old_ip -> new_ip

However, the status field of the Service still uses old ip.

status:
  loadBalancer:
    ingress:
    - ip: old_ip

And GCP console shows that the new IP isn't attached to anything. Old IP is still used.

I tried to modify the status field manually with kubectl -n tests edit svc lb --subresource=status but it didn't work - LoadBalancer went into Pending state and got stuck.

I didn't find a solution on how to make GKE/K8s to update an IP properly.