Known issues#
The MKE 4 known issues with available workarounds are described herein.
Post-install kubelet parameter modifications require a k0s restart#
Modifications made to the kubelet parameters in the mke4.yaml configuration
file after the initial MKE 4 installation require a restart of k0s on every
cluster node. To do this:
-
Wait for a short time, roughly 60 seconds after the application of the
mkectl applycommand, to give the pods time to enter theirRunningstate. -
Run the
systemctl restart k0scontrollercommand on all manager nodes and thesystemctl restart k0scontrollercommand on all worker nodes.
Upgrade may fail on clusters with two manager nodes#
MKE 3 upgrades to MKE 4 may fail on clusters that have only two manager nodes.
Info
Mirantis does not sanction upgrading MKE 3 clusters that have an even number of manager nodes. In general, having an even number of manager nodes is avoided in clustering systems due to quorum and availability factors.
Kube-proxy IPVS mode is not supported#
Kube-proxy IPVS mode has been deprecated and its removal from Kubernetes is in progress. MKE 3 clusters running kube-proxy in IPVS mode will need to be retired or migrated to another kube-proxy mode. Please contact Mirantis support.
Upgrade to MKE 4 fails if kubeconfig file is present in source MKE 3.x#
Upgrade to MKE 4 fails if the ~/.mke/mke.kubeconf file is present in the
source MKE 3.x system.
Workaround:
Make a backup of the old ~/.mke/mke.kubeconf file and then delete it.
MKE 3 clusters that use Calico in BPF mode cannot be upgraded to MKE 4#
You cannot upgrade MKE 3 clusters that are running Calico in BPF mode to MKE 4.
reset command must be run with --force flag#
You must run the reset command with the --force flag, as without this flag
the command will always return an error.
mkectl reset -f mke4.yaml
Example output:
time="2025-09-08T19:35:44-04:00" level=info msg="==> Running phase: Disconnect from hosts"
Error: reset requires --force
Addition of extra scopes with mkectl login causes CLI to authenticate twice#
When you create the kubeconfig with the mkectl login command and add extra
scopes using the --oidc-extra-scopes flag, the MKE 4 CLI attempts to authenticate
two times during the generation of the configuration and on each cluster
interaction with the generated kubeconfig.
Workaround:
When adding extra scopes to the --oidc-extra-scopes flag, make sure to also
add the offline_access scope. For example:
--oidc-extra-scopes=groups,offline_access`
mkectl config get command generates log lines that malform YAML output#
The mkectl config get command output contains log records at the
beginning of the generated output that invalidate the resulting YAML
configuration file.
Workaround:
Exclude unwanted logs by running the mkectl config get command with the higher
log level.
mkectl config get -l fatal
Pod logs do not display when MKE 4 is unininstalled and then reinstalled on same nodes#
If you uninstall MKE 4 and later try to reinstall it on the same nodes, the installation will succeed but the pods that run on manager nodes from the previous installation will not display logs and will present the following CA error:
tls: failed to verify certificate: x509: certificate signed by unknown authority (possibly because of "crypto/rsa: verification error" while trying to verify candidate authority certificate "kubernetes-ca"
Workaround:
-
Following the uninstallation of MKE 4, reboot the manager nodes before you reinstall the software.
-
Run the following command on each manager node:
rm -rf /var/lib/kubelet/
Child clusters with AWS nodes can hang in unavailable state#
Due to an issue with the AWS cloud provider, MKE 4 child clusters can hang in an unavailable state for operations wherein the control plane nodes are scaled down (recreated or removed, for example).
Workaround method 1:
Restart the CAPI manager pod in the k0rdent namespace. On its recreation, the pod will reconfigure the connection to the child cluster and continue the scale-down process.
Workaround method 2:
Mnually change the configuration of Network Load Balancer (NLB) target groups; however, to do this, you must:
-
Locate the NLB of the child cluster in the AWS console.
-
Set the target group to the listener port
6443. -
Enable Target deregistration management in the Attributes tab.
With this method, be aware that the target group can be reconciled by Cluster API Provider AWS (CAPA), which will result in the reversion of the configuration.
Use of --keep-ingress-nginx flag during upgrade requires two correlated flags#
To apply the --keep-ingress-nginx flag during an upgrade from a previous MKE
4 version to MKE 4.1.3 you must also apply both the
--ingress-nginx-alt-http-node-port flag and the
--ingress-nginx-alt-https-node-port flag, otherwise, the target cluster will
not be fully functional.
Long upgrade times from MKE 4.1.2 to version 4.1.5#
The upgrade from MKE 4.1.2 to version 4.1.5 may appear to stall while waiting for the Management resource to become ready, as this step can take a significant amount of time.
Example output:
DBG checking Management Ready condition
DBG k0rdent installation is not Ready, components status:
DBG capi: true
DBG kcm: true
DBG cluster-api-provider-aws: true
DBG cluster-api-provider-gcp: true
DBG cluster-api-provider-k0sproject-k0smotron: true
DBG cluster-api-provider-vsphere: true
DBG cluster-api-provider-azure: InfrastructureProvider is not yet ready: condition Ready is in status False
DBG mke-operator: true
DBG projectsveltos: true
DBG cluster-api-provider-docker: true
DBG cluster-api-provider-infoblox: true
DBG cluster-api-provider-ipam: true
DBG cluster-api-provider-openstack: true
No action is required. The upgrade will automatically proceed after 25–35 minutes.
Workaround:
To avoid the long wait, you can use kubectl to disable CAPI providers prior to running the upgrade.
Warning
Do not disable CAPI providers if you have child clusters as this will result in the loss of those child clusters.
kubectl patch management kcm \
--type='json' \
-p="$(kubectl get management kcm -o json | \
jq -c '[{"op":"replace","path":"/spec/providers","value":(.spec.providers | map(select(.name == "projectsveltos" or .name == "mke-operator")))}]')"
Use of Calico CNI with BPF dataplane requires customer intervention#
Due to a known Calico CNI
issue, MKE 4.1.5
customers using Calico CNI with BPF dataplane must disable
bpfConnectTimeLoadBalancing in the defaultfelixConfiguration configuration
of the Calico CNI configuration file:
defaultFelixConfiguration:
enabled: true
bpfConnectTimeLoadBalancing: Disabled
....
For fresh MKE 4 installations, this must be done at the time the cluster is created. To upgrade existing MKE 4.1.2 clusters with BPF dataplane to version 4.1.5, this must be done prior to the upgrade.
mkectl 4.1.5 backup command fails on clusters running versions earlier than MKE 4.1.5#
For mkectl 4.1.5 only, you cannot invoke the mkectl upgrade command with the
--backup-path option to make use of a manually created pre-upgrade backup.
Workaround:
Users must rely on the automatic backup that is created during the upgrade procedure.
mkectl cannot run in parallel across multiple clusters due to shared $HOME paths#
mkectl writes all kubeconfig, logs, and local state to fixed paths under the
invoking user's $HOME (for example, ~/.local/state/mke4-dsinfo/). Because these
paths are not namespaced per cluster, concurrent mkectl commands targeting
different clusters from the same host will overwrite each other's state.
As such, you cannot run operations against multiple clusters in parallel from
a single host — even when the commands are independent (for example, mkectl
apply against one cluster and mkectl upgrade against another from the same CI
host). Installing multiple mkectl versions side-by-side does not resolve the
issue, since the conflict is in the shared $HOME paths rather than in any
per-binary state.
Workaround:
Set a unique $HOME for each cluster before invoking mkectl:
HOME=/tmp/cluster-a mkectl apply ...
HOME=/tmp/cluster-b mkectl upgrade ...
This isolates each cluster's kubeconfig, logs, and state to its own directory,
allowing parallel installs and upgrades on the same host. Note that qa-mke
already uses this pattern.
Parallel mkectl upgrade invocations interfere with each other#
Running two mkectl upgrade commands concurrently on the same host — even
targeting different clusters — causes failures during the pre-upgrade backup
step. The root cause is that mkectl writes to hard-coded, non-namespaced paths
under the system root temp directory, /tmp on Linux, so concurrent runs
collide on such shared paths as /tmp/k0s, /tmp/mke4.yaml, and
/tmp/etcdctl.
Workaround:
Export a per-invocation TMPDIR before running the mkectl upgrade command:
TMPDIR=$(mktemp -d) mkectl upgrade ...
This causes the Go os.TempDir() to resolve to an invocation-specific path,
eliminating the collision without requiring file locks or serialization.
Parallel upgrades can proceed independently. Note that qa-mke already handles
this automatically by scoping a tempfile.TemporaryDirectory() to each phase
working directory.
Child clusters default to dev registry when registries is omitted#
When a MkeChildConfig is applied without an explicit registries block,
a child cluster is deployed using the development registry instead of the
production registry.
Workaround:
Always set the registries block explicitly in MkeChildConfig.spec.
apiVersion: mke.mirantis.com/v1alpha1
kind: MkeChildConfig
metadata:
name: my-mke-child
namespace: k0rdent
spec:
registries:
chartRegistry:
url: oci://registry.mirantis.com/mke
imageRegistry:
url: registry.mirantis.com/mke
Expiring certificates can cause control plane failure#
Cluster certificates may expire a year after install or upgrade from MKE 3, rendering control plane components non-functional.
Workaround:
Restart the k0s controller service on the manager nodes to force certificate recreation. If you have a load balancer for manager nodes, you can manually force cert rotation without any visible downtime.
SSH into each manager node, one by one, and run the following commands:
-
Remove the etcd server and peer certificates to force renewal:
rm -f /var/lib/k0s/pki/etcd/server.crt rm -f /var/lib/k0s/pki/etcd/server.key -
Restart the k0s controller service:
systemctl restart k0scontroller
projectsveltos component can become stuck if it fails to deploy#
If the projectsveltos component fails to deploy when the mkectl apply command is run, for
example because of temporary resource pressure on a node or a transient network
hiccup, it can become stuck in a failed state from which it cannot recover on its own.
When this happens, the command will not complete, even once the original cause has been cleared and mkectl apply
is run again. Other cluster components are not affected.
Workaround:
Trigger a fresh reconcile of the projectsveltos release to clear the failed state. To do this, run the following against the cluster:
ts=$(date +%s)
kubectl --kubeconfig ~/.mke/mke.kubeconf -n k0rdent annotate helmrelease projectsveltos \
reconcile.fluxcd.io/requestedAt="$ts" \
reconcile.fluxcd.io/resetAt="$ts" \
--overwrite
Once the release reconciles and reports as ready, mkectl apply will continue and successfully complete.
Dex refresh tokens accumulate for concurrent logins of the same user#
When multiple fresh logins for the same user occur simultaneously — for example,
parallel CI/CD jobs sharing a service account and using mkectl ROPC
(grant_type=password) — Dex creates a separate refreshtokens.dex.coreos.com
object for each login without deleting the previous ones. The race condition
leaves the user's single offlinesessions.dex.coreos.com object pointing to
only one of those tokens; the rest are orphaned.
Dex does not perform garbage collection for refresh tokens, so orphaned tokens accumulate indefinitely. Over time, this bloats Dex storage and etcd and can degrade performance.
Workaround:
To reduce the likelihood of the race condition, avoid making many simultaneous fresh logins under the same identity. Where possible, reuse the local token cache across pipeline runs so cached clients refresh in place rather than re-authenticate.
If the race condition is already occurring, run the following script to clean up orphaned
refresh tokens. The script is non-disruptive, as it keeps the token referenced by each
user's current offlinesessions object and deletes only the orphaned
duplicates. Adjust the namespace as necessary.
export KUBECONFIG=~/.mke/mke.kubeconf
declare -A live
for id in $(kubectl get offlinesessions.dex.coreos.com -n mke -o json | jq -r '.items[].refresh[].ID'); do
live[$id]=1
done
for rt in $(kubectl get refreshtokens.dex.coreos.com -n mke -o name | cut -d/ -f2); do
[[ ${live[$rt]} ]] || kubectl delete refreshtokens.dex.coreos.com -n mke "$rt"
done
Child clusters blocked as a result of Management cluster upgrade#
Child cluster deployments are blocked whenever the management cluster is upgraded to 4.2.0 from MKE 3.9.x or any MKE 4 version. As a result, some of the components that are needed to bootstrap and manage child clusters fail to install during the upgrade process.
Workaround:
Run the mkectl apply command to provision the missing components.
Fresh installation interrupted when the admin kubeconfig is not yet written#
The mkectl apply command for a fresh installation is interrupted during the
"Run k0sctl apply" phase, at the point where a k0s controller is up but the
admin kubeconfig has yet to be written to ~/.mke/mke.kubeconf. Re-running
mkectl apply then fails at the "Collect cluster facts" phase with the
following message:
Error: apply failed: phase 'Collect cluster facts' failed: unable to initialize kube clients:
... stat /home/<user>/.mke/mke.kubeconf: no such file or directory
Workaround:
Important
The workaround detailed herein applies only to an interrupted fresh MKE 4.2.0 installation, as there is no running cluster or jeopardized data.
-
Run the
mkectl reset --forcecommand, to tear down the interrupted installation. -
Run the
mkectl apply -f mke4.yamlcommand, to re-run the fresh install.
Windows worker nodes retain stale CNI state after reset#
The mkectl reset command intermittently leaves stale Calico Host
NetworkingService (HNS) state on a Windows worker node. When you subsequently
rejoin the node to a cluster, the Windows Pods scheduled to it remain in
the ContainerCreating state and do not receive a Pod IP; the affected Pod's
events report hcs::CreateComputeSystem ... The endpoint was not found.
To determine whether a node is affected, list its Calico HNS networks from an elevated PowerShell session. The presence of any such network confirms the issue:
Get-HnsNetwork | Where-Object { $_.Name -like '*calico*' -or $_.Name -eq 'External' }
Workaround:
Run the following in an elevated PowerShell session on the affected node:
-
If the node has already rejoined a cluster, stop the k0s worker service first, so the removal that follows does not hang. Skip this step on a node that was only reset.
Stop-Service k0sworker -Force -
Remove the stale Calico HNS endpoints and networks:
if (-not (Get-Command Get-HnsNetwork -ErrorAction SilentlyContinue)) { Import-Module (Join-Path $env:SystemRoot 'System32\WindowsPowerShell\v1.0\Modules\hns\hns.psm1') } Get-HnsEndpoint | Where-Object { $_.Name -like '*calico*' } | Remove-HnsEndpoint -ErrorAction SilentlyContinue Get-HnsNetwork | Where-Object { $_.Name -like '*calico*' -or $_.Name -eq 'External' } | Remove-HnsNetwork -ErrorAction SilentlyContinue -
If you stopped the k0s worker service, restart it (
Start-Service k0sworker); otherwise runmkectl applyto rejoin the node. Calico subsequently programs a clean HNS network, and the affected Pods will reach theRunningstate.
Info
If Remove-HnsNetwork hangs, reboot the node with Restart-Computer -Force. On restart, k0s and Calico cleanly reprogram the HNS dataplane.
Root certificate causes LDAP login failure after MKE 3 to MKE 4 upgrade#
When an MKE 3 cluster being upgraded to MKE 4 has an LDAP root certificate
configured through the rootCerts parameter, the
migration maps the PEM certificate content into the Dex file path
spec.authentication.ldap.ca rather than the raw certificate data file path
spec.authentication.ldap.caData. As a result, the LDAP connector fails to
initialize, and the following error is presented on MKE 4 LDAP login page:
Authentication error
Error type: Bad Request
Error message: Connector failed to initialize
Workaround:
Move the certificate content from ca to caData and clear the old ca value,
so the LDAP connector initializes and logins can succeed.
-
Copy the value from
catocaData:export KUBECONFIG=~/.mke/mke.kubeconf CA=$(kubectl get mkeconfig mke -n mke -o jsonpath='{.spec.authentication.ldap.ca}') kubectl patch mkeconfig mke -n mke --type merge \ -p "{\"spec\":{\"authentication\":{\"ldap\":{\"caData\":$(jq -Rs . <<<"$CA")}}}}" -
Remove the old
cakey:export KUBECONFIG=~/.mke/mke.kubeconf kubectl patch mkeconfig mke -n mke --type merge \ -p '{"spec":{"authentication":{"ldap":{"ca":null}}}}'
Controller node not added when it is first in the hosts list#
The mkectl apply command fails to add a controller node when that is placed
first in the hosts list in the mke4.yaml configuration file. The failure
occurs at the Sync Encryption Configuration step with:
✗ Sync Encryption Configuration
Error: unable to upload file 'encryption.cfg' to host <existing-controller>:
file /var/lib/k0s/encryption.cfg already exists and differs on node <existing-controller>
Note
The error names an existing controller, not the new node.
Workaround:
When you add or re-add a controller node to an existing cluster, place the host entry for the
new controller after the existing controllers on the host list in the mke4.yaml configuration file, then
run mkectl apply. Note that the new node can be placed ahead of any worker entries.
When the new controller node is first on the hosts list it causes the sync to treat
its empty or freshly generated encryption.cfg file as canonical and attempts to push
it onto the healthy controllers, which causes the operation to abort.
Nodes must be rebalanced following restore operation#
Following cluster restore, all of the MKE 4 system components run on the single
bootstrap node and are not automatically rebalanced when the remaining control
plane nodes rejoin as a result of the mkectl apply command. As such, although
all Pods report Running, critical management components remain on the
bootstrap node.
Workaround:
To restore High Availability and to enhance node use, once all of the control
plane nodes have rejoined the cluster and reported as Ready, force a rollout
to reschedule the components across the nodes:
kubectl rollout restart deployment -n mke
kubectl rollout restart deployment -n k0rdent
Info
Rebalancing is not a factor for clusters that have a single controller node.
Namespace-scoped grants migrated from MKE 3 do not inherit team membership#
When you upgrade from MKE 3 to MKE 4, a namespace-scoped Kubernetes grant held by a team or organization is migrated with its members captured at the moment of the upgrade. The migrated grant is not reconciled against team membership afterward: users added to the team after the upgrade do not receive that grant's access in the namespace. Members present at the time of the upgrade are unaffected, and cluster-wide grants are unaffected — they continue to track membership through the team's aggregated role.
In the Grants view, the migrated grant is indistinguishable from a grant created natively in MKE 4. Name, role, and role kind match; only the namespace differs. Nothing in the MKE Dashboard indicates that the grant will fail to extend to new members.
As an example, if organization acme has a team dev granted the admin role in the dev-ns namespace during the upgrade, a user added to dev after the upgrade is denied access to dev-ns, despite the grant appearing valid.
Workaround:
Re-create the affected grant in MKE 4:
- In the MKE Dashboard, navigate to Access Control > Grants.
- Create a new grant with the same team, role, and namespace as the migrated one.
A grant created in MKE 4 tracks team membership, and thus all current and future members receive access. Repeat this for any team whose membership changes after the upgrade and that held a namespace-scoped grant in MKE 3. The original migrated grant is harmless and additive, and you can delete it once you have re-created the grant.