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

  1. Restore the stock dns-controller manifest so its Deployment pod template has exactly one container
  2. If a sidecar is required, restructure it (e.g. separate Deployment) or update kops so the remapper tolerates extra containers
  3. Check the addon channel version matches the kops version; downgrade/upgrade the addon channel to a compatible release
  4. 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

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


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/69d2c3632d5ffa8d. Report an issue: GitHub.