kubernetes/kubernetes · info

external etcd detected, won't try to change any etcd state

Error message

external etcd detected, won't try to change any etcd state

What it means

Returned by performEtcdStaticPodUpgrade when cfg.Etcd.External != nil. It is a deliberate, non-fatal abort: kubeadm detects an externally-managed etcd and refuses to touch etcd state during a control-plane static-pod upgrade. The function returns fatal=false, signalling the caller that etcd upgrade was intentionally skipped rather than a hard failure.

Source

Thrown at cmd/kubeadm/app/phases/upgrade/staticpods.go:287

			return rollbackOldManifests(recoverManifests, err, pathMgr, recoverEtcd)
		}
	}

	// Wait for the static pod component to come up and register itself as a mirror pod
	if err := waiter.WaitForPodsWithLabel("component=" + component); err != nil {
		return rollbackOldManifests(recoverManifests, err, pathMgr, recoverEtcd)
	}

	fmt.Printf("[upgrade/staticpods] Component %q upgraded successfully!\n", component)

	return nil
}

// performEtcdStaticPodUpgrade performs upgrade of etcd, it returns bool which indicates fatal error or not and the actual error.
func performEtcdStaticPodUpgrade(certsRenewMgr *renewal.Manager, client clientset.Interface, waiter apiclient.Waiter, pathMgr StaticPodPathManager, cfg *kubeadmapi.InitConfiguration, recoverManifests map[string]string, oldEtcdClient, newEtcdClient etcdutil.ClusterInterrogator) (bool, error) {
	// Add etcd static pod spec only if external etcd is not configured
	if cfg.Etcd.External != nil {
		return false, errors.New("external etcd detected, won't try to change any etcd state")
	}

	// Checking health state of etcd before proceeding with the upgrade
	err := oldEtcdClient.CheckClusterHealth()
	if err != nil {
		return true, errors.Wrap(err, "etcd cluster is not healthy")
	}

	// Backing up etcd data store
	backupEtcdDir := pathMgr.BackupEtcdDir()
	runningEtcdDir := cfg.Etcd.Local.DataDir
	output, err := filesutil.CopyDir(runningEtcdDir, backupEtcdDir)
	if err != nil {
		return true, errors.Wrapf(err, "failed to back up etcd data, output: %q", output)
	}

	// Get the desired etcd version. That's either the one specified by the user in cfg.Etcd.Local.ImageTag
	// or the kubeadm preferred one for the desired Kubernetes version

View on GitHub (pinned to b882c60b40)

Solutions

  1. No action required for kubeadm: this is informational. Upgrade the external etcd cluster separately.
  2. If you expected stacked (local) etcd, verify your config does not set etcd.external; switch to local etcd config to let kubeadm manage etcd.
  3. Confirm the caller treats fatal=false as non-terminal (the upgrade of other static pods continues).
Defensive patterns

Strategy: validation

Validate before calling

if cfg.Etcd.External != nil {
    // external etcd: skip etcd upgrade, log and continue
    klog.Info("external etcd configured; skipping etcd static-pod upgrade")
    return nil
}
return performEtcdStaticPodUpgrade(...)

Try / catch

fatal, err := performEtcdStaticPodUpgrade(...)
if err != nil && !fatal && strings.Contains(err.Error(), "external etcd detected") {
    klog.Infof("skipping etcd upgrade: %v", err)
    err = nil
}

Prevention

When it happens

Trigger: Running 'kubeadm upgrade apply'/'upgrade node' on a cluster whose ClusterConfiguration.Etcd.External is populated (etcd endpoints/caCert/keyFile set), then kubeadm reaching the etcd static-pod upgrade phase via performEtcdStaticPodUpgrade.

Common situations: Clusters provisioned with external/managed etcd (e.g. etcd running on separate hosts or a managed service). This is expected and benign; the operator must upgrade external etcd themselves.

Related errors


AI-assisted analysis of kubernetes/kubernetes@b882c60b40 (2026-08-07). Data as JSON: /api/errors/bbc69c343c460e32. Report an issue: GitHub.