kubernetes/kops · error
instance group %q neither control-plane nor api-server
Error message
instance group %q neither control-plane nor api-server
What it means
createInternalLB (pkg/model/gcemodel/api_loadbalancer.go:184) classifies each API-serving instance group as control-plane or API-server-only; anything else cannot be attached to the API load balancer and is rejected. This catches specs where a non-control-plane, non-apiserver IG (e.g. a plain Node IG) is configured in a way that makes RunsAPIServer() true, or a role the classifier does not recognize.
Source
Thrown at pkg/model/gcemodel/api_loadbalancer.go:184
for _, ig := range b.InstanceGroups {
if !ig.RunsAPIServer() {
continue
}
if len(ig.Spec.Zones) > 1 {
return fmt.Errorf("instance group %q has %d zones, which is not yet supported for GCP", ig.GetName(), len(ig.Spec.Zones))
}
if len(ig.Spec.Zones) == 0 {
return fmt.Errorf("instance group %q must specify exactly one zone", ig.GetName())
}
zone := ig.Spec.Zones[0]
igm := &gcetasks.InstanceGroupManager{Name: s(gce.NameForInstanceGroupManager(b.Cluster.ObjectMeta.Name, ig.ObjectMeta.Name, zone)), Zone: s(zone)}
apiIGMs = append(apiIGMs, igm)
if ig.IsControlPlane() {
controlPlaneIGMs = append(controlPlaneIGMs, igm)
} else if ig.IsAPIServerOnly() {
requireEtcdLB = b.Cluster.UsesNoneDNS()
} else {
return fmt.Errorf("instance group %q neither control-plane nor api-server", ig.GetName())
}
}
backendService := &gcetasks.BackendService{
Name: s(b.NameForBackendService("api")),
Protocol: s("TCP"),
HealthChecks: []*gcetasks.HealthCheck{hc},
Lifecycle: b.Lifecycle,
LoadBalancingScheme: s("INTERNAL"),
InstanceGroupManagers: apiIGMs,
}
c.AddTask(backendService)
// controlPlaneBS is a backend service that only targets ControlPlane MIGs.
// It is used for kops-controller and etcd forwarding rules, which only run
// on ControlPlane nodes. When there are no dedicated APIServer IGs, this is
// the same set of backends as the API backend service.
controlPlaneBS := backendService
if b.HasAPIServerOnlyInstanceGroups() {View on GitHub (pinned to 4c8573c808)
Solutions
- Inspect the named IG's spec.role and fix it to ControlPlane (Master), Node, or APIServer as intended
- If a Node IG is wrongly marked as API-serving (e.g. kubelet api-server related flags), revert it via 'kops edit ig'
- Regenerate the IG with 'kops create ig' rather than hand-editing internal fields
- Upgrade/downgrade kOps to a version matching the spec's role semantics
Example fix
// before metadata: name: nodes spec: role: Node machineType: n1-standard-2 # plus stale apiserver-role fields left from a template // after metadata: name: apiserver spec: role: APIServer machineType: n1-standard-2
Defensive patterns
Strategy: validation
Validate before calling
for _, ig := range instanceGroups {
if ig.RunsAPIServer() && !ig.IsControlPlane() && !ig.IsAPIServerOnly() {
return fmt.Errorf("IG %q is API-serving but role %q is neither ControlPlane nor APIServer", ig.Name, ig.Spec.Role)
}
} Type guard
func classifiableAPIIG(ig *kops.InstanceGroup) bool {
return !ig.RunsAPIServer() || ig.IsControlPlane() || ig.IsAPIServerOnly()
} Prevention
- Use only standard roles (ControlPlane/Master, Node, APIServer) in GCP specs
- Avoid merging IG specs across clusters with kOps versions differing in role semantics
- Audit generated manifests for stale role fields after template changes
- Keep Node IGs free of API-server role markers
When it happens
Trigger: Looping over b.InstanceGroups, an IG with RunsAPIServer() true is neither IsControlPlane() nor IsAPIServerOnly() — typically a Node-role IG with an api-server role override, or a corrupted/legacy IG spec with role combinations the current kOps cannot classify.
Common situations: Hand-edited manifests mixing role fields; migrating clusters between kOps versions where the APIServer-only role handling changed; tooling that emits instance groups with unexpected role values.
Related errors
- unknown InstanceGroup Role %s
- instance group %q must specify exactly one zone
- error recreating Instance %s: %v
- error listing InstanceGroupManagers: %v
- error getting instance group for MIG %q
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/801546d18ef104d7.
Report an issue: GitHub.