{"record":{"id":"087febc0f79ed903","repo":"kubernetes/kops","slug":"instance-group-q-has-d-zones-which-is-not-yet-s","errorCode":null,"errorMessage":"instance group %q has %d zones, which is not yet supported for GCP","messagePattern":"instance group %q has (.+?) zones, which is not yet supported for GCP","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/model/gcemodel/api_loadbalancer.go","lineNumber":171,"sourceCode":"\t\tName:      s(b.NameForHealthCheck(\"api\")),\n\t\tPort:      wellknownports.KubeAPIServer,\n\t\tProtocol:  gcetasks.HealthCheckProtocolTCP,\n\t\tLifecycle: b.Lifecycle,\n\t}\n\tc.AddTask(hc)\n\n\t// Collect ControlPlane and APIServer MIGs separately. The API backend service\n\t// includes both (both serve the kube-apiserver), while the kops-controller and\n\t// etcd backend services only include ControlPlane MIGs.\n\tvar apiIGMs []*gcetasks.InstanceGroupManager\n\tvar controlPlaneIGMs []*gcetasks.InstanceGroupManager // Currently these contain etcd instances\n\trequireEtcdLB := false\n\tfor _, ig := range b.InstanceGroups {\n\t\tif !ig.RunsAPIServer() {\n\t\t\tcontinue\n\t\t}\n\t\tif len(ig.Spec.Zones) > 1 {\n\t\t\treturn fmt.Errorf(\"instance group %q has %d zones, which is not yet supported for GCP\", ig.GetName(), len(ig.Spec.Zones))\n\t\t}\n\t\tif len(ig.Spec.Zones) == 0 {\n\t\t\treturn fmt.Errorf(\"instance group %q must specify exactly one zone\", ig.GetName())\n\t\t}\n\t\tzone := ig.Spec.Zones[0]\n\t\tigm := &gcetasks.InstanceGroupManager{Name: s(gce.NameForInstanceGroupManager(b.Cluster.ObjectMeta.Name, ig.ObjectMeta.Name, zone)), Zone: s(zone)}\n\t\tapiIGMs = append(apiIGMs, igm)\n\t\tif ig.IsControlPlane() {\n\t\t\tcontrolPlaneIGMs = append(controlPlaneIGMs, igm)\n\t\t} else if ig.IsAPIServerOnly() {\n\t\t\trequireEtcdLB = b.Cluster.UsesNoneDNS()\n\t\t} else {\n\t\t\treturn fmt.Errorf(\"instance group %q neither control-plane nor api-server\", ig.GetName())\n\t\t}\n\t}\n\tbackendService := &gcetasks.BackendService{\n\t\tName:                  s(b.NameForBackendService(\"api\")),\n\t\tProtocol:              s(\"TCP\"),","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/model/gcemodel/api_loadbalancer.go#L153-L189","documentation":"The GCE internal API load balancer model (pkg/model/gcemodel/api_loadbalancer.go:171) creates one regional InstanceGroupManager per zone. GCE internal LB support in kOps requires each API-serving instance group to be pinned to exactly one zone; if an IG spans multiple zones, createInternalLB cannot map it and returns this error naming the IG and zone count.","triggerScenarios":"createInternalLB (called from Build) encounters an instance group with RunsAPIServer() true whose spec.zones has length > 1 — e.g. a control-plane IG with zones [us-central1-a, us-central1-b] while using an internal (None-DNS) API load balancer.","commonSituations":"Multi-zone GCP clusters configured before GCP internal LB multi-zone support existed; templates built for AWS (which allows multi-zone IGs) reused for GCP; users adding zones to the control-plane IG for HA.","solutions":["Split the API-serving instance group into one IG per zone, each with a single zone in spec.zones","Or configure a public load balancer / DNS-based API endpoint if multi-zone internal LB is not supported by your kOps version","Upgrade kOps — newer versions may have relaxed this limitation; check release notes before restructuring","Run 'kops update cluster' to validate after re-zoning"],"exampleFix":"// before\nspec:\n  role: ControlPlane\n  zones: [us-central1-a, us-central1-b]\n// after (two instance groups)\n- role: ControlPlane\n  zones: [us-central1-a]\n- role: ControlPlane\n  zones: [us-central1-b]","handlingStrategy":"validation","validationCode":"for _, ig := range instanceGroups {\n\tif ig.Spec.Role == kops.InstanceGroupRoleControlPlane && len(ig.Spec.Zones) > 1 {\n\t\treturn fmt.Errorf(\"IG %q: GCP internal LB needs one zone per IG; split %v into separate IGs\", ig.Name, ig.Spec.Zones)\n\t}\n}","typeGuard":"func singleZoneAPIIG(ig *kops.InstanceGroup) bool {\n\treturn !ig.RunsAPIServer() || len(ig.Spec.Zones) == 1\n}","tryCatchPattern":null,"preventionTips":["On GCP, model HA as one control-plane IG per zone","Don't reuse AWS-style multi-zone IG templates for GCP","Check current kOps GCP docs for multi-zone internal LB support before adding zones","Run 'kops update cluster --target dry-run' after zone changes"],"tags":["kops","gcp","load-balancer","zones"],"backgroundTag":"multi-zone-instance-group-unsupported","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}