Issue
kubeadm pins the CoreDNS version to be deployed to a single flat constant (constants.CoreDNSVersion, currently v1.14.4), used regardless of which Kubernetes version is being installed or upgraded to. Users can already override the deployed CoreDNS tag via ClusterConfiguration.dns.imageTag, but several code paths reference the raw constant directly instead of the resolved/overridden value, so the override doesn't fully propagate everywhere it should:
- Corefile migration logic (
phases/addons/dns/dns.go) migrates toward the hardcoded constant rather than the actually-deployed/overridden tag.
- The CoreDNS upgrade preflight checks (
phases/upgrade/preflight.go) validate migration compatibility against the hardcoded constant.
- The suggested
DNSVersion shown by kubeadm upgrade plan (phases/upgrade/compute.go) is a flat constant instead of being computed per target Kubernetes version, unlike the sibling EtcdVersion on the same lines.
There's also a maintenance-side problem: the upstream CoreDNS version does not get updated once a Kubernetes release branch is cut, which forces kubeadm to keep carrying the same pinned CoreDNS dependency for the lifetime of that branch. Combined with the hardcoded constant, this means there is no supported way to move off an older CoreDNS build on an existing release branch even when upstream ships a newer one.
This matters beyond consistency: newer CoreDNS releases are rebuilt against newer Go toolchain versions, which routinely carry Go CVE fixes. Because the override doesn't propagate everywhere today, a user who explicitly sets dns.imageTag to a newer CoreDNS build to pick up those fixes doesn't get consistent behavior across kubeadm. The migration/preflight/upgrade-plan logic still reasons about the old hardcoded version instead of the version the user actually asked to run. Users should be able to opt into a newer, more secure CoreDNS build without kubeadm second-guessing that choice in some code paths but not others.
What did you expect to happen?
CoreDNS should follow the same override model that etcd already has:
- A
SupportedCoreDNSVersion map (keyed by Kubernetes minor version) with a resolver function
GetDNSImage a new GetDNSImageTag helper should resolve the default from that map (falling back to the nearest version with a warning if the target Kubernetes version isn't covered yet), then apply cfg.DNS.ImageTag on top if set.
- Corefile migration, the CoreDNS upgrade preflight checks, and the
kubeadm upgrade plan suggested DNSVersion should all consult the resolved/overridden version instead of the raw constant, so a user's override — including overriding to a newer CoreDNS build for CVE/security reasons — is honored consistently everywhere, not just in the deployed manifest.
This does not require any new API field — ClusterConfiguration.dns.imageTag dns.imageRepository already exist and already provide the override surface.
Created a PR addressing the changes -
Issue
kubeadm pins the CoreDNS version to be deployed to a single flat constant (
constants.CoreDNSVersion, currentlyv1.14.4), used regardless of which Kubernetes version is being installed or upgraded to. Users can already override the deployed CoreDNS tag viaClusterConfiguration.dns.imageTag, but several code paths reference the raw constant directly instead of the resolved/overridden value, so the override doesn't fully propagate everywhere it should:phases/addons/dns/dns.go) migrates toward the hardcoded constant rather than the actually-deployed/overridden tag.phases/upgrade/preflight.go) validate migration compatibility against the hardcoded constant.DNSVersionshown bykubeadm upgrade plan(phases/upgrade/compute.go) is a flat constant instead of being computed per target Kubernetes version, unlike the siblingEtcdVersionon the same lines.There's also a maintenance-side problem: the upstream CoreDNS version does not get updated once a Kubernetes release branch is cut, which forces kubeadm to keep carrying the same pinned CoreDNS dependency for the lifetime of that branch. Combined with the hardcoded constant, this means there is no supported way to move off an older CoreDNS build on an existing release branch even when upstream ships a newer one.
This matters beyond consistency: newer CoreDNS releases are rebuilt against newer Go toolchain versions, which routinely carry Go CVE fixes. Because the override doesn't propagate everywhere today, a user who explicitly sets
dns.imageTagto a newer CoreDNS build to pick up those fixes doesn't get consistent behavior across kubeadm. The migration/preflight/upgrade-plan logic still reasons about the old hardcoded version instead of the version the user actually asked to run. Users should be able to opt into a newer, more secure CoreDNS build without kubeadm second-guessing that choice in some code paths but not others.What did you expect to happen?
CoreDNS should follow the same override model that etcd already has:
SupportedCoreDNSVersionmap (keyed by Kubernetes minor version) with a resolver functionGetDNSImagea newGetDNSImageTaghelper should resolve the default from that map (falling back to the nearest version with a warning if the target Kubernetes version isn't covered yet), then applycfg.DNS.ImageTagon top if set.kubeadm upgrade plansuggestedDNSVersionshould all consult the resolved/overridden version instead of the raw constant, so a user's override — including overriding to a newer CoreDNS build for CVE/security reasons — is honored consistently everywhere, not just in the deployed manifest.This does not require any new API field —
ClusterConfiguration.dns.imageTagdns.imageRepositoryalready exist and already provide the override surface.Created a PR addressing the changes -