kubernetes/kops · error
expected exactly one container in dns-controller Deployment,
Error message
expected exactly one container in dns-controller Deployment, found %d
What it means
The dns-controller addon remapper (dnscontroller.Remap) locates the single apps/v1 Deployment in the dns-controller manifest, parses its pod spec, and injects the IAM service-account role. It hard-codes the assumption that the Deployment runs exactly one container; if the parsed podSpec.Containers slice has any other length, the function aborts because per-container patches (volume mounts, env, annotation) would otherwise be ambiguous.
Source
Thrown at pkg/model/components/addonmanifests/dnscontroller/remap.go:57
}
if object.APIVersion() != "apps/v1" {
continue
}
deployments = append(deployments, object)
}
if len(deployments) != 1 {
return fmt.Errorf("expected exactly one Deployment in dns-controller manifest, found %d", len(deployments))
}
podSpec := &corev1.PodSpec{}
if err := deployments[0].Reparse(podSpec, "spec", "template", "spec"); err != nil {
return fmt.Errorf("failed to parse spec.template.spec from Deployment: %v", err)
}
containers := podSpec.Containers
if len(containers) != 1 {
return fmt.Errorf("expected exactly one container in dns-controller Deployment, found %d", len(containers))
}
if err := iam.AddServiceAccountRole(&context.IAMModelContext, podSpec, &ServiceAccount{}); err != nil {
return err
}
if err := deployments[0].Set(podSpec, "spec", "template", "spec"); err != nil {
return err
}
return nil
}
View on GitHub (pinned to 4c8573c808)
Solutions
- Restore the stock dns-controller manifest so its Deployment pod template has exactly one container
- If a sidecar is required, restructure it (e.g. separate Deployment) or update kops so the remapper tolerates extra containers
- Check the addon channel version matches the kops version; downgrade/upgrade the addon channel to a compatible release
- Verify the Deployment is apps/v1 and the containers live at spec.template.spec.containers
Example fix
# before (dns-controller.yaml, pod template)
containers:
- name: dns-controller
image: ...
- name: sidecar
image: ...
# after
containers:
- name: dns-controller
image: ... Defensive patterns
Strategy: validation
Validate before calling
// Before applying a custom dns-controller manifest, check container count:
var podSpec corev1.PodSpec
if err := obj.Reparse(&podSpec, "spec", "template", "spec"); err != nil { return err }
if len(podSpec.Containers) != 1 {
return fmt.Errorf("dns-controller Deployment must have exactly 1 container, found %d", len(podSpec.Containers))
} Type guard
func hasExactlyOneContainer(podSpec *corev1.PodSpec) bool {
return podSpec != nil && len(podSpec.Containers) == 1
} Try / catch
if err := dnscontroller.Remap(ctx, addon, objects); err != nil {
if strings.Contains(err.Error(), "expected exactly one container") {
// fall back to stock manifest or strip sidecar containers
}
return err
} Prevention
- Never add sidecar containers to the dns-controller Deployment when using IRSA in kops
- Pin the addon channel version to one matching your kops version
- Diff custom manifests against the stock channel manifest before applying
When it happens
Trigger: Calling RemapAddonManifest for the dns-controller.addons.k8s.io addon (with UseServiceAccountExternalPermissions enabled) where the manifest's spec.template.spec.containers list has 0 or >=2 entries — e.g. a hand-edited or newer upstream manifest added a sidecar container.
Common situations: Users overriding the dns-controller manifest via an older/newer addon channel version whose Deployment gained a sidecar (e.g. proxy or metrics container); custom manifests that omitted the main container; typo causing the container list to fail parsing into the expected single container.
Related errors
- expected exactly one Deployment in dns-controller manifest,
- failed to annotate %q: %w
- unhandled kind %q in %s
- must specify %q label with cluster name to replace SSHCreden
- spec.PublicKey is required
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/69d2c3632d5ffa8d.
Report an issue: GitHub.