На странице приведен список алертов мониторинга в Deckhouse Platform.
Список не содержит алертов подключаемых модулей.
Алерты сгруппированы по модулям. Справа от названия алерта указаны иконки минимальной редакции DP в которой доступен алерт и уровня критичности алерта (severity).
Для каждого алерта приведено краткое описание (summary), раскрыв которое можно увидеть подробное описание алерта (description), при их наличии.
Критичность алерта
В описании алертов присутствует параметр Severity (S), означающий уровень критичности. Его значение варьируется от S1 до S9 и может расцениваться следующим образом:
S1— максимальный уровень, критический сбой/авария (требуются незамедлительные действия);S2— высокий уровень, близкий к максимальному, возможная авария (необходимо быстрое реагирование);S3— средний уровень, потенциально серьёзная проблема (необходима проверка);S4-S9— низкий уровень. Есть проблема, но в целом работоспособность не нарушена.
Модуль admission-policy-engine
-
ControllerPolicyViolation
CE
S4
Pod-creating controllers in the XXX namespace violate the XXX policy, so their Pods are denied.
The
XXXpolicy (XXX) denies the Pods that violate it. For a transition period, it only warns about a violation in a pod-creating controller (Deployment, StatefulSet, DaemonSet, Job, CronJob, ReplicationController) instead of denying the controller. The controller is accepted, but it cannot create its Pods: the denial appears only in the events of the ReplicaSet or the controller.Controllers that violate the policy in the namespace: VALUE.
The
d8-pod-security-baselineandd8-pod-security-restrictedpolicies are the Pod Security Standards.To list the violating controllers and the rules they break, run the following Prometheus query:
count by (violating_kind, violating_name, kind, violation_msg) ( d8_gatekeeper_exporter_constraint_violations{ source_type="XXX", name=~"d8-controllers-XXXXXX-deny(-d8)?(-default)?XXX", violating_namespace="XXX" } )Bring the pod template of each controller in line with the policy. To deny such controllers instead of warning about them, set
spec.controllerValidation.mode: Enforcein the policy, or thepodSecurityStandards.controllerValidationEnforcementmodule parameter toPolicy. You can also check the admission-policy-engine reports in the Deckhouse web interface. -
The audit controller of admission-policy-engine has no available replicas.
The
gatekeeper-auditDeployment in thed8-admission-policy-enginenamespace has no available replicas.Admission of new objects is not affected, but the module stops reporting and stops picking up new policies:
- Violations among the objects that already run are not collected, so the
PodSecurityStandardsViolation,OperationPolicyViolationandSecurityPolicyViolationalerts go silent instead of reporting that all is well. - The list of resources the webhook intercepts is not updated, so a policy added while the audit is down is not enforced on admission.
Find out why the replica is gone:
d8 k -n d8-admission-policy-engine get pods -l app=gatekeeper,control-plane=audit-controller d8 k -n d8-admission-policy-engine describe pods -l app=gatekeeper,control-plane=audit-controller d8 k -n d8-admission-policy-engine logs deploy/gatekeeper-audit -c manager --tail=200 d8 k -n d8-admission-policy-engine logs deploy/gatekeeper-audit -c constraint-exporter --tail=200 - Violations among the objects that already run are not collected, so the
-
D8AdmissionPolicyEngineNotBootstrapped
CE
S7
Not every ConstraintTemplate of the admission-policy-engine module is ready for 10 minutes.
Some ConstraintTemplates of the admission-policy-engine module are missing or not processed by Gatekeeper. The constraints of a template are applied only once Gatekeeper has established its CRD.
On a new installation, the module also renders no webhooks and no policies until every template is ready. In a cluster where the module has already worked, the webhooks and the constraints of the other templates stay in effect.
Steps to troubleshoot:
-
Verify that the module’s components are up and running:
d8 k get pods -n d8-admission-policy-engine -
Check logs for issues, such as missing constraint templates or incomplete CRD creation:
d8 k logs -n d8-system -lapp=deckhouse --tail=1000 | grep admission-policy-engine
-
-
D8AdmissionPolicyEngineWebhookDegraded
CE
S3
The admission webhook of admission-policy-engine has unavailable replicas.
The
gatekeeper-controller-managerDeployment in thed8-admission-policy-enginenamespace has unavailable replicas, and the remaining ones still serve admission requests.The webhook has no redundancy left. Losing the last replica makes the API server reject every request the webhook intercepts, because the webhook has
failurePolicy: Fail.A rollout of the Deployment raises this alert for a short time and needs no action. If the alert holds, find out why the replica does not start:
d8 k -n d8-admission-policy-engine get pods -l app=gatekeeper,control-plane=controller-manager -o wide d8 k -n d8-admission-policy-engine describe pods -l app=gatekeeper,control-plane=controller-manager d8 k -n d8-admission-policy-engine get events --sort-by=.lastTimestamp | tail -30 -
D8AdmissionPolicyEngineWebhookNotServing
CE
S2
The API server cannot call the admission webhook of admission-policy-engine.
The API server is rejecting requests because it fails to call a webhook of the
admission-policy-enginemodule. The webhook hasfailurePolicy: Fail, so the cluster is blocked for everything the webhook intercepts.The alert is independent of the replica counters: it fires while the pods are
Readyas well. A replica that is running but unreachable to the API server produces the same outage, and only this alert reports it. Typical causes are agatekeeper-webhook-server-certthat no longer matches thecaBundleof the ValidatingWebhookConfiguration, an emptygatekeeper-webhook-serviceendpoint list, and a network policy that blocks the API server.The API server counts a webhook that exceeds its
timeoutSecondsof 15 the same way it counts one it cannot reach, so a few slow evaluations of a large object raise the metric as well. They do not raise the alert:for: 15mrequires the failures to continue, while a burst leaves the rate elevated for little more than its own duration plus the five-minute window.Read the reason the API server reports, then check the certificate and the endpoints:
d8 k -n d8-admission-policy-engine logs deploy/gatekeeper-controller-manager -c manager --all-pods=true --tail=200 d8 k -n d8-admission-policy-engine get endpoints gatekeeper-webhook-service d8 k get validatingwebhookconfiguration d8-admission-policy-engine-config -o jsonpath='{.webhooks[0].clientConfig.caBundle}' | base64 -d | openssl x509 -noout -subject -dates d8 k -n d8-admission-policy-engine get secret gatekeeper-webhook-server-cert -o jsonpath='{.data.ca\.crt}' | base64 -d | openssl x509 -noout -subject -datesThe two certificates must match. Deckhouse Platform reissues them through the module’s hook, so deleting the secret makes it regenerate the pair.
-
The admission webhook of admission-policy-engine has no available replicas.
The
gatekeeper-controller-managerDeployment in thed8-admission-policy-enginenamespace has no available replicas.The Deployment serves the admission webhook of the module, and the webhook has
failurePolicy: Fail. While no replica is available, the API server rejects every request the webhook intercepts, cluster-wide:- Pods and the controllers that create them are not created or updated.
- Deletion of those resources is rejected as well.
- Roles, RoleBindings and Gatekeeper constraints are not applied.
- The
d8 k exec,d8 k attachandd8 k debugrequests intercepted by the webhooks are rejected. This includesd8 k execandd8 k attachin thed8-*andkube-*namespaces.
Find out why the replicas are gone:
d8 k -n d8-admission-policy-engine get deploy gatekeeper-controller-manager d8 k -n d8-admission-policy-engine get pods -l app=gatekeeper,control-plane=controller-manager -o wide d8 k -n d8-admission-policy-engine describe pods -l app=gatekeeper,control-plane=controller-manager d8 k -n d8-admission-policy-engine logs deploy/gatekeeper-controller-manager -c manager --all-pods=true --tail=200If a pod stays
Pending, look at the events of the namespace and at the nodes the replicas can run on:d8 k -n d8-admission-policy-engine get events --sort-by=.lastTimestamp | tail -30 d8 k get nodes -l node-role.deckhouse.io/system d8 k get nodes -l node-role.kubernetes.io/control-plane -
OperationPolicyViolation
CE
S3
XXXObjects in the XXX namespaceXXXCluster-scoped objectsXXX violate the XXX OperationPolicy.
Existing objects XXXin the
XXXnamespace XXXof cluster-scoped kinds XXXviolate theXXXOperationPolicy. An object is checked when it is created or updated, so these objects were created before the policy applied to them or before its rules changed.Objects that violate the policy: VALUE.
To list the violating objects and the rules they break, run the following Prometheus query:
count by (violating_kind, violating_name, kind, violation_msg) ( d8_gatekeeper_exporter_constraint_violations{ source_type="OperationPolicy", name="XXX", violation_enforcement="deny", violating_namespace="XXX" } )Bring the objects in line with the policy. You can also check the admission-policy-engine reports in the Deckhouse web interface.
-
PodSecurityStandardsViolation
CE
S3
Pods in the XXX namespace violate the XXX Pod Security Standard.
Running Pods in the
XXXnamespace violate the Pod Security Standard published as theXXXSecurityPolicy. A Pod is checked when it is created, so these Pods were created before the standard applied to them or before its rules changed. They keep running until they are restarted, and are denied then.Pods that violate the standard in the namespace: VALUE.
To list the violating Pods and the rules they break, run the following Prometheus query:
count by (violating_name, kind, violation_msg) ( d8_gatekeeper_exporter_constraint_violations{ source_type="PSS", name=~"XXX-.+", violation_enforcement="deny", violating_kind="Pod", violating_namespace="XXX" } )Bring the workloads in line with the standard, or exempt them with a SecurityPolicyException. You can also check the admission-policy-engine reports in the Deckhouse web interface.
-
SecurityPolicyViolation
CE
S3
XXXObjects in the XXX namespaceXXXCluster-scoped objectsXXX violate the XXX SecurityPolicy.
Existing objects XXXin the
XXXnamespace XXXof cluster-scoped kinds XXXviolate theXXXSecurityPolicy. An object is checked when it is created or updated, so these objects were created before the policy applied to them or before its rules changed.Objects that violate the policy: VALUE.
To list the violating objects and the rules they break, run the following Prometheus query:
count by (violating_kind, violating_name, kind, violation_msg) ( d8_gatekeeper_exporter_constraint_violations{ source_type="SecurityPolicy", name="XXX", violation_enforcement="deny", violating_namespace="XXX" } )Bring the objects in line with the policy, or exempt them with a SecurityPolicyException. You can also check the admission-policy-engine reports in the Deckhouse web interface.
Модуль cert-manager
-
CertmanagerCertificateChallengePending
CE
S4
ACME Challenge for domain "XXX" is pending for more than 1 hour.
The ACME Challenge
NAMESPACE/NAMEfor domainXXXhas been inpendingstate for more than 1 hour and requires investigation.Common causes:
- DNS misconfiguration (for DNS-01 challenges).
- Ingress or firewall issues blocking HTTP-01 validation.
- ACME provider rate limiting.
- Network connectivity issues.
Resolution steps:
- Check the Challenge status and reason:
d8 k -n NAMESPACE describe challenge NAME - Check
cert-managerlogs for errors:d8 k -n d8-cert-manager logs -l app=cert-manager -c cert-manager --tail=100 - If the challenge is stuck, delete the Order to trigger a retry:
d8 k -n NAMESPACE get orders d8 k -n NAMESPACE delete order ORDER_NAME
-
CertmanagerCertificateChallengePending
CE
S6
ACME Challenge for domain "XXX" is pending for more than 10 minutes.
The ACME Challenge
NAMESPACE/NAMEfor domainXXXhas been inpendingstate for more than 10 minutes.This may indicate issues with the ACME challenge validation process.
Common causes:
- DNS propagation delays (for DNS-01 challenges).
- Ingress or firewall issues blocking HTTP-01 validation.
- ACME provider rate limiting or temporary unavailability.
Diagnostic steps:
- Check the Challenge status:
d8 k -n NAMESPACE describe challenge NAME - Check
cert-managerlogs for errors:d8 k -n d8-cert-manager logs -l app=cert-manager -c cert-manager --tail=100
-
CertmanagerCertificateChallengeStuck
CE
S4
ACME Challenge for domain "XXX" is stuck in "STATUS_REFERENCE" state.
The ACME Challenge
NAMESPACE/NAMEfor domainXXXis inSTATUS_REFERENCEstate and requires manual intervention.Reason: XXX
The certificate will not be issued or renewed until the issue is resolved.
Common causes:
- DNS misconfiguration (for DNS-01 challenges).
- Ingress or firewall issues (for HTTP-01 challenges).
- Rate limiting by the ACME provider.
- Authorization expired before challenge completion.
Resolution steps:
- Check the Challenge status and reason:
d8 k -n NAMESPACE describe challenge NAME - Delete the failed Order to trigger a new certificate request:
d8 k -n NAMESPACE get orders d8 k -n NAMESPACE delete order ORDER_NAME
-
CertmanagerCertificateExpired
CE
S4
Certificate NAMESPACE/NAME is not provided.
Certificate is not provided.
To check the certificate details, run the following command:
d8 k -n NAMESPACE describe certificate NAME -
CertmanagerCertificateExpiredSoon
CE
S4
Certificate will expire soon.
The certificate
NAMESPACE/NAMEwill expire in less than two weeks.To check the certificate details, run the following command:
d8 k -n NAMESPACE describe certificate CERTIFICATE-NAME -
CertmanagerCertificateOrderErrors
CE
S5
Cert-manager couldn't order a certificate.
Cert-manager received responses with the status code
STATUS_REFERENCEwhen requestingSCHEME://HOST_NAMEPATH.This can affect certificate ordering and prolongation in the future. For details, check the cert-manager logs using the following command:
d8 k -n d8-cert-manager logs -l app=cert-manager -c cert-manager
Модуль chrony
-
NodeTimeOutOfSync
CE
S5
Clock on the node NODE_NAME is drifting.
Time on the node
NODE_NAMEis out of sync and drifts apart from the NTP server clock by VALUE seconds.To resolve the time synchronization issues:
- Fix network errors:
- Ensure the upstream time synchronization servers defined in the chrony configuration are available.
- Eliminate large packet loss and excessive latency to upstream time synchronization servers.
- Modify the NTP servers list defined in the chrony configuration.
- Fix network errors:
-
NTPDaemonOnNodeDoesNotSynchronizeTime
CE
S5
NTP daemon on the node NODE_NAME haven't synchronized time for too long.
Steps to troubleshoot:
-
Check if the chrony pod is running on the node by executing the following command:
d8 k -n d8-chrony --field-selector spec.nodeName="NODE_NAME" get pods -
Verify the chrony daemon’s status by executing the following command:
d8 k -n d8-chrony exec POD_NAME -- /opt/chrony-static/bin/chronyc sources -
Resolve the time synchronization issues:
- Fix network errors:
- Ensure the upstream time synchronization servers defined in the chrony configuration are available.
- Eliminate large packet loss and excessive latency to upstream time synchronization servers.
- Modify the NTP servers list defined in the chrony configuration.
- Fix network errors:
-
Модуль cloud-provider-aws
-
D8CloudProviderAWSIMDSv2NotConverged
CE
S6
Some EC2 instances of the cluster still allow IMDSv1.
imdsv2: trueis set inAWSClusterConfiguration, but VALUE EC2 instances of the cluster still accept metadata requests without a session token, which leaves them more exposed to unauthorized metadata access, including through SSRF attacks.Existing instances are not reconfigured by the setting alone:
- Master, static and bastion instances are updated by a converge run. Start the DKP installer and run
dhctl converge. - Ephemeral instances are re-created when their nodes are rolled, which happens on its own. Check that the nodes of every
CloudEphemeralNodeGroup are being replaced:d8 k get nodegroups.
The instance state is re-read once per discovery period of the cloud data discoverer (one hour by default), so the alert can lag behind the last node being replaced.
- Master, static and bastion instances are updated by a converge run. Start the DKP installer and run
Модуль cloud-provider-dvp
-
D8CloudProviderDVPMigrationPending
CE
S6
The cloud-provider-dvp module is waiting for migration resources to be applied.
The
cloud-provider-dvpmodule has detected the legacyDVPProviderClusterConfigurationsecret in the cluster and is waiting for the new migration resources (ModuleConfig v2, CredentialSecret, NodeGroups, InstanceClasses) to be applied before completing the migration.To complete the migration, apply the resources from the
d8-migration-resourcesSecret:d8 k -n d8-cloud-provider-dvp get secret d8-migration-resources -o jsonpath='{.data.resources\.yaml}' | base64 -d | d8 k apply -f -After applying the resources, the alert will disappear automatically once the module detects that all required resources are in place.
Модуль cloud-provider-huaweicloud
-
D8HuaweiCloudMachineStuckInDeleting
EE
S6
HuaweiCloudMachine NAME is stuck in Deleting for more than 24h.
The HuaweiCloudMachine
NAMEin namespaceNAMESPACEhas been stuck in Deleting state for more than 24 hours.This usually means the deletion job in HuaweiCloud is failing or the API is unavailable.
To inspect the machine status, run:
d8 k get huaweicloudmachine -n NAMESPACE NAME -o yamlCheck the controller logs for errors:
d8 k logs -n d8-cloud-provider-huaweicloud -l app=caphc-controller-manager
Модуль cloud-provider-openstack
-
OpenStackPreemptibleUnsupported
EE
S8
NodeGroup NODE_GROUP_NAME requests preemptible instances, but this cluster cannot deliver them (reason: XXX).
The OpenStackInstanceClass referenced by NodeGroup
NODE_GROUP_NAMEhasspec.preemptible: true, but the raw Novapreemptibletag will not reach the virtual machines: nodes are created as regular (non-preemptible) VMs, and Selectel-side preemption never kicks in.XXX Reason: the NodeGroup runs on the MCM engine, which has no way to emit raw Nova tags —
machine-controller-manager’s OpenStackMachineClass CRD does not expose the field. Only the CAPI engine (capi-controller-manager+capo-controller-manager) renders raw Nova tags viaOpenStackMachineTemplate.spec.template.spec.tags.How to fix:
-
Confirm the current engine and offending InstanceClass:
d8 k get ng NODE_GROUP_NAME -o jsonpath='{.status.engine}{"\n"}' d8 k get ng NODE_GROUP_NAME -o jsonpath='{.spec.cloudInstances.classReference}{"\n"}' -
Choose one of the following actions:
-
Recommended. Remove the
node.deckhouse.io/use-mcmannotation from the NodeGroup so it migrates to CAPI. Nodes will be recreated on the CAPI engine, this time carrying thepreemptibletag:d8 k annotate ng NODE_GROUP_NAME node.deckhouse.io/use-mcm- -
Alternatively, if this NodeGroup must stay on MCM, set
spec.preemptible: falseon the OpenStackInstanceClass (nodes stay regular, the alert clears):d8 k patch openstackinstanceclass CLASS_NAME --type=merge -p '{"spec":{"preemptible":false}}'Note: a single OpenStackInstanceClass shared between a CAPI NodeGroup (where the field works) and an MCM one (where it doesn’t) will keep firing this alert on the MCM side. Use separate InstanceClasses per engine when the classes differ in
preemptible.
-
XXX Reason: the cluster’s
connection.authURLdoes not point at Selectel (selcloud.ru/selectel). The raw Novapreemptibletag is a Selectel-specific mechanism; on other OpenStack providers Nova accepts the tag but ignores it, so instances are billed and behave as regular non-preemptible VMs.How to fix:
-
Confirm the offending InstanceClass and the cluster’s authURL:
d8 k get ng NODE_GROUP_NAME -o jsonpath='{.spec.cloudInstances.classReference}{"\n"}' d8 k -n kube-system get secret d8-node-manager-cloud-provider -o jsonpath='{.data.openstack}' | base64 -d | jq -r '.connection.authURL' -
Set
spec.preemptible: falseon the OpenStackInstanceClass — the field only makes sense on Selectel-hosted clusters:d8 k patch openstackinstanceclass CLASS_NAME --type=merge -p '{"spec":{"preemptible":false}}'The alert clears on the next scrape after the change; existing nodes stay running (they are already regular VMs — the tag was never emitted).
XXX Reason: unknown (
XXX). This alert should surface only two well-known cases (mcm,non-selectel). A new reason implies node-controller has been extended without this runbook — check the release notes forcloud-provider-openstackbefore deciding what to do. XXX -
Модуль cloud-provider-yandex
-
D8CloudProviderYandexCloudMigrationPending
CE
S6
The cloud-provider-yandex module is waiting for migration resources to be applied.
The
cloud-provider-yandexmodule has detected the legacyYandexProviderClusterConfigurationsecret in the cluster and is waiting for the new migration resources (ModuleConfig v2, CredentialSecret, NodeGroups, InstanceClasses) to be applied before completing the migration.To complete the migration, apply the resources from the
d8-migration-resourcesSecret:d8 k -n d8-cloud-provider-yandex get secret d8-migration-resources -o jsonpath='{.data.resources\.yaml}' | base64 -d | d8 k apply -f -After applying the resources, the alert will disappear automatically once the module detects that all required resources are in place.
After the migration is complete, the legacy
YandexProviderClusterConfigurationsecret is no longer needed and can be deleted manually:-
Make sure the cloud discovery data is stored outside the legacy secret. The module reads it from the
d8-candi-cloud-provider-discovery-dataSecret first and uses the legacy secret only as a fallback, so the following command must print a non-empty value:d8 k -n d8-cloud-provider-yandex get secret d8-candi-cloud-provider-discovery-data -o jsonpath='{.data.cloud-provider-discovery-data\.json}'If it prints nothing, the discovery data exists only in the legacy secret, and deleting that secret would lose it. Copy the payload over — the key holds exactly the same discovery data dhctl recorded from the infrastructure run:
d8 k -n kube-system get secret d8-provider-cluster-configuration \ -o jsonpath='{.data.cloud-provider-discovery-data\.json}' | base64 -d > /tmp/yandex-discovery.json d8 k -n d8-cloud-provider-yandex create secret generic d8-candi-cloud-provider-discovery-data \ --from-file=cloud-provider-discovery-data.json=/tmp/yandex-discovery.json \ --dry-run=client -o yaml | d8 k apply -f - -
Back up the secret. It contains cloud credentials and discovery data, so store the file securely:
d8 k -n kube-system get secret d8-provider-cluster-configuration -o yaml > d8-provider-cluster-configuration-backup.yaml -
Allow the deletion. The secret is protected by an admission webhook and cannot be deleted without the annotation:
d8 k -n kube-system annotate secret d8-provider-cluster-configuration deckhouse.io/allow-delete=true -
Delete the secret:
d8 k -n kube-system delete secret d8-provider-cluster-configuration
-
-
D8YandexNatInstanceConnectionsQuotaUtilization
CE
S4
Connection quota utilization of the Yandex NAT instance exceeds 85% over the last 5 minutes.
The connection quota for the Yandex NAT instance has exceeded 85% utilization over the past 5 minutes.
To prevent potential issues, contact Yandex technical support and request an increase in the connection quota.
-
NATInstanceWithDeprecatedAvailabilityZone
CE
S9
NAT instance NAME is in a deprecated availability zone.
The NAT instance
NAMEis located in the availability zoneru-central1-c, which has been deprecated by Yandex Cloud. To resolve this issue, migrate the NAT instance to eitherru-central1-aorru-central1-bby following the instructions below.The migration process involves irreversible changes and may result in a significant downtime. The duration typically depends on Yandex Cloud’s response time and can last several tens of minutes.
-
Migrate the NAT instance. To get
providerClusterConfiguration.withNATInstance, run the following command:d8 k -n d8-system exec -ti svc/deckhouse-leader -c deckhouse -- deckhouse-controller module values -g cloud-provider-yandex -o json | jq -c | jq '.cloudProviderYandex.internal.providerClusterConfiguration.withNATInstance'-
If you specified
withNATInstance.natInstanceInternalAddressand/orwithNATInstance.internalSubnetIDinproviderClusterConfiguration, remove them using the following command:d8 system edit provider-cluster-configuration -
If you specified
withNATInstance.externalSubnetIDand/orwithNATInstance.natInstanceExternalAddressinproviderClusterConfiguration, change them to the appropriate values.To get the address and subnet ID, use the Yandex Cloud Console or CLI.
To change
withNATInstance.externalSubnetIDandwithNATInstance.natInstanceExternalAddress, run the following command:d8 system edit provider-cluster-configuration
-
-
Run the appropriate edition and version of the Deckhouse installer container on the local machine. You may have to change the container registry address to do that. After that, perform the converge.
-
Get the appropriate edition and version of Deckhouse:
DH_VERSION=$(d8 k -n d8-system get deployment deckhouse -o jsonpath='{.metadata.annotations.core\.deckhouse\.io\/version}') DH_EDITION=$(d8 k -n d8-system get deployment deckhouse -o jsonpath='{.metadata.annotations.core\.deckhouse\.io\/edition}' | tr '[:upper:]' '[:lower:]') echo "DH_VERSION=$DH_VERSION DH_EDITION=$DH_EDITION" -
Run the installer:
docker run --pull=always -it -v "$HOME/.ssh/:/tmp/.ssh/" registry.deckhouse.io/deckhouse/${DH_EDITION}/install:${DH_VERSION} bash -
Perform the converge:
dhctl converge --ssh-agent-private-keys=/tmp/.ssh/SSH_KEY_FILENAME --ssh-user=USERNAME --ssh-host MASTER-NODE-0-HOST
-
-
Update the route table.
-
Get the route table name:
d8 k -n d8-system exec -ti svc/deckhouse-leader -c deckhouse -- deckhouse-controller module values -g cloud-provider-yandex -o json | jq -c | jq '.global.prefix // .global.clusterConfiguration.cloud.prefix' -
Get the NAT instance name:
d8 k -n d8-system exec -ti svc/deckhouse-leader -c deckhouse -- deckhouse-controller module values -g cloud-provider-yandex -o json | jq -c | jq '.cloudProviderYandex.internal.providerDiscoveryData.natInstanceName' -
Get the NAT instance internal IP address:
yc compute instance list | grep -e "INTERNAL IP" -e NAT_INSTANCE_NAME_FROM_PREVIOUS_STEP -
Update the route:
yc vpc route-table update --name ROUTE_TABLE_NAME_FROM_PREVIOUS_STEP --route "destination=0.0.0.0/0,next-hop=NAT_INSTANCE_INTERNAL_IP_FROM_PREVIOUS_STEP"
-
-
-
NodeGroupNodeWithDeprecatedAvailabilityZone
CE
S9
NodeGroup NODE_GROUP_NAME contains nodes in a deprecated availability zone.
Certain nodes in the node group
NODE_GROUP_NAMEare located in the availability zoneru-central1-c, which has been deprecated by Yandex Cloud.Steps to troubleshoot:
-
Identify the nodes that need to be migrated by running the following command:
d8 k get node -l "topology.kubernetes.io/zone=ru-central1-c" -
Migrate your nodes, disks, and load balancers to one of the supported zones:
ru-central1-a,ru-central1-b, orru-central1-d. Refer to the Yandex migration guide for detailed instructions.You can’t migrate public IP addresses between zones. For details, refer to the migration guide.
-
Модуль cloud-provider-zvirt
-
D8CloudProviderZvirtMigrationPending
SE-PLUS
S6
The cloud-provider-zvirt module is waiting for migration resources to be applied.
The
cloud-provider-zvirtmodule has detected the legacyZvirtClusterConfigurationsecret in the cluster and is waiting for the new migration resources (ModuleConfig v2, CredentialSecret, NodeGroups, InstanceClasses) to be applied before completing the migration.To complete the migration, apply the resources from the
d8-migration-resourcesSecret:d8 k -n d8-cloud-provider-zvirt get secret d8-migration-resources -o jsonpath='{.data.resources\.yaml}' | base64 -d | d8 k apply -f -After applying the resources, the alert will disappear automatically once the module detects that all required resources are in place.
After the migration is complete, the legacy
ZvirtProviderClusterConfigurationsecret is no longer needed and can be deleted manually:-
Make sure the cloud discovery data is stored outside the legacy secret. The module reads it from the
d8-candi-cloud-provider-discovery-dataSecret first and uses the legacy secret only as a fallback, so the following command must print a non-empty value:d8 k -n d8-cloud-provider-zvirt get secret d8-candi-cloud-provider-discovery-data -o jsonpath='{.data.cloud-provider-discovery-data\.json}'If it prints nothing, the discovery data exists only in the legacy secret, and deleting that secret would lose it. Copy the payload over — the key holds exactly the same discovery data dhctl recorded from the infrastructure run:
d8 k -n kube-system get secret d8-provider-cluster-configuration \ -o jsonpath='{.data.cloud-provider-discovery-data\.json}' | base64 -d > /tmp/zvirt-discovery.json d8 k -n d8-cloud-provider-zvirt create secret generic d8-candi-cloud-provider-discovery-data \ --from-file=cloud-provider-discovery-data.json=/tmp/zvirt-discovery.json \ --dry-run=client -o yaml | d8 k apply -f - -
Back up the secret. It contains cloud credentials and discovery data, so store the file securely:
d8 k -n kube-system get secret d8-provider-cluster-configuration -o yaml > d8-provider-cluster-configuration-backup.yaml -
Allow the deletion. The secret is protected by an admission webhook and cannot be deleted without the annotation:
d8 k -n kube-system annotate secret d8-provider-cluster-configuration deckhouse.io/allow-delete=true -
Delete the secret:
d8 k -n kube-system delete secret d8-provider-cluster-configuration
-
Модуль cni-cilium
-
CiliumAgentEndpointsNotReady
CE
S4
Over 50% of all known endpoints aren't ready in agent NAMESPACE/POD_NAME.
For details, refer to the logs of the agent:
d8 k -n NAMESPACE logs POD_NAME -
CiliumAgentMapPressureCritical
CE
S4
eBPF map MAP_NAME exceeds 90% utilization in agent NAMESPACE/POD_NAME.
The eBPF map resource utilization limit has almost been reached.
Check with the vendor for potential remediation steps.
-
CiliumAgentMetricNotFound
CE
S4
Agent NAMESPACE/POD_NAME isn't sending some metrics.
Steps to troubleshoot:
-
Check the logs of the agent:
d8 k -n NAMESPACE logs POD_NAME -
Verify the agent’s health status:
d8 k -n NAMESPACE exec -ti POD_NAME cilium-health status -
Compare the metrics with those of a neighboring agent.
Note that the absence of metrics can indirectly indicate that new pods can’t be created on the node due to connectivity issues with the agent.
-
-
CiliumAgentPolicyImportErrors
CE
S4
Agent NAMESPACE/POD_NAME fails to import policies.
For details, refer to the logs of the agent:
d8 k -n NAMESPACE logs POD_NAME -
CiliumAgentUnreachableHealthEndpoints
CE
S4
Agent NAMESPACE/POD_NAME can't reach some of the node health endpoints.
For details, query Cilium health status API:
d8 k -n NAMESPACE exec POD_NAME -- cilium-health statusYou can also refer to the agent logs:
d8 k -n NAMESPACE logs POD_NAME -
CniCiliumNonStandardVXLANPortFound
CE
S4
Cilium configuration uses a non-standard VXLAN port.
The Cilium configuration specifies a non-standard VXLAN port
XXX. The recommended port number isXXX.To resolve this issue, update the
tunnel-portparameter in thecilium-configmapConfigMap located in thed8-cni-ciliumnamespace to match the recommended port.If you configured the non-standard port on purpose, ignore this alert.
-
CniCiliumOrphanEgressGatewayPolicyFound
SE-PLUS
S4
Orphaned EgressGatewayPolicy with an irrelevant EgressGateway name has been found.
The cluster contains an orphaned EgressGatewayPolicy named
NAMEwith an irrelevant EgressGateway name.To resolve this issue, verify the EgressGateway name specified in the EgressGatewayPolicy resource
EGRESSGATEWAYand update it as needed. -
CNICiliumPolicyWithRequiresFieldsFound
CE
S4
The XXX XXXNAMESPACE/XXXNAME uses the fromRequires or toRequires fields.
The XXX
NAMEXXX in theNAMESPACEnamespaceXXX uses thefromRequiresortoRequiresfields.Cilium 1.19 and later doesn’t support these fields. The Cilium agent of these versions can’t read such policies and fails on all nodes. Deckhouse won’t deploy a release with such a Cilium version until all these policies are rewritten.
To resolve this issue, rewrite each
fromRequiresconstraint as aningressDenyrule with an inverted selector. Don’t move the selector into the deny rule as is: this inverts the policy. A deny rule wins over allow rules of any policy, so it keeps the original scope:fromRequiresapplied to all policies selecting the endpoint.For example,
fromRequireswithmatchLabels: {env: prod}becomes:ingressDeny: - fromEndpoints: - matchExpressions: - {key: env, operator: NotIn, values: [prod]} XXX - matchExpressions: - {key: k8s:io.kubernetes.pod.namespace, operator: Exists} - {key: k8s:io.kubernetes.pod.namespace, operator: NotIn, values: [NAMESPACE]} XXX- Add a separate
NotInselector for each label of the constraint. XXX - Keep the second selector: in a CiliumNetworkPolicy,
fromRequiresalso implied the policy namespace, so sources from other namespaces were rejected. TheExistscondition is required, otherwise the rule also blocks the host, the world, and other sources without a namespace. XXX - Rewrite
toRequiresthe same way, as anegressDenyrule withtoEndpoints. - Add the deny rule first, check the traffic, and only then remove
fromRequiresandtoRequires.
To list all affected policies, use the
d8_cni_cilium_policy_with_requires_fields == 1expression in Prometheus. - Add a separate
-
D8NodeHasUnmetKernelRequirements
CE
S4
Nodes have unmet kernel requirements.
Deckhouse has detected that some nodes don’t meet the required kernel constraints. As a result, certain modules can’t run on these nodes.
Kernel requirements for each module:
- Cilium module: Kernel version must be >= 5.8.
To list all affected nodes, use the
d8_node_kernel_does_not_satisfy_requirements == 1expression in Prometheus.
Модуль control-plane-manager
-
D8ControlPlaneComponentsResourcesInsufficientCapacity
CE
S5
Automatic control-plane resource tuning cannot increase XXX requests due to lack of available capacity.
Automatic control-plane resource tuning attempted to increase
XXXrequests for one or more control-plane components (kube-apiserver, etcd, kube-controller-manager, kube-scheduler), but the calculated requests exceed the available capacity of at least one master node after accounting for the kubelet reservation and resource requests of other (non-control-plane) pods already scheduled on the node.XXX Additional memory required:
XXXB. XXX Additional CPU required:VALUEmCPU. XXXTo resolve this, free up resources on master nodes by moving or reducing other workloads or increase the CPU or RAM available on the nodes.
To disable automatic tuning for this resource and manage requests manually, set
spec.settings.resourcesRequests.XXXin the ModuleConfig ofcontrol-plane-manager. -
D8ControlPlaneDefaultVersionDrift
CE
S5
Control plane Kubernetes version rollback is blocked (Default soft-guard freeze).
The cluster tracks the Deckhouse default Kubernetes version (
kubernetesVersion: Defaultin ModuleConfigcontrol-plane-manager, or unset ModuleConfig with no ClusterConfiguration pin). That default is now more than 1 minor below the highest version this cluster has ever run (maxUsed).Rollback blocked: Deckhouse freezes the published target (holds it at the current control-plane version, or at the last desired version when the current one is not published yet) and does not roll Default down toward the lower default. Control plane and kubelet stay on the frozen target until the Deckhouse default catches up within the
maxUsed−1window.Check the
frozenlabel on the metric:frozen="true"means the digit is held as described above.frozen="false"means the window is violated but nothing was left to hold the digit at (for example thed8-cluster-kubernetesConfigMap was deleted), so the published target has moved down to the Deckhouse default — pin the intended version explicitly.To resolve this alert:
-
Do nothing and wait, if you are happy staying on the version the cluster runs now. This is a valid resolution only while
frozen="true": the cluster is not degraded, the version is held, and the alert clears by itself once the Deckhouse default rises back into themaxUsed−1window. How long that takes depends on why the default dropped — after a Deckhouse rollback, until you upgrade Deckhouse again; when the release default is simply older than the version this cluster runs, until a Deckhouse release ships a high enough default, which may be several releases away. -
To keep the current (higher) version and stop the alert now, pin it explicitly:
d8 k patch mc control-plane-manager --type merge -p '{"spec":{"settings":{"kubernetesVersion":"current version"}}}' -
To downgrade deliberately, pin one minor at a time (more than 1 minor below
maxUsedis rejected):d8 k patch mc control-plane-manager --type merge -p '{"spec":{"settings":{"kubernetesVersion":"current version - 1 minor"}}}'
-
-
D8ControlPlaneManagerObsoleteMonitoringKubernetesControlPlaneModuleConfig
CE
S9
Obsolete monitoring-kubernetes-control-plane ModuleConfig should be removed.
The
monitoring-kubernetes-control-planemodule was merged into thecontrol-plane-managermodule, but its ModuleConfig still exists in the cluster and is no longer used.Remove it manually:
d8 k delete moduleconfig monitoring-kubernetes-control-planeIf the ModuleConfig is deployed from an external source (e.g. a Git repository), make sure it is removed from there so it is not created again.
-
D8ControlPlaneManagerPodNotRunning
CE
S6
Controller pod isn't running on node NODE_NAME.
The
d8-control-plane-managerpod is either failing or hasn’t been scheduled on nodeNODE_NAME.To resolve this issue, check the status of the
kube-system/d8-control-plane-managerDaemonSet and its pods by running the following command:d8 k -n kube-system get daemonset,pod --selector=app=d8-control-plane-manager -
D8ControlPlaneNodeMaintenanceModeEnabled
CE
S4
Maintenance mode is enabled for control-plane node NODE_NAME.
Control-plane node
NODE_NAMEhas maintenance mode enabled with labelcontrol-plane-manager.deckhouse.io/maintenance. While this label is present, the control plane is not managed bycontrol-plane-manager.If maintenance is complete, remove the label:
d8 k label cpn NODE_NAME control-plane-manager.deckhouse.io/maintenance- -
D8ControlPlaneOperationRunningTooLong
CE
S4
Control-plane operation XXX for COMPONENT_NAME on node NODE_NAME runs or retries longer than 10 minutes.
Control-plane operation
XXXfor componentCOMPONENT_NAMEon nodeNODE_NAMEhas been running or retrying for more than 10 minutes.Check the corresponding ControlPlaneOperation and logs of the
d8-control-plane-managerPod on that node:d8 k get cpo XXX -o yaml d8 k -n kube-system logs -l app=d8-control-plane-manager --field-selector spec.nodeName=NODE_NAME -
D8EtcdDatabaseHighFragmentationRatio
CE
S7
etcd database size in use is less than 50% of the allocated storage.
The etcd database size in use on instance
INSTANCE_NAMEis less than 50% of the allocated disk space, indicating potential fragmentation. Additionally, the total storage size exceeds 75% of the configured quota.To resolve this issue, defragment the etcd database by running the following command:
d8 k -n kube-system exec -ti etcd-NODE_NAME -- /usr/bin/etcdctl \ --cacert /etc/kubernetes/pki/etcd/ca.crt \ --cert /etc/kubernetes/pki/etcd/ca.crt \ --key /etc/kubernetes/pki/etcd/ca.key \ --endpoints https://127.0.0.1:2379/ defrag --command-timeout=30s -
D8EtcdExcessiveDatabaseGrowth
CE
S4
etcd cluster database is growing rapidly.
Based on the growth rate observed over the last six hours, Deckhouse predicts that the etcd database will run out of disk space within one day on instance
INSTANCE_NAME.To prevent disruptions, investigate the cause and take necessary action.
-
D8EtcdHighRequestsLatency
CE
S5
Etcd request latency (p99) has exceeded 800 ms multiple times in the past hour.
The 99th percentile of etcd request duration on
INSTANCE_NAMEhas exceeded 800 ms more than twice in the last hour.High etcd latency can cause API server timeouts, slow admission webhooks, and general cluster instability.
Investigate the following:
- Node disk I/O: Etcd is extremely sensitive to disk performance. Check disk utilization and I/O wait on the control plane node.
- Network-attached storage: If the etcd data directory resides on NFS, Ceph, or another network storage, check connectivity and latency to the storage backend. Etcd requires a consistently low-latency local disk (SSD recommended).
- Control plane summary: Review the Kubernetes Cluster → Control Plane Status Grafana dashboard for an overall picture of API server and etcd health, request rates, and error rates.
- Node base performance: Check node CPU and RAM utilization and load average. If the node is CPU-bound (load average significantly exceeds the number of CPU cores), consider scaling up the control plane node.
-
D8InvalidEtcdDefragCronSchedule
CE
S6
Invalid etcd defragmentation cron schedule in ModuleConfig.
The
controlPlaneManager.etcd.defrag.cronSchedulevalueXXXis not a valid cron expression.Deckhouse has fallen back to the default schedule (
0 1 * * *) to keep defragmentation running.To fix this, set a valid 5-field cron expression:
d8 k patch moduleconfig control-plane-manager --type merge \ -p '{"spec":{"settings":{"etcd":{"defrag":{"cronSchedule":"0 1 * * *"}}}}}'Valid examples:
0 1 * * *— daily at 01:00 UTC0 */6 * * *— every 6 hours30 2 * * 0— weekly on Sunday at 02:30 UTC
-
D8KubeEtcdDatabaseSizeCloseToTheLimit
CE
S3
etcd database size is approaching the limit.
The etcd database size on
NODE_NAMEis nearing its size limit. This may be caused by a high number of events, such as pod evictions or the recent creation of numerous resources in the cluster.Possible solutions:
-
Defragment the etcd database by running the following command:
d8 k -n kube-system exec -ti etcd-NODE_NAME -- /usr/bin/etcdctl \ --cacert /etc/kubernetes/pki/etcd/ca.crt \ --cert /etc/kubernetes/pki/etcd/ca.crt \ --key /etc/kubernetes/pki/etcd/ca.key \ --endpoints https://127.0.0.1:2379/ defrag --command-timeout=30s -
Increase node memory. Starting from 24 GB,
quota-backend-byteswill increase by 1 GB for every extra 8 GB of memory.Example:
Node memory quota-backend-bytes 16 GB 2147483648 (2 GB) 24 GB 3221225472 (3 GB) 32 GB 4294967296 (4 GB) 40 GB 5368709120 (5 GB) 48 GB 6442450944 (6 GB) 56 GB 7516192768 (7 GB) 64 GB 8589934592 (8 GB) 72 GB 8589934592 (8 GB) … …
-
-
D8KubernetesStaleTokensDetected
CE
S8
Stale service account tokens detected for XXX/XXX.
Service account
XXX/XXXis using a stale token. This issue may occur if an application reads the token only at startup and does not reload it periodically. As a result, an outdated token might be used, leading to security breach and authentication failures.Recommended actions:
- Ensure your application is configured to periodically reload the token from the file system.
- Verify that you are using an up-to-date client library that supports automatic token rotation.
Note that currently these tokens are not blocked because the
--service-account-extend-token-expirationflag is enabled by default (Default: true). With this flag enabled, admission-injected tokens are extended up to 1 year during token generation to facilitate a safe transition from legacy tokens to the bound service account token feature, ignoring the value ofservice-account-max-token-expiration.For further investigation: You can find the problematic pods using the following command:
d8 k get pods -A -o json | jq -r '.items[] | select(.spec.serviceAccountName=="XXX" and .metadata.namespace=="XXX") | .metadata.name' -
D8KubernetesVersionIsDeprecated
CE
S7
Kubernetes version VERSION_NUMBER is deprecated.
The current Kubernetes version
VERSION_NUMBERhas been deprecated, and support for it will be removed in upcoming releases.Please migrate to the next kubernetes version (at least 1.34)
Read documentation about how to update the Kubernetes version in the cluster.
-
D8NeedDecreaseEtcdQuotaBackendBytes
CE
S6
Deckhouse suggests reducing quota-backend-bytes.
When the control plane node memory is reduced, Deckhouse may suggest reducing
quota-backend-bytes. While Deckhouse is capable of automatically increasing this value, reducing it must be done manually.To modify
quota-backend-bytes, set thecontrolPlaneManager.etcd.maxDbSizeparameter. Before setting a new value, check the current database usage on every control plane node by running:for pod in $(d8 k get pod -n kube-system -l component=etcd,tier=control-plane -o name); do d8 k -n kube-system exec -ti "$pod" -- /usr/bin/etcdctl \ --cacert /etc/kubernetes/pki/etcd/ca.crt \ --cert /etc/kubernetes/pki/etcd/ca.crt \ --key /etc/kubernetes/pki/etcd/ca.key \ endpoint status -w json | jq --arg a "$pod" -r \ '.[0].Status.dbSize / 1024 / 1024 | tostring | $a + ": " + . + " MB"'; doneThings to note:
- The maximum value for
controlPlaneManager.etcd.maxDbSizeis 8 GB. - If control plane nodes have less than 24 GB, set
controlPlaneManager.etcd.maxDbSizeto 2 GB. -
Starting from 24 GB,
quota-backend-byteswill increase by 1 GB for every extra 8 GB of memory.Example:
Node memory quota-backend-bytes 16 GB 2147483648 (2 GB) 24 GB 3221225472 (3 GB) 32 GB 4294967296 (4 GB) 40 GB 5368709120 (5 GB) 48 GB 6442450944 (6 GB) 56 GB 7516192768 (7 GB) 64 GB 8589934592 (8 GB) 72 GB 8589934592 (8 GB) … …
- The maximum value for
-
D8ObsoleteClusterDomainInClusterConfiguration
CE
S6
The obsolete clusterDomain field is still present in ClusterConfiguration.
ClusterConfigurationstill carries the obsoleteclusterDomainfield. The place to manage the cluster domain is ModuleConfigcontrol-plane-manager.This fires simply because the field is present, even if ModuleConfig
control-plane-manageralready overrides it - the goal is to remove the deprecated field, not just override it.To resolve this alert:
-
If ModuleConfig
control-plane-managerdoes not exist, create it:d8 s module enable control-plane-manager -
Migrate the value straight from the Secret into ModuleConfig:
DOMAIN=$(d8 k -n kube-system get secret d8-cluster-configuration \ -o jsonpath='{.data.cluster-configuration\.yaml}' | base64 -d \ | sed -n 's/^clusterDomain:[[:space:]]*//p' | tr -d "\"'") d8 k patch moduleconfig control-plane-manager --type merge \ -p "{\"spec\":{\"version\":3,\"settings\":{\"network\":{\"clusterDomain\":\"$DOMAIN\"}}}}"The value must match the one the cluster currently runs with; admission rejects a mismatch.
-
Remove the field from ClusterConfiguration:
d8 system edit cluster-configurationDelete
clusterDomain, then save.
Once the field is removed from
ClusterConfiguration, this alert is resolved. -
-
D8ObsoleteEncryptionAlgorithmInClusterConfiguration
CE
S6
Obsolete encryptionAlgorithm in ClusterConfiguration needs to be migrated to control-plane-manager ModuleConfig.
The
encryptionAlgorithmfield is set to a non-default value in ClusterConfiguration but has not been migrated to ModuleConfigcontrol-plane-manageryet.Until the migration is complete, the value from ClusterConfiguration is used to avoid unintended certificate rotation.
To resolve this alert, migrate the setting:
-
If ModuleConfig
control-plane-managerdoes not exist, create it first:d8 s module enable control-plane-manager -
Migrate the value from ClusterConfiguration to ModuleConfig in one command:
d8 k patch moduleconfig control-plane-manager --type merge -p "$(cat <<EOF {"spec": {"version": 3, "settings": {"encryptionAlgorithm": "$(d8 k -n kube-system get secret d8-cluster-configuration -o jsonpath='{.data.cluster-configuration\.yaml}' | base64 -d | grep encryptionAlgorithm | awk '{print $2}')"}}} EOF )"
Once ModuleConfig is updated, this alert will be resolved automatically.
-
Remove
encryptionAlgorithmfrom ClusterConfiguration:d8 system edit cluster-configurationDelete the
encryptionAlgorithmfield and save.
-
-
D8ObsoleteGlobalControlPlaneResourcesRequests
CE
S6
Obsolete global control-plane resource requests need to be migrated.
Control-plane resource requests are being migrated from global settings to
moduleconfig control-plane-manager.The obsolete settings are still used as a fallback, but they should be moved to the
control-plane-managermodule settings. The migration does not change the meaning of the values:cpuandmemoryremain the total resource requests for control-plane components on each master node.To complete the migration, follow the steps below:
-
Review the current obsolete settings in
moduleconfig global:d8 k get mc global -o jsonpath='{.spec.settings.modules.resourcesRequests.controlPlane}'; echoExample of obsolete settings:
spec: settings: modules: resourcesRequests: controlPlane: cpu: 1000m memory: 500Mi -
Make sure the
moduleconfig control-plane-managerresource exists and uses settings version3.If the resource does not exist, create it:
d8 s module enable control-plane-managerSet the settings version:
d8 k patch mc control-plane-manager --type merge \ -p '{"spec":{"version":3}}' -
Copy the obsolete values from
moduleconfig globaltomoduleconfig control-plane-manager.The following command preserves the original JSON value types, including numeric CPU values:
d8 k patch mc control-plane-manager --type merge -p "$( d8 k get mc global -o json | jq -c \ '{"spec":{"version":3,"settings":{"resourcesRequests": .spec.settings.modules.resourcesRequests.controlPlane}}}' )"After migration, the
moduleconfig control-plane-managerresource should contain:spec: version: 3 settings: resourcesRequests: cpu: 1000m memory: 500Mi -
Check that the values were applied:
d8 k get mc control-plane-manager -o jsonpath='{.spec.settings.resourcesRequests}'; echo -
Remove the obsolete settings from
moduleconfig global:d8 k patch mc global --type merge \ -p '{"spec":{"settings":{"modules":{"resourcesRequests":null}}}}'
-
-
D8ObsoleteKubernetesVersionFieldInClusterConfiguration
CE
S6
The obsolete kubernetesVersion field is still present in ClusterConfiguration.
ClusterConfigurationstill carries the obsoletekubernetesVersionfield. The place to manage the cluster Kubernetes version issettings.kubernetesVersionin ModuleConfigcontrol-plane-manager.To resolve this alert:
-
If ModuleConfig
control-plane-managerdoes not exist, create it:d8 s module enable control-plane-manager -
Read what the obsolete field currently holds:
d8 k -n kube-system get secret d8-cluster-configuration -o jsonpath='{.data.cluster-configuration\.yaml}' | base64 -d | grep '^kubernetesVersion:' -
If ModuleConfig has no
kubernetesVersionyet, set that same value there, so the cluster keeps the version it runs today (replace1.34with what you saw; if you sawAutomatic, useDefault):d8 k patch moduleconfig control-plane-manager --type merge -p '{"spec":{"version":3,"settings":{"kubernetesVersion":"1.34"}}}'Set
Defaultinstead if you want Deckhouse to choose the version. Note that this starts an upgrade whenever the release default is higher than the pinned version:d8 k patch moduleconfig control-plane-manager --type merge -p '{"spec":{"version":3,"settings":{"kubernetesVersion":"Default"}}}' -
Remove
kubernetesVersionfrom ClusterConfiguration:d8 system edit cluster-configurationDelete the
kubernetesVersionfield and save.
Once the
kubernetesVersionfield is removed fromClusterConfiguration, this alert is resolved. -
-
D8ObsoleteNetworkFieldsInClusterConfiguration
CE
S6
Obsolete network fields are still present in ClusterConfiguration.
ClusterConfigurationstill carries one or more of the obsoletepodSubnetCIDR,serviceSubnetCIDR,podSubnetNodeCIDRPrefixfields. The place to manage the cluster’s network is thenetworksection of ModuleConfigcontrol-plane-manager.This fires simply because a field is present, even if ModuleConfig
control-plane-manageralready overrides it - the goal is to remove the deprecated field, not just override it.To resolve this alert:
-
If ModuleConfig
control-plane-managerdoes not exist, create it:d8 s module enable control-plane-manager -
Migrate the values straight from the Secret into ModuleConfig using the following command:
d8 k patch moduleconfig control-plane-manager --type merge -p "$( d8 k -n kube-system get secret d8-cluster-configuration -o jsonpath='{.data.cluster-configuration\.yaml}' | base64 -d \ | yq -o=json '{"podSubnetCIDR": .podSubnetCIDR, "serviceSubnetCIDR": .serviceSubnetCIDR, "podSubnetNodeCIDRPrefix": .podSubnetNodeCIDRPrefix}' \ | jq -c '{spec: {version: 3, settings: {network: with_entries(select(.value != null))}}}' )"Once a field is set in ModuleConfig this way, it cannot be migrated again: the network group is immutable once set.
-
Remove all three fields from ClusterConfiguration:
d8 system edit cluster-configurationDelete
podSubnetCIDR,serviceSubnetCIDRandpodSubnetNodeCIDRPrefix, then save.
Once all three fields are removed from
ClusterConfiguration, this alert is resolved. -
-
D8ObsoletePublishAPIinUserAuthn
CE
S6
Obsolete Publish API settings in user-authn need to be migrated.
Publish API ingress settings are being migrated from
mc user-authntomc control-plane-manager.To complete the migration, follow the steps below:
-
Review current settings for
publishAPIin themoduleconfig user-authnresource.Note that legacy
user-authnspec.version: 1usespublishAPI.enableinstead ofpublishAPI.enabled. No manual rewrite is required: the command in step 4 uses the normalized payload from the temporary ConfigMap. -
If the
moduleconfig control-plane-managerresource exists, update its spec tospec.version: 3. Ifsettings.apiserver.loadBalanceris set, migrate it tosettings.apiserver.publishAPI.loadBalancer. If the resource does not exist, proceed to step 3. -
If
moduleconfig control-plane-managerdoes not exist, create it viad8:d8 s module enable control-plane-managerAnd set the settings version:
d8 k patch moduleconfig control-plane-manager --type merge \ -p '{"spec":{"version":3}}' -
Apply the migrated settings into
moduleconfig control-plane-managerfrom temporary configMap by executing the following script:d8 k patch moduleconfig control-plane-manager --type merge -p "$(cat <<EOF {"spec": {"settings": {"apiserver": {"publishAPI": {"ingress": \ $(d8 k -n kube-system get cm d8-publishapi-config-migration -ojsonpath='{.data.config}') }}}}} EOF )" -
Remove obsolete
spec.settings.publishAPIsection frommoduleconfig user-authn.
-
-
D8ProblematicFeatureGateInUse
CE
S9
Feature gate XXX is STATUS_REFERENCE in current Kubernetes version XXX and should be removed from the configuration. Is not using in the cluster control-plane.
The feature gate
XXXis currently enabled in the control-plane-manager ModuleConfig, but it is STATUS_REFERENCE in the current Kubernetes versionXXX.XXX This feature gate does not exist in any component (apiserver, kube-controller-manager, kube-scheduler, kubelet) and is not being applied to the cluster. XXX
Recommended actions:
- Remove
XXXfrom thespec.settings.enabledFeatureGateslist in the control-plane-manager ModuleConfig:
d8 k edit mc control-plane-managerFor more information about Kubernetes feature gates, refer to the official documentation.
- Remove
-
D8UsingFeatureGateWillBeDeprecated
CE
S9
Feature gate XXX will be deprecated in Kubernetes version XXX.
The feature gate
XXXis currently enabled in the control-plane-manager ModuleConfig, but it will be deprecated in Kubernetes versionXXX.Current Kubernetes version:
XXXRecommended actions:
- Review the usage of this feature gate in your cluster.
- Plan migration away from this feature gate before upgrading to version
XXX. - Remove
XXXfrom thespec.settings.enabledFeatureGateslist in the control-plane-manager ModuleConfig:
d8 k edit mc control-plane-managerFor more information about Kubernetes feature gates, refer to the official documentation.
-
HelmReleasesHasResourcesWithDeprecatedVersions
CE
S5
At least one Helm release contains resources with deprecated apiVersion, which will be removed in Kubernetes version VERSION_NUMBER.
To list all affected resources, run the following Prometheus query:
max by (helm_release_namespace, helm_release_name, helm_version, resource_namespace, resource_name, api_version, kind, k8s_version) (resource_versions_compatibility) == 1For more details on upgrading deprecated resources, refer to the Kubernetes deprecation guide available at
https://kubernetes.io/docs/reference/using-api/deprecation-guide/#vXXX.Note that the check runs once per hour, so this alert should resolve within an hour after migrating deprecated resources.
-
HelmReleasesHasResourcesWithUnsupportedVersions
CE
S4
At least one Helm release contains resources with unsupported apiVersion for Kubernetes version VERSION_NUMBER.
To list all affected resources, run the following Prometheus query:
max by (helm_release_namespace, helm_release_name, helm_version, resource_namespace, resource_name, api_version, kind, k8s_version) (resource_versions_compatibility) == 2For more details on migrating deprecated resources, refer to the Kubernetes deprecation guide available at
https://kubernetes.io/docs/reference/using-api/deprecation-guide/#vXXX.Note that the check runs once per hour, so this alert should resolve within an hour after migrating deprecated resources.
-
K8SApiserverDown
CE
S3
API servers can't be reached.
No API servers are reachable, or they have all disappeared from service discovery.
-
K8sCertificateExpiration
CE
S5
Kubernetes has API clients with soon-to-expire certificates.
Some clients are connecting to COMPONENT_NAME with certificates that will expire in less than a day on node
COMPONENT_NAME.To check control plane certificates, use kubeadm:
-
Install kubeadm using the following command:
apt install kubeadm=1.24.* -
Check certificates:
kubeadm alpha certs check-expiration
To check kubelet certificates, do the following on each node:
-
Check kubelet configuration:
ps aux \ | grep "/usr/bin/kubelet" \ | grep -o -e "--kubeconfig=\S*" \ | cut -f2 -d"=" \ | xargs cat - Locate the
client-certificateorclient-certificate-datafield. - Check certificate expiration using OpenSSL.
Note that there are no tools to find other stale kubeconfig files. Consider enabling the
control-plane-managermodule for advanced debugging. -
-
K8sCertificateExpiration
CE
S6
Kubernetes has API clients with soon-to-expire certificates.
Some clients are connecting to COMPONENT_NAME with certificates that will expire in less than 7 days on node
NODE_NAME.To check control plane certificates, use kubeadm:
-
Install kubeadm using the following command:
apt install kubeadm=1.24.* -
Check certificates:
kubeadm alpha certs check-expiration
To check kubelet certificates, do the following on each node:
-
Check kubelet configuration:
ps aux \ | grep "/usr/bin/kubelet" \ | grep -o -e "--kubeconfig=\S*" \ | cut -f2 -d"=" \ | xargs cat - Locate the
client-certificateorclient-certificate-datafield. - Check certificate expiration using OpenSSL.
Note that there are no tools to find other stale kubeconfig files. Consider enabling the
control-plane-managermodule for advanced debugging. -
-
K8SControllerManagerTargetDown
CE
S3
Controller manager is down.
There is no running kube-controller-manager. As a result, deployments and replication controllers are not progressing.
-
K8SSchedulerTargetDown
CE
S3
Scheduler is down.
The Kubernetes scheduler is not running. As a result, new pods are not being assigned to nodes.
-
KubeEtcdHighFsyncDurations
CE
S7
Syncing (fsync) WAL files to disk is slow.
In the last 15 minutes, the 99th percentile of the fsync duration for WAL files exceeded 0.5 seconds: VALUE.
Possible causes:
- High disk latency where etcd data is stored.
- High CPU usage on the node.
-
KubeEtcdHighNumberOfLeaderChanges
CE
S5
The etcd cluster is re-electing the leader too frequently.
There have been VALUE leader re-elections for the etcd cluster member running on node
NODE_NAMEin the last 10 minutes.Possible causes:
- High disk latency where etcd data is stored.
- High CPU usage on the node.
- Degradation of network connectivity between cluster members in the multi-master mode.
-
KubeEtcdInsufficientMembers
CE
S4
Insufficient members in the etcd cluster.
The etcd cluster has too few members, increasing the risk of failure if another member becomes unavailable. To resolve this issue, check the status of etcd Pods:
bash d8 k -n kube-system get pod -l component=etcd -
KubeEtcdNoLeader
CE
S4
The etcd cluster member running on node NODE_NAME has lost the leader.
To resolve this issue, check the status of the etcd Pods:
bash d8 k -n kube-system get pod -l component=etcd | grep NODE_NAME -
KubeEtcdTargetAbsent
CE
S5
There is no etcd target in Prometheus.
Steps to troubleshoot:
-
Check the status of the etcd Pods:
d8 k -n kube-system get pod -l component=etcd -
Review Prometheus logs:
d8 k -n d8-monitoring logs -l app.kubernetes.io/name=prometheus -c prometheus
-
-
KubeEtcdTargetDown
CE
S5
Prometheus is unable to scrape etcd metrics.
Steps to troubleshoot:
-
Check the status of the etcd Pods:
d8 k -n kube-system get pod -l component=etcd -
Review Prometheus logs:
d8 k -n d8-monitoring logs -l app.kubernetes.io/name=prometheus -c prometheus
-
-
KubernetesServiceExternalIPsDeprecated
CE
S6
The cluster has Services that use the deprecated spec.externalIPs field.
There are
VALUEService(s) in user namespaces that use thespec.externalIPsfield. Services in thed8-*andkube-systemnamespaces are not checked.The
spec.externalIPsfield is officially deprecated in Kubernetes because of the CVE-2020-8554 security vulnerability. Starting with Kubernetes 1.36, the API server returns a warning for every request that sets this field. Support for the field will be removed in future Kubernetes versions.Plan the migration of the affected Services to a supported way of exposing them, for example:
- A Service of the
LoadBalancertype. In bare-metal clusters, use themetallbmodule to assign addresses. - A Service of the
NodePorttype. - An Ingress or Gateway API resource for HTTP(S) traffic.
For details, refer to the Kubernetes announcement.
To list the affected Services with their namespaces and external IP addresses, run:
d8 k get services -A -o json | jq -r '["NAMESPACE", "NAME", "TYPE", "EXTERNAL-IPS"], (.items[] | select(.spec.externalIPs) | select(.metadata.namespace | test("^(d8-.*|kube-system)$") | not) | [.metadata.namespace, .metadata.name, .spec.type, (.spec.externalIPs | join(","))]) | @tsv' | column -tAlternatively, run the following Prometheus query:
max by (namespace, service, external_ip) (kube_service_spec_external_ip{namespace!~"d8-.*|kube-system"}) - A Service of the
Модуль deckhouse
-
ApplicationIsInMaintenanceMode
CE
S6
Application NAME in namespace NAMESPACE is running in maintenance mode.
Application
NAMEin namespaceNAMESPACEis running in maintenance mode. In this mode, its state is not reconciled, which prevents configuration or hook changes from being applied automatically.To switch the application back to normal mode, edit the corresponding Application resource with the following command:
d8 k patch application NAME -n NAMESPACE --type=json -p='[{"op": "remove", "path": "/spec/maintenance"}]' -
D8CNIEnabledMoreThanOne
CE
S2
More than one CNI is enabled in the cluster.
Deckhouse has detected that multiple CNIs are enabled in the cluster. For the cluster to work correctly, exactly one CNI must be enabled.
To resolve this issue, follow these steps:
-
List the CNI modules and their enabled state:
d8 k get moduleconfig -o custom-columns='NAME:.metadata.name,ENABLED:.spec.enabled' | grep -E 'NAME|cni-' -
Decide which CNI the cluster must keep. Check which one actually serves the nodes before disabling anything:
d8 k -n d8-cni-cilium get pods 2>/dev/null; d8 k -n d8-cni-flannel get pods 2>/dev/null; d8 k -n d8-cni-simple-bridge get pods 2>/dev/null -
Disable every other CNI module, one at a time:
d8 k patch moduleconfig CNI_MODULE_NAME --type=merge -p '{"spec":{"enabled":false}}'
Changing the CNI of a running cluster disrupts pod networking. If you are unsure which CNI to keep, contact support before disabling anything.
-
-
D8CNIMisconfigured
CE
S5
The parameters specified in ModuleConfig of CNI_NAME do not match the ones that are actually being used in the cluster.
This happened because there were several sources for configuring CNI parameters in the cluster, and ModuleConfig did not have the highest priority previously.
To resolve this issue, the following steps should be taken:
-
Find the ConfigMap
d8-system/desired-cni-moduleconfigin the cluster, which contains the actual ModuleConfig settings.d8 k -n d8-system get configmap desired-cni-moduleconfig -o yaml -
Apply this prepared ModuleConfig to the cluster. This will not cause any actual reconfigurations in the cluster and is completely safe.
- Once the parameters in “ModuleConfig” match those used in the cluster:
- this alert will be resolved,
- and the priority of the sources for configuring CNI will change, and ModuleConfig will become the main source of truth.
- After that, you can add the desired parameters to the ModuleConfig CNI and they will be applied immediately.
-
-
D8DeckhouseConfigInvalid
CE
S5
Deckhouse rejected the cluster configuration: one of the ModuleConfig resources is invalid.
Deckhouse has detected errors in the cluster configuration. The usual causes are
spec.settingsthat do not match the module’s settings schema, and a failed conversion ofspec.settingsto the latest schema version.This alert does not name the module, because the underlying metric has no labels. Deckhouse puts the exact error into the
status.messagefield of the ModuleConfig that caused it, prefixed withError:.To resolve this issue, follow these steps:
-
Find the affected configuration. The
MESSAGEcolumn holds the error and theVERSIONcolumn holds the settings schema version currently in use:d8 k get moduleconfig -
Read the full error for the ModuleConfig that reports one (
globalis a valid value forMODULE_NAME):d8 k get moduleconfig MODULE_NAME -o jsonpath='{.status.message}{"\n"}' -
Fix
spec.settings, orspec.versionif the error mentions a settings version or a conversion:d8 k edit moduleconfig MODULE_NAME -
If no ModuleConfig reports an error, check the Deckhouse logs:
d8 k -n d8-system logs -f -l app=deckhouse
-
-
D8DeckhouseCouldNotDeleteModule
CE
S4
Deckhouse is unable to delete the MODULE_NAME module.
To investigate the issue, check the logs by running the following command:
d8 k -n d8-system logs -f -l app=deckhouse -
D8DeckhouseCouldNotDiscoverModules
CE
S4
Deckhouse is unable to discover modules.
To investigate the issue, check the logs by running the following command:
d8 k -n d8-system logs -f -l app=deckhouse -
D8DeckhouseCouldNotRunGlobalHook
CE
S5
Deckhouse is unable to run the HOOK_NAME global hook.
To investigate the issue, check the logs by running the following command:
d8 k -n d8-system logs -f -l app=deckhouse -
D8DeckhouseCouldNotRunModule
CE
S4
Deckhouse is unable to start the MODULE_NAME module.
To investigate the issue, check the logs by running the following command:
d8 k -n d8-system logs -f -l app=deckhouse -
D8DeckhouseCouldNotRunModuleHook
CE
S7
Deckhouse is unable to run the MODULE_NAME/HOOK_NAME module hook.
To investigate the issue, check the logs by running the following command:
d8 k -n d8-system logs -f -l app=deckhouse -
D8DeckhouseCustomTargetDown
CE
S4
Prometheus is unable to scrape custom metrics generated by Deckhouse hooks.
Prometheus cannot reach the endpoint that serves metrics exported by Deckhouse hooks. Deckhouse core metrics may still be scraped, so this usually points at the hook metrics endpoint rather than at Deckhouse being down.
To investigate the issue, follow these steps:
-
Check that the pod is up:
d8 k -n d8-system get pods -l app=deckhouse -o wide -
Look for hook failures in the logs, since a hook that never completes exports no metrics:
d8 k -n d8-system logs -l app=deckhouse --tail=100 | grep -i error -
Check that the scrape configuration for hook metrics is still present:
d8 k -n d8-monitoring get podmonitor deckhouse -o jsonpath='{range .spec.podMetricsEndpoints[*]}{.path}{"\n"}{end}'
-
-
D8DeckhouseDeprecatedConfigmapManagedByArgoCD
CE
S4
Deprecated Deckhouse ConfigMap managed by Argo CD.
The Deckhouse ConfigMap is no longer used.
To resolve this issue, remove the
d8-system/deckhouseConfigMap from Argo CD. -
D8DeckhouseGlobalHookFailsTooOften
CE
S9
The HOOK_NAME Deckhouse global hook is crashing too frequently.
The
HOOK_NAMEhook has failed multiple times in the last__SCRAPE_INTERVAL_X_4__.To investigate the issue, check the logs by running the following command:
d8 k -n d8-system logs -f -l app=deckhouse -
D8DeckhouseHasNoAccessToRegistry
CE
S7
Deckhouse is unable to connect to the registry.
Deckhouse can’t connect to the registry to check for new releases. With a release channel set, it checks the channel every 3 minutes; without one, it checks the digest of its own image every 15 seconds. Without access to the registry, automatic updates are unavailable.
Module images come from the same registry, so pods that need a new image fail to start as well, sometimes with errors that do not mention the registry. The usual causes are expired or changed credentials, a registry certificate that has expired or was replaced with one signed by an unknown authority, and a network or proxy change.
To investigate the issue, follow these steps:
-
Read the registry error in the logs.
UNAUTHORIZEDpoints at the credentials,x509at the certificate, and a timeout or a refused connection at the network:d8 k -n d8-system logs -l app=deckhouse --tail=500 | grep -iE 'check deckhouse release|registry' -
Check which registry address the cluster is configured to use:
d8 k -n d8-system get secret deckhouse-registry -o jsonpath='{.data.address}' | base64 -d -
If the address is correct, the credentials are the next suspect. Check when the secret was last updated:
d8 k -n d8-system get secret deckhouse-registry -
If the error mentions
x509, check who issued the registry certificate and when it expires. Run the command on a master node and substitute the host from the registry address, and its port if it is not 443:openssl s_client -connect REGISTRY_HOST:443 -servername REGISTRY_HOST </dev/null 2>/dev/null | openssl x509 -noout -issuer -enddate -
Check that the node running Deckhouse can reach the registry at all, for example through a proxy or a firewall rule that changed.
-
-
D8DeckhouseIsHung
CE
S4
Deckhouse is down.
Deckhouse is probably down, since the
deckhouse_live_ticksmetric in Prometheus has stopped increasing. This metric is expected to increment every 10 seconds.To investigate the issue, follow these steps:
-
Check the pod state and its restart count:
d8 k -n d8-system get pods -l app=deckhouse -o wide -
Read the logs. A deadlock or a hook that never returns stops the ticks while the pod still looks healthy:
d8 k -n d8-system logs -l app=deckhouse --tail=200 -
Check whether a queue stopped moving at the same time:
d8 system queue list -
If the pod is alive but stuck, restart it:
d8 k -n d8-system rollout restart deploy/deckhouse
-
-
D8DeckhouseIsNotOnReleaseChannel
CE
S9
Deckhouse isn't subscribed to any regular release channels.
Deckhouse in this cluster isn’t subscribed to any of the regular release channels:
Alpha,Beta,EarlyAccess,Stable, orRockSolid.To resolve this issue, follow these steps:
-
Check the current release channel used in the cluster:
d8 k -n d8-system get deploy deckhouse -o json | jq '.spec.template.spec.containers[0].image' -r -
Subscribe to one of the regular release channels by adjusting the
deckhousemodule configuration.
-
-
D8DeckhouseModuleHookFailsTooOften
CE
S9
The MODULE_NAME/HOOK_NAME Deckhouse hook is crashing too frequently.
The
HOOK_NAMEhook of theMODULE_NAMEmodule has failed multiple times in the last__SCRAPE_INTERVAL_X_4__.To investigate the issue, check the logs by running the following command:
d8 k -n d8-system logs -f -l app=deckhouse -
D8DeckhouseModuleUpdatePolicyNotFound
CE
S5
Module update policy not found for MODULE_RELEASE.
The module update policy for MODULE_RELEASE is missing.
To resolve this issue, remove the label from the module release using the following command:
d8 k label mr MODULE_RELEASE modules.deckhouse.io/update-policy-A new suitable policy will be detected automatically.
-
D8DeckhouseModuleValidationError
CE
S5
Module configuration failed for module MODULE_NAME.
Initial config for module MODULE_NAME is not valid.
You can get more details via
d8 k get mr -l module=MODULE_NAMEProvided error: XXX
-
D8DeckhouseObsoleteMonitoringDeckhouseModuleConfig
CE
S9
Obsolete monitoring-deckhouse ModuleConfig should be removed.
The
monitoring-deckhousemodule was merged into thedeckhousemodule, but its ModuleConfig still exists in the cluster and is no longer used.Remove it manually:
d8 k delete moduleconfig monitoring-deckhouseIf the ModuleConfig is deployed from an external source (e.g. a Git repository), make sure it is removed from there so it is not created again.
-
D8DeckhousePodIsNotReady
CE
S4
The Deckhouse Pod is NOT Ready.
The Deckhouse pod is running but has not become Ready. While this lasts, Deckhouse is not converging the cluster: module updates and configuration changes are not applied.
To investigate the issue, follow these steps:
-
Check the pod state and its restart count:
d8 k -n d8-system get pods -l app=deckhouse -o wide -
Read the events and probe failures at the bottom of the pod description:
d8 k -n d8-system describe pod -l app=deckhouse -
Check the logs. A readiness probe that never succeeds is most often a startup hook that fails or hangs:
d8 k -n d8-system logs -l app=deckhouse --tail=200 -
Check whether a queue is stuck, which keeps Deckhouse from reporting Ready:
d8 system queue list
-
-
D8DeckhousePodIsNotRunning
CE
S4
The Deckhouse Pod is NOT Running.
There is no running Deckhouse pod in the
d8-systemnamespace. Nothing is reconciling the cluster: no module updates, no configuration changes, and no Deckhouse releases are applied.To investigate the issue, follow these steps:
-
Check the pod state.
Pendingpoints at scheduling,ImagePullBackOffat the registry, andCrashLoopBackOffat Deckhouse failing to start:d8 k -n d8-system get pods -l app=deckhouse -o wide -
Read the events to find out why the pod is not running:
d8 k -n d8-system describe pod -l app=deckhouse -
If the pod is restarting, read the logs of the previous run:
d8 k -n d8-system logs -l app=deckhouse --previous --tail=200 -
Check that the Deployment itself is present and has the replicas it expects:
d8 k -n d8-system get deploy deckhouse
-
-
D8DeckhousePodIsRestartingTooOften
CE
S9
Excessive Deckhouse restarts detected.
Number of restarts in the last hour: VALUE.
Excessive Deckhouse restarts indicate a potential issue. Normally, Deckhouse should be up and running continuously.
To investigate the issue, check the logs by running the following command:
d8 k -n d8-system logs -f -l app=deckhouse -
D8DeckhouseQueueIsHung
CE
S6
Module queue MODULE_NAME (type XXX, hook HOOK_NAME) is hung.
The module queue head has remained unchanged for more than 10 minutes.
Affected queue:
- Module:
MODULE_NAME - Task type:
XXX - Hook:
HOOK_NAME
To investigate the issue, check the logs of the
deckhousecontroller pods:d8 k -n d8-system logs -f -l app=deckhouse - Module:
-
D8DeckhouseQueueIsHungCritical
CE
S4
Critical module queue MODULE_NAME (type XXX, hook HOOK_NAME) is hung.
The critical module queue head has remained unchanged for more than 10 minutes.
Affected queue:
- Module:
MODULE_NAME - Task type:
XXX - Hook:
HOOK_NAME
To investigate the issue, check the logs of the
deckhousecontroller pods:d8 k -n d8-system logs -f -l app=deckhouse - Module:
-
D8DeckhouseQueueIsHungGlobal
CE
S4
Global/Parallel task XXX (hook HOOK_NAME) is hung.
The global/parallel task head has remained unchanged for more than 10 minutes.
Affected task:
- Task type:
XXX - Hook:
HOOK_NAME
To investigate the issue, check the logs of the
deckhousecontroller pods:d8 k -n d8-system logs -f -l app=deckhouse - Task type:
-
D8DeckhouseSelfTargetAbsent
CE
S4
There is no Deckhouse target in Prometheus.
Prometheus has no
deckhousetarget at all. Unlike a target that is down, this means the target was never discovered, so the problem is usually with the Service, its endpoints, or the monitoring configuration rather than with Deckhouse itself.To investigate the issue, follow these steps:
-
Check that the Deckhouse pod exists and is running:
d8 k -n d8-system get pods -l app=deckhouse -o wide -
Check that the Service has endpoints. An empty
ENDPOINTScolumn means nothing matches the selector:d8 k -n d8-system get endpoints deckhouse -
Check that the scrape configuration for Deckhouse exists:
d8 k -n d8-system get servicemonitor,podmonitor -l app=deckhouse -
Check that the monitoring stack itself is healthy:
d8 k -n d8-monitoring get pods
-
-
D8DeckhouseSelfTargetDown
CE
S4
Prometheus is unable to scrape Deckhouse metrics.
Prometheus cannot reach the
deckhousemetrics endpoint. Deckhouse itself may still be working, but its own metrics are missing, so most other Deckhouse alerts are blind while this lasts.To investigate the issue, follow these steps:
-
Check that the pod is up and how long it has been running:
d8 k -n d8-system get pods -l app=deckhouse -o wide -
Look for scrape errors, such as a connection refused or a TLS failure:
d8 k -n d8-system logs -l app=deckhouse --tail=100 -
Check that the pod still exposes the
selfmetrics port:d8 k -n d8-system get pod -l app=deckhouse -o jsonpath='{range .items[*].spec.containers[*].ports[*]}{.name}{"="}{.containerPort}{"\n"}{end}'
-
-
D8DeckhouseWatchErrorOccurred
CE
S5
Possible API server connection error in the client-go informer.
Deckhouse has detected an error in the client-go informer, possibly due to connection issues with the API server.
Steps to investigate:
-
Check Deckhouse logs for more information by running:
d8 k -n d8-system logs deploy/deckhouse | grep error | grep -i watch -
This alert attempts to detect a correlation between the faulty snapshot invalidation and API server connection errors, specifically for the
handle-node-templatehook in thenode-managermodule.To compare the snapshot with the actual node objects for this hook, run the following command:
diff -u <(d8 k get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}'|sort) <(d8 k -n d8-system exec svc/deckhouse-leader -c deckhouse -- deckhouse-controller module snapshots node-manager -o json | jq '."040-node-manager/hooks/handle_node_templates.go"' | jq '.nodes.snapshot[] | .filterResult.Name' -r | sort)
-
-
D8HasModuleConfigAllowedToDisable
CE
S4
The ModuleConfig annotation for allowing module disabling is set.
The ModuleConfig is pending module disabling.
It is recommended that you keep your module configurations clean by removing unnecessary approval annotations.
If you ignore this alert and do not clear the annotation, the module may be accidentally removed from the cluster, potentially leading to irreversible consequences.
To resolve this issue and stop the alert, run the following command:
d8 k annotate moduleconfig MODULE_NAME modules.deckhouse.io/allow-disabling-With Module v2 enabled, remove the
packages.deckhouse.io/allow-disablingannotation instead:d8 k annotate moduleconfig MODULE_NAME packages.deckhouse.io/allow-disabling- -
D8ModuleOutdatedByMajorVersion
CE
S9
Module MODULE_NAME is running XXX major versions behind.
Module
MODULE_NAMEis running XXX major versions behind on major version releases. Major version updates may contain breaking changes and require immediate attention and careful planning.To check the module releases status, run the following command:
d8 k get mr -l module=MODULE_NAME ```XXXXXX This major release has from-to version constraints that must be met before applying the update. To check the update instructions (from-to versions), run the following command: ```bash d8 k get mr NAME -o jsonpath='{.spec.update.versions[*]}'This will show you the update paths including the from-to versions defined in the release.XXX
To approve the module major release update, run the following command:
bash d8 k annotate mr NAME modules.deckhouse.io/approved="true"XXX -
D8NodeHasDeprecatedOSVersion
CE
S4
Nodes with deprecated OS versions detected.
Deckhouse has detected nodes running deprecated OS versions.
Steps to troubleshoot:
-
Get a list of affected nodes by running the following Prometheus query:
kube_node_info{os_image=~"Ubuntu 18.04.*|Debian GNU/Linux 10.*|CentOS Linux 7.*"} -
Update the affected nodes to a supported OS version.
-
-
DeckhouseEditionNotFound
CE
S6
Incorrect Deckhouse Platform edition.
Specify a Deckhouse Platform edition in
MODULE_NAMEModuleConfig.d8 k patch moduleconfig MODULE_NAME --type merge --patch '{"spec": {"settings": {"license": {"edition": "DKP_EDITION"}}}}'Where
DKP_EDITIONis the edition you want to use:CE,BE,EE,SE, orSE-plus. -
DeckhouseHighMemoryUsage
CE
S3
Deckhouse memory usage is too high.
Deckhouse pod
POD_NAMEon nodeNODE_NAMEhas high memory usage.Please, if possible, get the dumps for debugging purposes (it will take around 30 seconds):
curl -s "http://$(d8 k -n d8-system get pod POD_NAME -o jsonpath='{.status.hostIP}'):4222/debug/pprof/heap" -o /tmp/heap.pprof curl -s "http://$(d8 k -n d8-system get pod POD_NAME -o jsonpath='{.status.hostIP}'):4222/debug/pprof/goroutine" -o /tmp/goroutine.pprof curl -s "http://$(d8 k -n d8-system get pod POD_NAME -o jsonpath='{.status.hostIP}'):4222/debug/pprof/profile?seconds=30" -o /tmp/cpu.pprofand send these files (/tmp/heap.pprof, /tmp/cpu.pprof and /tmp/goroutine.pprof) to the support team.
-
DeckhouseMigratedModuleNotDownloaded
CE
S6
Migrated module MODULE_NAME has not been downloaded yet.
Module
MODULE_NAMEspecified in DeckhouseRelease was moved to an external source and is available in a ModuleSource registry, but it has not been downloaded yet (no deployed ModuleRelease exists). DeckhouseRelease will be locked until the module is downloaded.This alert is usually temporary while the module source controller downloads the module from the registry. If the alert persists, this may indicate:
- The module’s update policy or ModuleSource is misconfigured, preventing the module from being downloaded.
- A network issue is preventing the module from being downloaded.
To investigate the issue, do the following:
-
Check the ModuleRelease objects for the module:
d8 k get mr -l module=MODULE_NAME -
Check the configured ModuleSources:
d8 k get modulesources -
Check the
deckhouselogs for more details:d8 k -n d8-system logs -f -l app=deckhouse
-
DeckhouseMigratedModuleNotFound
CE
S6
Migrated module MODULE_NAME was not found in any ModuleSource registry.
Module
MODULE_NAMEspecified in DeckhouseRelease was moved to an external source and was not found in any available ModuleSource registry. DeckhouseRelease will be locked until the module becomes available in one of the configured ModuleSource registries.This may indicate:
- A ModuleSource registry is misconfigured.
- The module has not been published to the registry yet.
- A network issue is preventing access to the registry.
To investigate the issue, do the following:
-
Check the configured ModuleSources:
d8 k get modulesources -
List the available module sources:
d8 k -n d8-system exec -it deployment/deckhouse -c deckhouse -- deckhouse-controller registry get sources -
List the modules available in a specific source:
d8 k -n d8-system exec -it deployment/deckhouse -c deckhouse -- deckhouse-controller registry get modules source_name -
Check the
deckhouselogs for more details:d8 k -n d8-system logs -f -l app=deckhouse
-
DeckhouseModuleUpdatingFailedBrokenSequence
CE
S4
Module update has failed. Updating sequence is broken.
The ‘MODULE_NAME’ module update has failed.
Current version: XXX. Desired version: VERSION_NUMBER.
Attempt to download interim releases failed. Deckhouse updates modules one minor version at a time, so every intermediate version must exist in the registry.
Possible reasons:
- Some of the necessary versions of the module image are not available in the registry.
- The registry is unreachable.
To resolve this issue, follow these steps:
-
Check which module releases exist and where the sequence stopped:
d8 k get modulereleases -l module=MODULE_NAME -
Read the reason recorded on the release that is not deployed:
d8 k get modulereleases -l module=MODULE_NAME -o custom-columns='NAME:.metadata.name,VERSION:.spec.version,PHASE:.status.phase,MESSAGE:.status.message' -
Find the module source that serves this repo. The
registrylabel above is a repo URL, not a source name:d8 k get modulesource -o custom-columns='NAME:.metadata.name,REPO:.spec.registry.repo' -
Ensure that every minor version of the ‘MODULE_NAME’ module image between XXX and VERSION_NUMBER is available in the registry ‘XXX’. If the cluster uses a mirror, the missing versions have to be pulled into it first.
-
DeckhouseModuleUpdatingFailedModuleIsNotValid
CE
S4
Module update has failed. Module is not valid.
The ‘MODULE_NAME’ module update has failed.
Desired version: VERSION_NUMBER.
Possible reasons:
- The module image is corrupted.
To resolve this issue, ensure that the VERSION_NUMBER image in the registry ‘XXX’ is valid.
Check which versions of the ‘MODULE_NAME’ module are available in the registry:
d8 cr ls XXX/MODULE_NAME/releaseFor a private registry, pass the credentials from the corresponding ModuleSource:
d8 cr ls -u USERNAME -p PASSWORD XXX/MODULE_NAME/releaseTo get the exact error, check Deckhouse logs:
d8 k -n d8-system logs deploy/deckhouse | grep "failed to download module" -
DeckhouseReleaseDisruptionApprovalRequired
CE
S4
Deckhouse release disruption approval required.
The new Deckhouse release includes a disruptive update that requires manual approval.
To check the details, run the following command:
d8 k describe DeckhouseRelease NAMETo approve the disruptive update, run the following command:
d8 k annotate DeckhouseRelease NAME release.deckhouse.io/disruption-approved=true -
DeckhouseReleaseIsBlocked
CE
S5
Deckhouse release requirements haven't been met.
The requirements for the Deckhouse release haven’t been met.
To check the details, run the following command:
d8 k describe DeckhouseRelease NAME -
DeckhouseReleaseIsWaitingManualApproval
CE
S3
A new Deckhouse release is awaiting manual approval.
A new Deckhouse release is available but requires manual approval before it can be applied.
To approve the release, run the following command:
d8 k patch DeckhouseRelease NAME --type=merge -p='{"approved": true}' -
DeckhouseReleaseIsWaitingManualApproval
CE
S6
A new Deckhouse release is awaiting manual approval.
A new Deckhouse release is available but requires manual approval before it can be applied.
To approve the release, run the following command:
d8 k patch DeckhouseRelease NAME --type=merge -p='{"approved": true}' -
DeckhouseReleaseIsWaitingManualApproval
CE
S9
A new Deckhouse release is awaiting manual approval.
A new Deckhouse release is available but requires manual approval before it can be applied.
To approve the release, run the following command:
d8 k patch DeckhouseRelease NAME --type=merge -p='{"approved": true}' -
DeckhouseReleaseNotificationNotSent
CE
S4
Deckhouse release notification webhook hasn't been sent.
The Deckhouse release notification webhook failed to send.
To check the notification webhook address, run the following command:
d8 k get mc deckhouse -o yaml -
DeckhouseUpdating
CE
S4
Deckhouse is being updated to XXX.
-
DeckhouseUpdatingFailed
CE
S4
Deckhouse update has failed.
The Deckhouse update to version VERSION_NUMBER has failed.
Possible reasons:
- The next minor or patch version of the Deckhouse image is not available in the registry.
- The Deckhouse image is corrupted.
- Deckhouse cannot reach the registry.
To resolve this issue, follow these steps:
-
Check the state of the releases. The one stuck in
Pendingis the one that failed:d8 k get deckhousereleases -
Read the reason recorded on that release:
d8 k get deckhousereleases -o custom-columns='NAME:.metadata.name,PHASE:.status.phase,MESSAGE:.status.message' -
Read the corresponding error in the logs:
d8 k -n d8-system logs -l app=deckhouse --tail=200 | grep -i release -
Ensure that version VERSION_NUMBER of the Deckhouse image is present in the registry. If the cluster uses a mirror, the missing version has to be pulled into it first.
-
ModuleAtConflict
CE
S4
Conflict detected for module MODULE_NAME.
Deckhouse has detected conflicting sources for the MODULE_NAME module: it is available from more than one ModuleSource and no source is selected, so the module is not deployed.
To resolve this issue, follow these steps:
-
List the sources that provide the module:
d8 k get module MODULE_NAME -o jsonpath='{.properties.availableSources}{"\n"}' -
Compare what each source offers, so you pick the one you actually want:
d8 k get modulerelease -l module=MODULE_NAME -
Select the source in the module configuration:
d8 k patch moduleconfig MODULE_NAME --type=merge -p '{"spec":{"source":"SOURCE_NAME"}}' -
Verify that the module has left the
Conflictphase. TheSOURCEandPHASEcolumns show the result:d8 k get module MODULE_NAME
-
-
ModuleConfigObsoleteVersion
CE
S4
ModuleConfig NAME uses obsolete settings version VERSION_NUMBER, the latest one is XXX.
Deckhouse has detected that ModuleConfig
NAMEhasspec.version: VERSION_NUMBER, while the latest settings schema version of theNAMEmodule is XXX.Deckhouse converts
spec.settingsfrom version VERSION_NUMBER to version XXX on the fly, so the module keeps working, but the stored configuration remains outdated. Support for version VERSION_NUMBER may be dropped in a future release.To resolve this issue, follow these steps:
-
Review the migration notes for the
NAMEmodule settings, one line per conversion step:d8 k get modulesettingsdefinition NAME -o jsonpath='{range .spec.versions[*].conversions[*]}{.descriptions.en}{"\n"}{end}' -
Migrate
spec.settingsaccordingly and setspec.versionto XXX:d8 k edit moduleconfig NAME -
Verify that the version has been updated and no warnings are left:
d8 k get moduleconfig NAME -o jsonpath='{.spec.version}{"\t"}{.status.message}{"\n"}'
-
-
ModuleHasDeprecatedUpdatePolicy
CE
S4
Module MODULE_NAME is matched by the deprecated update policy UPDATE_POLICY_NAME.
Deckhouse has detected that the module
MODULE_NAMEis using the deprecated update policyUPDATE_POLICY_NAME. Thev1alpha1policy has a selector that no longer functions.To specify the update policy in the module configuration, run the following command:
d8 k patch moduleconfig MODULE_NAME --type='json' -p='[{"op": "add", "path": "/spec/updatePolicy", "value": "UPDATE_POLICY_NAME"}]'After resolving all alerts related to the update policy
UPDATE_POLICY_NAME, clear the selector by running the following command:d8 k patch moduleupdatepolicies.v1alpha1.deckhouse.io UPDATE_POLICY_NAME --type='json' -p='[{"op": "replace", "path": "/spec/moduleReleaseSelector/labelSelector/matchLabels", "value": {"": ""}}]' -
ModuleIsDeprecated
CE
S9
Module MODULE_NAME is deprecated.
The module
MODULE_NAMEis deprecated and will not receive new updates. The module may be removed in a future release, so disable it in a controlled manner rather than waiting for it to disappear.To resolve this issue, follow these steps:
-
Check the module state before changing anything. The
STAGEcolumn readsDeprecated, and the conditions show whether anything still runs:d8 k get module MODULE_NAME -
Find out whether other modules declare a dependency on it:
d8 k get modules -o json | jq -r '.items[] | select(.properties.requirements.modules | has("MODULE_NAME")) | .metadata.name' -
Once nothing depends on it and its workloads are no longer needed, disable the module:
d8 k patch moduleconfig MODULE_NAME --type=merge -p '{"spec":{"enabled":false}}'
-
-
ModuleIsInMaintenanceMode
CE
S6
Module MODULE_NAME is running in maintenance mode.
Module
MODULE_NAMEis running in maintenance mode. In this mode, its state is not reconciled, which prevents configuration or hook changes from being applied automatically.To switch the module back to normal mode, edit the corresponding ModuleConfig resource with the following command:
d8 k patch moduleconfig MODULE_NAME --type=json -p='[{"op": "remove", "path": "/spec/maintenance"}]' -
ModuleReleaseIsBlockedByRequirements
CE
S6
A new release for module MODULE_NAME has been blocked due to unmet requirements.
A new release for module
MODULE_NAMEhas been blocked because it doesn’t meet the required conditions.To check the requirements, run the following command:
d8 k get mr NAME -o json | jq .spec.requirements -
ModuleReleaseIsOutdated
CE
S5
Module MODULE_NAME is XXX or more minor versions behind the latest available release.
Module
MODULE_NAMEis running XXX or more minor versions behind the latest available release. This module is significantly outdated and may have compatibility issues.To approve the module release update, run the following command:
d8 k annotate mr NAME modules.deckhouse.io/approved="true" -
ModuleReleaseIsOutdated
CE
S7
Module MODULE_NAME is 2 minor versions behind the latest available release.
Module
MODULE_NAMEis running 2 minor versions behind the latest available release. Updating is recommended to maintain compatibility and access to latest features.To approve the module release update, run the following command:
d8 k annotate mr NAME modules.deckhouse.io/approved="true" -
ModuleReleaseIsOutdated
CE
S9
Module MODULE_NAME is 1 minor version behind the latest available release.
Module
MODULE_NAMEis running 1 minor version behind the latest available release. Consider updating to maintain compatibility and security.To approve the module release update, run the following command:
d8 k annotate mr NAME modules.deckhouse.io/approved="true" -
ModuleReleaseIsWaitingManualApproval
CE
S6
A new release for module MODULE_NAME is awaiting manual approval.
A new release for module
MODULE_NAMEis available but requires manual approval before it can be applied.To approve the module release, run the following command:
d8 k annotate mr NAME modules.deckhouse.io/approved="true"
Модуль descheduler
Модуль documentation
-
ModuleConfigDeprecated
CE
S9
Deprecated deckhouse-web ModuleConfig detected.
The
deckhouse-webmodule has been renamed todocumentation, and a newdocumentationModuleConfig is generated automatically.Steps to troubleshoot:
- Remove the deprecated
deckhouse-webModuleConfig from the CI deployment process. -
Delete it using the following command:
d8 k delete mc deckhouse-web
- Remove the deprecated
-
ModuleDocumentationRenderError
CE
S6
Documentation rendering failed for module MODULE_NAME.
An error occurred while rendering documentation for the
MODULE_NAMEmodule. The broken module was removed from the documentation site during Hugo build.Check the
ModuleDocumentationresource status for details:d8 k get moduledocumentations MODULE_NAME -o yamlCheck docs-builder logs for more information:
d8 k -n d8-system logs -l app=docs-builder | grep -i "removed broken module"
Модуль istio
-
D8IstioActiveWaypointsWithAmbientDisabled
EE
S6
Active Istio waypoint exists while ambient mesh is disabled.
Deckhouse has detected an active waypoint Deployment
DEPLOYMENT_NAMEin namespaceNAMESPACE, created for WaypointInstanceXXX, while ambient mesh is disabled.This usually happens if ambient mesh was enabled, a WaypointInstance was created, and then ambient mesh was disabled. In this state the waypoint-controller is not running, so it cannot reconcile or clean up WaypointInstance resources.
To inspect affected resources, run:
d8 k -n NAMESPACE get waypointinstance XXX -o yaml d8 k -n NAMESPACE get deploy,svc,sa,gateway,pdb,hpa,vpa -l istio.deckhouse.io/waypoint-instance=XXXRecommended remediation:
- Temporarily enable ambient mesh.
- Wait until waypoint-controller starts.
- Delete the affected WaypointInstance or change configuration as needed.
- Wait until managed waypoint resources are reconciled as needed or removed.
- Disable ambient mesh again.
If ambient mesh cannot be re-enabled, manually remove the managed waypoint resources and then remove the WaypointInstance finalizer only after verifying that no managed resources remain.
-
D8IstioActualDataPlaneVersionNotEqualDesired
EE
S8
There are pods with Istio data plane version VERSION_NUMBER, but desired version is XXX.
There are pods in the
NAMESPACEnamespace with Istio data plane versionVERSION_NUMBER, while the desired version isXXX. As a result, the Istio version will be changed after the pod is restarted.To resolve the issue, use the following cheat sheet:
### Namespace-wide configuration # `istio.io/rev=vXYZ`: Use a specific revision. # `istio-injection=enabled`: Use the global revision. d8 k get ns NAMESPACE --show-labels ### Pod-wide configuration d8 k -n NAMESPACE get pods -l istio.io/rev=DESIRED_VISION -
D8IstioActualVersionIsNotInstalled
EE
S4
The control plane version for pods with injected sidecars isn't installed.
There are pods in the
NAMESPACEnamespace with injected sidecars of versionVERSION_NUMBER(revisionREVISION_NUMBER), but the corresponding control plane version is not installed. As a result, these pods have lost synchronization with the state in Kubernetes.To resolve this issue, install the required control plane version. Alternatively, update the namespace or pod configuration to match an installed control plane version.
To identify orphaned pods, run the following command:
d8 k -n NAMESPACE get pods -l 'service.istio.io/canonical-name' -o json | jq --arg revision REVISION_NUMBER '.items[] | select(.metadata.annotations."sidecar.istio.io/status" // "{}" | fromjson | .revision == $revision) | .metadata.name' -
D8IstioAdditionalControlplaneDoesntWork
CE
S4
Additional control plane isn't working.
Deckhouse has detected that the additional Istio control plane
ISTIO_REVISION_LABELisn’t working.As a result, sidecar injection for pods with
ISTIO_REVISION_LABELisn’t working as well.To check the status of the control plane pods, run the following command:
d8 k get pods -n d8-istio -l istio.io/rev=ISTIO_REVISION_LABEL -
D8IstioAllianceAmbientGatewayAddressUnusable
EE
S6
The ambient east-west gateway has no address peers can dial.
The ambient east-west gateway is deployed in this cluster, but publishes no address peer clusters can dial: its Service is missing, it has no external address, no node is running a gateway pod, or every address it has is neither an IP address nor a usable DNS name. The
metadata-exporterpod logs ind8-istiosay which.Peer clusters keep using the addresses they fetched last, if any. Those that have none cannot reach ambient-mode workloads here.
To fix, set
alliance.ambientGateway.advertiseto the IP address or DNS name peers should dial. Or make the load balancer assign an address (alliance.ambientGateway.loadBalancerClass,.serviceAnnotations). Or switchalliance.ambientGateway.inlettoNodePortand check that gateway pods are scheduled (.nodeSelector,.tolerations). Or, if ambient multicluster is not needed, switch all multicluster members back to sidecar mode. -
D8IstioAllianceDataPlaneNotConnected
EE
S4
Data-plane connectivity check failed for XXX NAME.
The data-plane health check of XXX
NAMEwith uuidXXXhas been failing for more than 5 minutes.This means that actual service mesh traffic between clusters is not flowing properly, even though the control plane metadata exchange may be working.
Possible causes:
- The remote cluster’s
alliance-healthcheckpod is not running. - Istio sidecar injection is not working properly on the healthcheck pods.
- The ingress gateway between clusters is misconfigured or unreachable.
- mTLS or trust domain configuration issues between clusters.
To check the status:
d8 k get XXX NAME -o json | jq '.status.conditions[] | select(.type=="DataplaneConnectionReady")' - The remote cluster’s
-
D8IstioAllianceDiscoveryMetadataEndpointRequestedViaDeprecatedSubdomain
EE
S5
A peer cluster requests private metadata using a deprecated subdomain.
Remote XXX
NAME, (UUID:XXX) requests private metadata from hostnameXXX, that hostname uses the deprecatedistiosubdomain.Update the remote cluster XXX resource: set
spec.metadataEndpointto(publicDomainTemplate + istio-metadata)/metadata/.Migration steps on the remote cluster:
- Ensure DNS resolves the new target
(publicDomainTemplate + istio-metadata). - Update
spec.metadataEndpointto use the new domain name. Keep the path/metadata/unchanged. - Verify remote metadata fetch and alliance health after the change.
- Ensure DNS resolves the new target
-
D8IstioAllianceIngressGatewayAddressUnusable
EE
S6
The ingress gateway for federation and multicluster has no address peers can dial.
The ingress gateway that peer clusters reach this cluster through is deployed, but publishes no address they can dial: its Service is missing, it has no external address, or no node is running a gateway pod. The
metadata-exporterpod logs ind8-istiosay which.Peer clusters keep using the addresses they fetched last, if any. Those that have none cannot reach federated services or, over multicluster, sidecar-mode workloads here.
To fix, set
alliance.ingressGateway.advertiseto the addresses peers should dial. Or make the load balancer assign an address (alliance.ingressGateway.loadBalancerClass,.serviceAnnotations). Or switchalliance.ingressGateway.inlettoNodePortand check that gateway pods are scheduled (.nodeSelector,.tolerations). -
D8IstioConfigAnalysisConflictingGateways
EE
S5
Conflicting Istio Gateways detected (IST0145).
The Istio configuration analyzer found conflicting Gateways in revision
REVISION_NUMBER.Code:
XXX(ConflictingGateways) Namespace:NAMESPACEResource:XXXTwo or more Gateways share the same selector, port, and host match. Ingress traffic may be routed unpredictably or return 404.
Steps to resolve:
- List Gateways and compare
spec.selector, server ports, and hosts for overlaps involvingXXX. - Deduplicate or narrow hosts/ports so each combination is unique.
- See https://istio.io/latest/docs/reference/config/analysis/ist0145/
List matching issues in Prometheus (Grafana → Explore):
d8_istio_config_analysis_issue{type="ConflictingGateways",revision="REVISION_NUMBER"}Check analyzer logs:
d8 k -n d8-istio logs -l app=istio-config-analyzer,istio.io/rev=REVISION_NUMBER --tail=100 - List Gateways and compare
-
D8IstioConfigAnalysisError
EE
S5
Istio configuration analysis detected an error-level issue.
The Istio configuration analyzer found an error in revision
REVISION_NUMBER.Type:
ERROR_TYPE(XXX) Namespace:NAMESPACEResource:XXXInspect the reported resource in namespace
NAMESPACE.Documentation for analysis codes: https://istio.io/latest/docs/reference/config/analysis/
List analysis issues in Prometheus (Grafana → Explore):
d8_istio_config_analysis_issue{revision="REVISION_NUMBER",severity="Error"}Check analyzer pods and logs:
d8 k -n d8-istio get pods -l app=istio-config-analyzer,istio.io/rev=REVISION_NUMBER d8 k -n d8-istio logs -l app=istio-config-analyzer,istio.io/rev=REVISION_NUMBER --tail=100 -
D8IstioConfigAnalysisImageAutoWithoutInjection
EE
S5
Pod uses image auto without Istio injection (IST0147).
The Istio configuration analyzer found pods with
image: autothat are not targeted for sidecar injection in revisionREVISION_NUMBER.Code:
XXX(ImageAutoWithoutInjectionError) Namespace:NAMESPACEResource:XXXimage: autois rewritten only when the Istio injector mutates the pod. Without injection the container image stays literallyautoand the pod will not run correctly.Steps to resolve:
- Enable sidecar injection for the namespace or workload (
istio-injection=enabled/istio.io/rev=REVISION_NUMBER, or a matching RevisionTag). - Restart / recreate the affected pods after injection is enabled.
- See https://istio.io/latest/docs/reference/config/analysis/ist0147/
List matching issues in Prometheus (Grafana → Explore):
d8_istio_config_analysis_issue{type="ImageAutoWithoutInjectionError",revision="REVISION_NUMBER"}Check analyzer logs:
d8 k -n d8-istio logs -l app=istio-config-analyzer,istio.io/rev=REVISION_NUMBER --tail=100 - Enable sidecar injection for the namespace or workload (
-
D8IstioConfigAnalysisInvalidGatewayCredential
EE
S5
Gateway TLS credential is invalid (IST0161).
The Istio configuration analyzer found an invalid Gateway credential in revision
REVISION_NUMBER.Code:
XXX(InvalidGatewayCredential) Namespace:NAMESPACEResource:XXXThe Secret referenced by the Gateway for TLS is missing or does not contain a usable certificate/key. HTTPS listeners on that Gateway will fail.
Steps to resolve:
- Open the Gateway
XXXin namespaceNAMESPACEand notecredentialName/ TLS secret references. - Verify the Secret exists in the same namespace as the ingress Gateway workload and has valid
tls.crt/tls.key(or the expected keys). - See https://istio.io/latest/docs/reference/config/analysis/ist0161/
List matching issues in Prometheus (Grafana → Explore):
d8_istio_config_analysis_issue{type="InvalidGatewayCredential",revision="REVISION_NUMBER"}Check analyzer logs:
d8 k -n d8-istio logs -l app=istio-config-analyzer,istio.io/rev=REVISION_NUMBER --tail=100 - Open the Gateway
-
D8IstioConfigAnalysisReferencedResourceNotFound
EE
S5
Istio resource references a missing dependency (IST0101).
The Istio configuration analyzer found a missing reference in revision
REVISION_NUMBER.Code:
XXX(ReferencedResourceNotFound) Namespace:NAMESPACEResource:XXXAn Istio object points to a Gateway, Service, ServiceEntry, or another dependency that does not exist (typo, wrong namespace, or resource not created yet). Traffic to that route may fail.
Steps to resolve:
- Inspect the reported resource in namespace
NAMESPACEand fix the broken reference (use FQDN for cross-namespace hosts, e.g.reviews.backend.svc.cluster.local). - Confirm the target object exists.
- See https://istio.io/latest/docs/reference/config/analysis/ist0101/
List matching issues in Prometheus (Grafana → Explore):
d8_istio_config_analysis_issue{type="ReferencedResourceNotFound",revision="REVISION_NUMBER"}Check analyzer logs:
d8 k -n d8-istio logs -l app=istio-config-analyzer,istio.io/rev=REVISION_NUMBER --tail=100 - Inspect the reported resource in namespace
-
D8IstioConfigAnalysisSchemaValidationError
EE
S5
Istio resource failed schema validation (IST0106).
The Istio configuration analyzer found a schema validation error in revision
REVISION_NUMBER.Code:
XXX(SchemaValidationError) Namespace:NAMESPACEResource:XXXThe resource does not match the Istio API schema and may be ignored or rejected by the control plane.
Steps to resolve:
- Inspect
XXXin namespaceNAMESPACEand compare fields with the Istio API for your control plane version. - Fix invalid or unknown fields, then re-apply the manifest.
- See https://istio.io/latest/docs/reference/config/analysis/ist0106/
List matching issues in Prometheus (Grafana → Explore):
d8_istio_config_analysis_issue{type="SchemaValidationError",revision="REVISION_NUMBER"}Check analyzer logs:
d8 k -n d8-istio logs -l app=istio-config-analyzer,istio.io/rev=REVISION_NUMBER --tail=100 - Inspect
-
D8IstioConfigAnalysisWarning
EE
S4
Istio configuration analysis detected a warning-level issue.
The Istio configuration analyzer found a warning in revision
REVISION_NUMBER.Type:
ERROR_TYPE(XXX) Namespace:NAMESPACEResource:XXXInspect the reported resource in namespace
NAMESPACE.Documentation for analysis codes: https://istio.io/latest/docs/reference/config/analysis/
List analysis warnings in Prometheus (Grafana → Explore):
d8_istio_config_analysis_issue{revision="REVISION_NUMBER",severity="Warning"}Check analyzer pods and logs:
d8 k -n d8-istio get pods -l app=istio-config-analyzer,istio.io/rev=REVISION_NUMBER d8 k -n d8-istio logs -l app=istio-config-analyzer,istio.io/rev=REVISION_NUMBER --tail=100 -
D8IstioCustomCAMaterialInvalid
CE
S4
The Istio custom CA material is invalid but is being served to istiod.
The Istio module is publishing CA material (
XXX) that failed validation to istiod.The module never hard-blocks on module-owned or last-good material (doing so would rotate the mesh root and break mTLS cluster-wide), so it keeps serving this material with only a warning. However, istiod may reject it, which can prevent it from issuing or renewing workload certificates.
Depending on the
source:cacerts— thed8-istio/cacertsSecret (or the CA reused from it) is not a valid CA. Inspect the Secret and restore validca-cert.pem/ca-key.pem(androot-cert.pem/cert-chain.pemif used).secretRef:namespace/name— the last-good CA that was previously resolved from thisca.secretRefhas become invalid (for example, its chain expired). Fix the referenced Secret so the next re-resolution (every 5 minutes) succeeds.
Refer to the custom CA documentation.
-
D8IstioCustomCASecretRefUnresolved
CE
S5
The Istio custom CA ca.secretRef cannot be resolved.
The Istio module could not re-resolve the configured
ca.secretRef(XXX) and is keeping the last successfully-resolved CA.The mesh is not regressed — istiod keeps running on the exact CA material it already had — but any change made to the source Secret is not being picked up. Common causes:
- the referenced Secret was deleted or renamed;
- the referenced Secret was made malformed (not valid PEM, not a CA certificate, or a mismatched key pair);
- a transient Kubernetes API problem.
The module re-resolves the Secret every 5 minutes; this alert clears automatically once resolution succeeds. Inspect the referenced Secret and restore valid CA material.
Refer to the custom CA documentation.
-
D8IstioDataPlaneVersionMismatch
EE
S8
There are pods with data plane version different from the control plane version.
There are pods in the
NAMESPACEnamespace with Istio data plane versionVERSION_NUMBER, which is different from the control plane versionDESIRED_VERSION.Steps to resolve the issue:
-
Restart affected pods and use the following PromQL query to get a full list:
max by (namespace, dataplane_pod) (d8_istio_dataplane_metadata{full_version="VERSION_NUMBER"}) -
Use the automatic Istio data plane upgrade.
-
-
D8IstioDataPlaneWithoutIstioInjectionConfigured
EE
S4
Detected pods with Istio sidecars but istio-injection isn't configured.
There are pods in the
NAMESPACEnamespace with Istio sidecars, but istio-injection isn’t configured. As a result, these pods will lose their Istio sidecars after being recreated.To identify the affected pods, run the following command:
d8 k -n NAMESPACE get pods -o json | jq -r --arg revision REVISION_NUMBER '.items[] | select(.metadata.annotations."sidecar.istio.io/status" // "{}" | fromjson | .revision == $revision) | .metadata.name' -
D8IstioDeprecatedIstioVersionInstalled
CE
The installed Istio version has been deprecated.
Deckhouse has detected that a deprecated Istio version
VERSION_NUMBERis installed.Support for this version will be removed in upcoming Deckhouse releases. The higher the alert severity, the greater the probability of support being discontinued.
To learn how to upgrade Istio, refer to the upgrade guide.
-
D8IstioDesiredVersionIsNotInstalled
EE
S6
Desired control plane version isn't installed.
There is a desired Istio control plane version
XXX(revisionREVISION_NUMBER) configured for pods in theNAMESPACEnamespace, but that version isn’t installed. As a result, pods can’t be recreated in theNAMESPACEnamespace.To resolve this issue, install the desired control plane version. Alternatively, update the namespace or pod configuration to match an installed control plane version.
Use the following cheat sheet:
### Namespace-wide configuration # `istio.io/rev=vXYZ`: Use a specific revision. # `istio-injection=enabled`: Use the global revision. d8 k get ns NAMESPACE --show-labels ### Pod-wide configuration d8 k -n NAMESPACE get pods -l istio.io/rev=REVISION_NUMBER -
D8IstioFederationMetadataEndpointDoesntWork
EE
S6
IstioFederation FEDERATION_NAME gets no usable metadata from the remote cluster.
The Deckhouse hook could not get usable metadata from the endpoint
ENDPOINT_NAMEfor IstioFederationFEDERATION_NAME.The reason and the details are in the
PublicMetadataExchangeReadyandPrivateMetadataExchangeReadyconditions of the IstioFederation. The endpoint may respond normally while the metadata is still unusable, for example, when the ingress gateway of the remote cluster has no address yet.To view the conditions, run the following command:
d8 k get istiofederation FEDERATION_NAME -o jsonpath='{range .status.conditions[*]}{.type}: {.status}: {.reason}: {.message}{"\n"}{end}'To reproduce the request to the public endpoint, run the following command:
curl ENDPOINT_NAMETo reproduce the request to private endpoints (run from the Deckhouse pod), run the following:
KEY="$(deckhouse-controller module values istio -o json | jq -r .internal.remoteAuthnKeypair.priv)" LOCAL_CLUSTER_UUID="$(deckhouse-controller module values -g istio -o json | jq -r .global.discovery.clusterUUID)" REMOTE_CLUSTER_UUID="$(d8 k get istiofederation FEDERATION_NAME -o json | jq -r .status.metadataCache.public.clusterUUID)" TOKEN="$(deckhouse-controller helper gen-jwt --private-key-path <(echo "$KEY") --claim iss=d8-istio --claim sub=$LOCAL_CLUSTER_UUID --claim aud=$REMOTE_CLUSTER_UUID --claim scope=private-federation --ttl 1h)" curl -H "Authorization: Bearer $TOKEN" ENDPOINT_NAME -
D8IstioFederationRemoteClusterUUIDMismatch
EE
S4
IstioFederation peer cluster UUID changed.
Public metadata from
ENDPOINT_NAMEfor IstioFederationFEDERATION_NAMEreports cluster UUIDXXX, but the previously pinned UUID isXXX.Deckhouse stops private metadata exchange and does not send a federation JWT until the peer identity is confirmed again.
Check whether
spec.metadataEndpointwas pointed to another cluster or the remote endpoint was replaced.To inspect the resource:
d8 k get istiofederation FEDERATION_NAME -o yaml curl ENDPOINT_NAMEIf the peer change is intentional, recreate the IstioFederation resource so a new UUID can be pinned.
-
D8IstioGlobalControlplaneDoesntWork
CE
S4
Global control plane isn't working.
Deckhouse has detected that the global Istio control plane
ISTIO_REVISION_LABELisn’t working.As a result, sidecar injection for pods with global revision isn’t working as well, and the validating webhook for Istio resources is absent.
To check the status of the control plane pods, run the following command:
d8 k get pods -n d8-istio -l istio.io/rev=ISTIO_REVISION_LABEL -
D8IstioMulticlusterMetadataEndpointDoesntWork
EE
S6
IstioMulticluster MULTICLUSTER_NAME gets no usable metadata from the remote cluster.
The Deckhouse hook could not get usable metadata from the endpoint
ENDPOINT_NAMEfor IstioMulticlusterMULTICLUSTER_NAME.The reason and the details are in the
PublicMetadataExchangeReadyandPrivateMetadataExchangeReadyconditions of the IstioMulticluster. The endpoint may respond normally while the metadata is still unusable, for example, when the remote cluster does not deploy the gateway this cluster reaches it through.To view the conditions, run the following command:
d8 k get istiomulticluster MULTICLUSTER_NAME -o jsonpath='{range .status.conditions[*]}{.type}: {.status}: {.reason}: {.message}{"\n"}{end}'To reproduce the request to the public endpoint, run the following command:
curl ENDPOINT_NAMETo reproduce the request to private endpoints (run from the
d8-system/deckhousepod), run the following:KEY="$(deckhouse-controller module values istio -o json | jq -r .internal.remoteAuthnKeypair.priv)" LOCAL_CLUSTER_UUID="$(deckhouse-controller module values -g istio -o json | jq -r .global.discovery.clusterUUID)" REMOTE_CLUSTER_UUID="$(d8 k get istiomulticluster MULTICLUSTER_NAME -o json | jq -r .status.metadataCache.public.clusterUUID)" TOKEN="$(deckhouse-controller helper gen-jwt --private-key-path <(echo "$KEY") --claim iss=d8-istio --claim sub=$LOCAL_CLUSTER_UUID --claim aud=$REMOTE_CLUSTER_UUID --claim scope=private-multicluster --ttl 1h)" curl -H "Authorization: Bearer $TOKEN" ENDPOINT_NAME -
D8IstioMulticlusterRemoteAPIHostDoesntWork
EE
S6
Multicluster remote API host health check failed.
The remote API host
API_HOSTfor IstioMulticlusterMULTICLUSTER_NAMEhas failed the health check performed by the Deckhouse monitoring hook.To reproduce the request (run from the
d8-system/deckhousepod), run the following:TOKEN="$(deckhouse-controller module values istio -o json | jq -r --arg ah API_HOST '.internal.multiclusters[]| select(.apiHost == $ah)| .apiJWT ')" curl -H "Authorization: Bearer $TOKEN" https://API_HOST/version -
D8IstioMulticlusterRemoteClusterUUIDMismatch
EE
S4
IstioMulticluster peer cluster UUID changed.
Public metadata from
ENDPOINT_NAMEfor IstioMulticlusterMULTICLUSTER_NAMEreports cluster UUIDXXX, but the previously pinned UUID isXXX.Deckhouse stops private metadata exchange and does not send a multicluster JWT until the peer identity is confirmed again.
Check whether
spec.metadataEndpointwas pointed to another cluster or the remote endpoint was replaced.To inspect the resource:
d8 k get istiomulticluster MULTICLUSTER_NAME -o yaml curl ENDPOINT_NAMEIf the peer change is intentional, recreate the IstioMulticluster resource so a new UUID can be pinned.
-
D8IstioOperatorReconcileError
CE
S5
The istio-operator is unable to reconcile Istio control plane setup.
Deckhouse has detected an error in the
istio-operatorreconciliation loop.To investigate the issue, check the operator logs:
d8 k -n d8-istio logs -l app=operator,revision=REVISION_NUMBER -
D8IstioPodsWithoutIstioSidecar
EE
S4
Detected pods without Istio sidecars but with istio-injection configured.
There is a pod
POD_NAMEin theNAMESPACEnamespace without Istio sidecars, but with istio-injection configured.To identify the affected pods, run the following command:
d8 k -n NAMESPACE get pods -l '!service.istio.io/canonical-name' -o json | jq -r '.items[] | select(.metadata.annotations."sidecar.istio.io/inject" != "false") | .metadata.name' -
D8IstioRemoteClusterNotSynced
EE
S4
XXXIstioMulticluster MULTICLUSTER_NAME is not synchronized.XXXIstio remote cluster CLUSTER_ID is not synchronized.XXX
XXXThe Istio control plane instance
INSTANCE_NAMEcannot synchronize with the remote cluster described by IstioMulticlusterMULTICLUSTER_NAME(cluster IDCLUSTER_ID).XXXThe Istio control plane instanceINSTANCE_NAMEcannot synchronize with the remote clusterCLUSTER_ID.XXXPossible causes:
- The remote cluster is offline.
- The remote API endpoint is not reachable.
- The remote ServiceAccount token is invalid or expired.
- There is a TLS or certificate issue between the clusters.
- Remote and local Istio versions mismatch.
XXXCheck the conditions of the IstioMulticluster:
d8 k get istiomulticluster MULTICLUSTER_NAME -o jsonpath='{range .status.conditions[*]}{.type}: {.status}: {.reason}: {.message}{"\n"}{end}'All conditions must be
True. If a condition is notTrue, itsreasonandmessagesay what is wrong. Access to the remote API is reported by theRemoteAPIServerReadycondition.If there is no such resource, this cluster was registered by the secret
XXXalone — check the API address and the token in the kubeconfig it stores. XXXNo IstioMulticluster resource registered this cluster, so check the API address and the token in the kubeconfig stored in the secretXXX. XXX -
D8IstioReservedUIDConflict
CE
S4
Application container is running as UID 1337 (reserved by Istio).
Container
CONTAINER_NAMEin podPOD_NAMEin namespaceNAMESPACEis running as UID1337.UID
1337is reserved by Istio for theistio-proxysidecar container. When application containers run with this UID, their traffic bypasses Istio completely — no routing rules, mTLS, or telemetry will be applied.To fix the issue, change the
runAsUserin the container’s or pod’ssecurityContextto a different UID. -
D8IstioVersionIsIncompatibleWithK8sVersion
CE
S3
The installed Istio version is incompatible with the Kubernetes version.
The installed Istio version
VERSION_NUMBERmay not work properly with the current Kubernetes versionVERSION_NUMBERbecause it’s not supported officially.To resolve the issue, upgrade Istio following the guide.
-
IstioIrrelevantExternalServiceFound
CE
S5
External service found with irrelevant ports specifications.
A service
NAMEin theNAMESPACEnamespace has an irrelevant port specification.The
.spec.ports[]field isn’t applicable for services of theExternalNametype. However, Istio renders port listeners for external services as0.0.0.0:port, which captures all traffic to the specified port. This can cause problems for services that aren’t registered in the Istio registry.To resolve the issue, remove the
.spec.portssection from the service configuration. It is safe.
Модуль kube-dns
-
KubernetesCoreDNSHasCriticalErrors
CE
S5
Critical errors found in CoreDNS.
Deckhouse has detected at least one critical error in the CoreDNS pod POD_NAME.
To resolve the issue, review the container logs:
d8 k -n kube-system logs POD_NAME
Модуль metallb
-
D8MetallbBGPSessionDown
EE
S4
MetalLB BGP session is down.
JOB_NAME, MetalLB CONTAINER_NAME on POD_NAME has BGP session PEER down.
Check the logs for details:
d8 k -n d8-metallb logs daemonset/speaker -c speaker -
D8MetallbConfigNotLoaded
EE
S4
The MetalLB configuration hasn't been loaded.
JOB_NAME, MetalLB CONTAINER_NAME on POD_NAME hasn’t been loaded.
To find the cause of the issue, review the controller logs:
d8 k -n d8-metallb logs deploy/controller -c controller -
D8MetallbConfigStale
EE
S4
MetalLB is running on a stale configuration.
JOB_NAME, MetalLB CONTAINER_NAME on POD_NAME is running on a stale configuration because the latest configuration failed to load.
To find the cause of the issue, review the controller logs:
d8 k -n d8-metallb logs deploy/controller -c controller -
D8MetallbNotSupportedServiceAnnotationsDetected
SE
S4
The annotation 'ANNOTATION_NAME' has been deprecated for the service 'NAME' in the 'NAMESPACE' namespace.
The annotation ‘ANNOTATION_NAME’ has been deprecated for the service ‘NAME’ in the ‘NAMESPACE’ namespace.
The following service annotations are no longer effective:
metallb.universe.tf/ip-allocated-from-pool: Remove this annotation.metallb.universe.tf/address-pool: Replace it with the.spec.loadBalancerClassparameter or use thenetwork.deckhouse.io/metal-load-balancer-classannotation, referencing the appropriate MetalLoadBalancerClass.metallb.universe.tf/loadBalancerIPs: Replace it withnetwork.deckhouse.io/load-balancer-ips: IP.metallb.universe.tf/allow-shared-ip: Replace it withnetwork.deckhouse.io/load-balancer-shared-ip-key.metallb.io/ip-allocated-from-pool: Remove this annotation.metallb.io/address-pool: Replace it with the.spec.loadBalancerClassparameter or use thenetwork.deckhouse.io/metal-load-balancer-classannotation, referencing the appropriate MetalLoadBalancerClass.metallb.io/loadBalancerIPs: Replace it withnetwork.deckhouse.io/load-balancer-ips: IP.metallb.io/allow-shared-ip: Replace it withnetwork.deckhouse.io/load-balancer-shared-ip-key.
Please note. Existing LoadBalancer services of Deckhouse have been migrated automatically, but the new ones will not be.
-
D8MetallbObsoleteLayer2PoolsAreUsed
SE
S7
The metallb module has obsolete layer2 pools configured.
In ModuleConfig version 2, addressPool ‘NAME’ of type “layer2” are ignored. They should be removed from the configuration.
-
D8MetallbUpdateMCVersionRequired
SE
S5
The metallb ModuleConfig settings are outdated.
D8 MetalLB settings are outdated.
To resolve this issue, increase version in the ModuleConfig
metallb. -
L2LoadBalancerOrphanServiceFound
SE
S4
Orphaned service with an irrelevant L2LoadBalancer name has been found.
The cluster contains an orphaned service
NAMEin theNAMESPACEnamespace with an irrelevant L2LoadBalancer name.To resolve this issue, verify the L2LoadBalancer name specified in the annotation
network.deckhouse.io/l2-load-balancer-name.
Модуль multitenancy-manager
-
ClusterResourceGrantPolicyViolation
CE
S6
Objects in namespace XXX use cluster-wide resources that are not available to its project.
Objects in namespace
XXXreference cluster-wide resources (for example, a StorageClass or a ClusterRole) that the current ClusterResourceGrantPolicy objects do not make available to the project of this namespace. Theprojectlabel of the metric holds the namespace, not the project name. Such an object was created before the policy changed. It keeps working, and when it is updated, only new values are checked.Steps to troubleshoot:
- Find the objects, their fields and the resources on the “Security” → “Cluster Resource Grant Violations” Grafana dashboard, or in the
d8_cluster_objects_grant_violated{project="XXX"}metric (labelsviolating_object_name,violating_field,violating_resourceandgrant). -
Check which resources are available to the project:
d8 k get available RESOURCE_NAME -n XXX -o yaml - Make the resource available to the project in a ClusterResourceGrantPolicy, or change the field of the object to an available value.
- Find the objects, their fields and the resources on the “Security” → “Cluster Resource Grant Violations” Grafana dashboard, or in the
-
MultitenancyManagerHelmProjectTemplate
CE
S9
ProjectTemplate XXX still renders its projects from a Helm text in resourcesTemplate.
ProjectTemplate
XXXdescribes the objects of its projects with a Helm text inresourcesTemplate, and its projects are rendered from that text. They keep working as before. This form of a template is deprecated, andresourcesTemplategoes away in a future release, so move the template to structured fields andmanifestsbefore then. Moving a template from a Helm text describes the move step by step.The built-in templates
default,secureandsecure-with-dedicated-nodesare structured and accept the same parameters as their Helm texts did, exceptadministratorsandresourceQuota, so they show how a text maps to the fields. The full mapping is in Moving a template from a Helm text. Objects of the text that have no structured field go tomanifests, which the controller applies with thed8:project:adminrole of the project. An AuthorizationRule of theAdminaccess level goes to.spec.administratorsof each Project instead, becausemanifestsdoes not create one. Cluster-scoped objects have no place in a template.Once the template has structured fields in place of
resourcesTemplate, the AuthorizationRule and ResourceQuota objects that.spec.administratorsand.spec.quotareplace are deleted after these fields work, and an AuthorizationRule that names nobody from.spec.administratorsany more is deleted at once. Every other object of the text that the structured fields do not render under the same kind and name is left in place, and theMultitenancyManagerProjectKeepsHelmTemplateObjectsalert names the project untilmanifeststakes the object over or it is deleted. The administrators then have thed8:project:adminrole in place of theAdminaccess level, and the two roles do not grant the same permissions. See Switching a project from a Helm text.Steps:
-
Read the template and compare it with the built-in template it was copied from, if any:
d8 k get projecttemplate XXX -o yaml d8 k get projecttemplate default -o yaml -
List the projects of the template. A template that no project uses can be deleted, and the alert goes with it:
d8 k get projects -l projects.deckhouse.io/project-template=XXX -
Find the projects of the template that still set
administratorsorresourceQuotain.spec.parameters:d8 k get projects -l projects.deckhouse.io/project-template=XXX -o json | jq -r '.items[] | select((.spec.parameters // {}) | has("administrators") or has("resourceQuota")) | .metadata.name'These values get no standard fields and are not handed over, so move them to
.spec.administratorsand.spec.quotafirst, and only as far as they mean the same there..spec.administratorsgives users and groups thed8:project:adminrole, so an administrator with another access level or another kind of subject needs a ProjectRoleBinding of its own..spec.quotaenforces every limit it holds,0included, so leave out a limit that the text did not render, such as a0that it skipped. -
If the structured fields and
manifestscover what the projects need, which they do unless the projects need cluster-scoped objects of the text or objects that thed8:project:adminrole does not allow, write the template asdeckhouse.io/v1alpha2with these fields andmanifestsand withoutresourcesTemplate, in one change, where the template is applied from, for example in Git or in CI. A template that projects use cannot loseresourcesTemplatewithout structured fields ormanifestsin its place, and once it has fields thatdeckhouse.io/v1alpha1cannot describe, a write of it throughdeckhouse.io/v1alpha1is refused. If the template is an unchanged copy of a built-in template, you can instead move its projects to that template in.spec.projectTemplateNameand then delete the copy. -
Check each project after the switch. Its
HandoverPendingcondition is removed once the replaced objects are deleted, itsManifestsAppliedcondition says whether the objects ofmanifestsare applied, and.status.keptObjectslists the objects left in place:d8 k get project PROJECT_NAME -o jsonpath='{range .status.conditions[*]}{.type}={.status}: {.message}{"\n"}{end}{range .status.keptObjects[*]}{.kind} {.namespace}/{.name}{"\n"}{end}'
-
-
MultitenancyManagerPreviousRevisionStillRunning
CE
S6
Pods of several revisions of the multitenancy-manager controller have run side by side for more than 15 minutes.
Pods of VALUE revisions of the
multitenancy-managerDeployment in thed8-multitenancy-managernamespace have been pending or running side by side for more than 15 minutes.The rollout of the controller is stuck: the new pod is pending or not ready, or an old pod is stuck terminating on a lost node. The new pod waits for the pods of older revisions for 10 minutes at most and then starts its controllers anyway. If an old pod of a revision that runs without leader election is still running, both pods write the Helm releases of the projects, and objects in the project namespaces may be deleted and created again.
Steps to troubleshoot:
-
List the controller pods with their revisions and nodes:
d8 k -n d8-multitenancy-manager get pods -L pod-template-hash -o wide -
Find out whether the new pod has started its controllers:
d8 k -n d8-multitenancy-manager logs NEW_POD_NAME -c multitenancy-manager | grep 'other revisions'hold the controllers until the pods of other revisions finishmeans that the new pod holds the lease and waits.no pods of other revisions to wait formeans that it has started its controllers at once, because the old pods had finished or were deleted more than 10 minutes ago.the pods of other revisions finishedmeans that it has started its controllers after waiting, because the old pods finished or were deleted more than 10 minutes ago.the pods of other revisions did not finish in time, starting the controllers anywaymeans that it has started its controllers after 10 minutes of waiting.
Without any of these lines, the new pod waits for the lease that the old pod holds. When the wait ends after 10 minutes, the new pod also writes a Warning event with the reason
PreviousRevisionStillRunning, and the message of the event names the old pods. An event is kept for an hour by default:d8 k -n d8-multitenancy-manager get events --field-selector reason=PreviousRevisionStillRunning -
Check the node of the old pod, shown in the
NODEcolumn:d8 k get node NODE_NAME -
Act on what you see:
-
The old pod is
Running, not terminating, and the new pod is not ready. The Deployment removes the old pods only after the new ones are ready, and deleting an old pod does not help, since its ReplicaSet creates it again. Find out why the new pod is not ready:d8 k -n d8-multitenancy-manager describe pod NEW_POD_NAME -
The old pod is
Terminatingon a node that isNotReady. Such a pod stays until its node comes back or the Node object is deleted. If the node is lost for good, delete the Node object, and its pods are deleted with it. If you know the machine of the node is powered off, you can force-delete the old pod instead:d8 k -n d8-multitenancy-manager delete pod OLD_POD_NAME --force --grace-period=0Do not force-delete a pod whose containers may still run. The pod disappears from the API, while its process keeps writing the Helm releases.
-
-
-
MultitenancyManagerProjectHandoverStuck
CE
S6
Project XXX still keeps the AuthorizationRule and ResourceQuota objects its standard fields replace.
An upgrade of the release of project
XXXdropped AuthorizationRule or ResourceQuota objects that the Helm text of its template had rendered for the administrators and the quota of the project. These are the AuthorizationRule objects with theAdminaccess level of the administrators and a quota such asall-podswhose every limit.spec.quotasets. That happens when a template switches fromresourcesTemplateto structured fields, when a project moves to such a template, or when the text no longer renders these objects. The controller kept them through the upgrade, so that the administrators never lost access and the namespace never lost its quota, and deletes them once the standard fields of the project replace them. The handover began more than 30 minutes ago and has not finished.Until it does, the kept AuthorizationRule objects keep granting the
Adminaccess level, theuser-authz:adminrole, next to thed8:project:adminrole of thed8-administratorsProjectRoleBinding. The kept quotas keep applying next to thed8-project-quotaResourceQuota, and the tighter of them wins.The kept objects are deleted by a reconcile of the project that succeeds once all of the following hold, and not earlier than 2 minutes after
d8-administratorsbecameReadyand after the handover began:- the
d8-administratorsProjectRoleBinding names the administrators from.spec.administratorsand isReadyfor its current generation, when a kept AuthorizationRule names one of them; - the
d8:project:adminClusterRole has its aggregated rules, when a kept AuthorizationRule names one of the administrators; - the
d8-project-quotaResourceQuota has the limits from.spec.quotaand is calculated, that is, itsstatus.hardmatches itsspec.hard, when a kept quota has limits.
A kept AuthorizationRule that names nobody from
.spec.administratorsany more is deleted at once, and a subject removed from.spec.administratorsis removed at once from a kept AuthorizationRule that names other administrators too. A reconcile that cannot find the template, validate the project against it, upgrade the release or apply the standard fields stops before the deletion, and the kept objects stay. A template that grants a role forbidden in projects puts the project in theErrorstate too, but it does not stop the deletion.The
HandoverPendingcondition of the project says what the controller waits for.Steps to troubleshoot:
-
Read what the controller waits for, and the state and the other conditions of the project:
d8 k get project XXX -o jsonpath='{.status.state}{"\n"}{range .status.conditions[*]}{.type}={.status}: {.message}{"\n"}{end}' -
Check the administrators binding. Its
status.observedGenerationmust matchmetadata.generation, and itsReadycondition must beTrue:d8 k -n XXX get projectrolebinding d8-administrators -o yamlIf the binding lags behind, the controller could not create its RoleBinding in some namespace of the project. The logs of the controller name the namespace and the error:
d8 k -n d8-multitenancy-manager logs -l app=multitenancy-manager -c multitenancy-manager --tail=-1 --prefix | grep d8-administrators -
Check that the
d8:project:adminClusterRole has rules. The aggregation controller of kube-controller-manager fills them:d8 k get clusterrole d8:project:admin -o jsonpath='{.rules}' -
Check the project quota and the events in the namespace of the project:
d8 k -n XXX get resourcequota d8-project-quota -o yaml d8 k -n XXX get events --sort-by=.lastTimestampA quota whose
status.hardstays empty is not processed by the resource quota controller of kube-controller-manager. -
Fix what the checks show, for example a RoleBinding that an admission policy refuses in one of the namespaces of the project, a kube-controller-manager that does not process the quota, or the condition that stops the reconcile of the project. The controller checks again whenever
d8-administratorsord8-project-quotachanges, and at least every minute, and deletes the kept objects once the conditions hold.
- the
-
MultitenancyManagerProjectKeepsHelmTemplateObjects
CE
S7
Project XXX has VALUE objects left from the Helm text of its template.
The release of project
XXXno longer holds VALUE objects that the Helm text of aresourcesTemplatehad rendered, because the project switched to structured fields, or because.spec.quotastopped covering a quota kept for a handover. Examples are AuthorizationRule or RoleBinding objects, quotas, network policies, workloads or their volumes. Instead of deleting them, the controller left them in place:- They keep working as before. The rules and the bindings keep granting access, the quotas keep applying, and the workloads keep running.
- The project no longer manages them. A change of the template or of the project does not change them. When the project is deleted, the ones in its namespaces go with the namespaces, and the controller deletes the cluster-scoped ones that still carry the label.
- They carry the
projects.deckhouse.io/kept-from-helm-template: "true"label and thehelm.sh/resource-policy: keepannotation, and they have lost theheritage: multitenancy-managerlabel. While they carry the label, only a requester who may make the same change to objects of their kind across the cluster may change or delete them, so the users of the project may not.
The project lists them in
.status.keptObjectsuntil each of them is deleted, loses the label, is rendered by the template again, or is taken over by themanifestsof the template. Decide for each object:- If it is still needed, describe it in the template or in the project, for example with a ProjectRoleBinding in place of an AuthorizationRule or a RoleBinding, or with a limit in
.spec.quota, and then delete the object. Or remove the label to hand it over to the project, whose users may then change and delete it. - If it is in a namespace of the project,
manifestsof the template can take it over. Oncemanifestsrenders an object of the same kind, namespace and name, the controller applies it as thesystem:multitenancy-manager:project:XXXuser, removes the label and takes the object off the list. The object then has whatmanifestsrenders, and a field that the Helm text set andmanifestsleaves out is removed. - If it is not needed, delete it. An access it grants ends only when it is deleted.
- If the template renders an object of the same kind and name again, the project release takes it over. The controller then removes the label, puts the
heritage: multitenancy-managerlabel back and removes thehelm.sh/resource-policy: keepannotation, unless the template sets it itself.
Steps:
-
List the objects:
d8 k get project XXX -o jsonpath='{range .status.keptObjects[*]}{.kind} {.namespace}/{.name}{"\n"}{end}' -
Keep an object as your own:
d8 k -n NAMESPACE label KIND NAME projects.deckhouse.io/kept-from-helm-template- -
Delete an object:
d8 k -n NAMESPACE delete KIND NAME
The controller looks at the list every 10 minutes, and at a reconcile of the project at most once a minute.
-
MultitenancyManagerProjectNamedLikeAdditionalNamespace
CE
S8
Project XXX is named like an additional namespace of project XXX.
The name of project
XXXis the name of projectXXX, a dash and a suffix. Additional namespaces of a project are named this way (project-spec.nameof a ProjectNamespace), butXXXis not one of them. It is a separate project with a namespace of its own. The administrators, quota, bindings and template of projectXXXdo not apply to it.Such a pair appears when both namespaces existed before they became projects, or when a project is created under such a name. Nothing is broken, but the names read as one project to anyone who looks at them.
If the two projects are meant to be separate, nothing has to change in the cluster. The alert keeps firing for as long as both projects exist, so silence it for this pair in Alertmanager.
If
XXXis meant to be an additional namespace of projectXXX, recreate it as one. A namespace cannot move between projects in place. Deleting the project deletes its namespace with everything in it.- Make sure that everything running in the
XXXnamespace can be deployed again, or move it elsewhere first. -
Find the ClusterProjectRoleBinding objects that name the ServiceAccounts of the
XXXnamespace. While a cluster-wide binding names them, the ProjectNamespace in step 4 is refused, so remove these subjects from the bindings first and add them back once the namespace is there again:d8 k get clusterprojectrolebindings -o json | jq -r --arg ns XXX '.items[] | select(any(.spec.subjects[]?; (.kind == "ServiceAccount" and .namespace == $ns) or (.kind == "User" and (.name | startswith("system:serviceaccount:" + $ns + ":"))) or (.kind == "Group" and .name == "system:serviceaccounts:" + $ns))) | .metadata.name' -
Delete the project. The command returns once the namespace is gone:
d8 k delete project XXX - Create a ProjectNamespace in the
XXXnamespace, withspec.nameset to the part of the name afterXXX-. The controller creates theXXXnamespace again, as an additional namespace of projectXXX. - Deploy the workloads into the namespace.
- Make sure that everything running in the
Модуль node-local-dns
-
D8NodeLocalDNSCacheDenialEvictionsHigh
BE
S6
node-local-dns denial cache is being frequently evicted.
The
denial(NXDOMAIN) cache in node-local-dns is evicting entries frequently.This might indicate that there are Services that are being recreated too often in cluster. So, denial cache size is not enough (
denial 65536is currently configured).Affected node:
NODE_NAME -
D8NodeLocalDNSCacheSuccessEvictionsHigh
BE
S6
node-local-dns success cache is being frequently evicted.
The
successcache in node-local-dns is evicting entries frequently (>100 in 5 minutes).This could mean there are too many different DNS records application have to resolve (to many Services?). So, node-local-dns cache capacity is too small (
success 120000is currently configured), or traffic patterns changed.Affected node:
NODE_NAME -
D8NodeLocalDNSForwardMaxConcurrentRejects
BE
S5
The forward plugin is rejecting DNS queries due to max concurrency limit.
More than 20 queries were rejected within the last 5 minutes on node
NODE_NAMEbecause the max concurrent query limit was reached. -
D8NodeLocalDNSKubeforwardRequestLatencyP95High
BE
S4
High DNS request latency in kubeforward (p95 > 300ms under load).
The 95th percentile DNS request latency for A-records through kubeforward exceeded 300 milliseconds over the last 5 minutes while handling more than 0.1 QPS.
This may indicate slow upstreams, network issues, or DNS overload on this node.
Affected node:
NODE_NAMEFor more detailed diagnostics, inspect
Top 5 upstreams by slow kubeforward requestsin Grafana.If the alert fires only on one node, run the checks below from node
NODE_NAME(for example, from a debug pod on this node). If the alert fires on many nodes, treat it as a potential systemic issue first.Get kubeforward upstream IPs from a master host:
d8 k -n kube-system get po -l k8s-app=kube-dns -o jsonpath='{.items[*].status.podIP}'Then run latency checks on the affected node
NODE_NAME(or from a debug pod on that node):UPSTREAMS="paste kube-dns pod IPs here" for ip in $UPSTREAMS; do echo "== upstream ${ip} ==" for i in $(seq 1 20); do dig @"$ip" -p 5353 kubernetes.default.svc.cluster.local A +tries=1 +time=1 +stats | grep "Query time" done doneTo identify slow requests, enable module logs (
enableLogs) and inspect slow query messages:pod=$(kubectl -n kube-system get po -l k8s-app=node-local-dns --field-selector spec.nodeName=NODE_NAME -o jsonpath='{.items[0].metadata.name}') d8 k -n kube-system logs "$pod" | grep '\[kubeforward\] slow query'Example log line:
[kubeforward] slow query A kubernetes.default.svc.cluster.local. took 425ms (rcode=NOERROR, upstream=10.96.0.10:53)Interpretation:
- If most upstreams are slow and many nodes are affected, suspect systemic network/CoreDNS overload.
- If one upstream is slow or only one node is affected, suspect a localized issue.
-
D8NodeLocalDNSUpstreamHealthcheckFailed
BE
S5
Too many upstream health check failures in forward plugin.
The health check system of the
forwardplugin failed more than 10 times within 5 minutes on nodeNODE_NAME. As a result, all upstreams were considered unhealthy.
Модуль node-manager
-
There are unavailable instances in the MACHINE_DEPLOYMENT_NAME MachineDeployment.
The MachineDeployment
MACHINE_DEPLOYMENT_NAMEhas VALUE unavailable instances.Check the status of the instances in the cluster with the following command:
d8 k get instance -l node.deckhouse.io/group=MACHINE_DEPLOYMENT_NAME -
ClusterHasOrphanedDisks
CE
S6
Cloud data discoverer found orphaned disks in the cloud.
The cloud data discoverer has found disks in the cloud that do not have a corresponding PersistentVolume in the cluster.
You can safely delete these disks manually from your cloud provider:
ID: ID, Name: NAME
-
D8BashibleApiserverLocked
CE
S6
Bashible-apiserver has been locked for too long.
Bashible-apiserverhas been locked for an extended period.To resolve the issue, check if the
bashible-apiserverPods are up-to-date and running:d8 k -n d8-cloud-instance-manager get pods -l app=bashible-apiserver -
D8CloudDataDiscovererCloudRequestError
CE
S6
Cloud data discoverer cannot get data from the cloud.
Refer to the cloud data discoverer’s logs for details:
d8 k -n NAMESPACE logs deploy/cloud-data-discoverer -
D8CloudDataDiscovererSaveError
CE
S6
Cloud data discoverer cannot save data to a Kubernetes resource.
Refer to the cloud data discoverer’s logs for details:
d8 k -n NAMESPACE logs deploy/cloud-data-discoverer -
D8ClusterAutoscalerManagerPodIsNotReady
CE
S8
The POD_NAME Pod is NOT Ready.
To check the Pod’s status, run the following command:
d8 k -n NAMESPACE logs POD_NAME -
D8ClusterAutoscalerPodIsNotRunning
CE
S8
The cluster-autoscaler Pod is NOT Running.
The POD_NAME Pod is STATUS.
To check the Pod’s status, run the following command:
d8 k -n NAMESPACE get pods POD_NAME -o json | jq .status -
D8ClusterAutoscalerPodIsRestartingTooOften
CE
S9
Too many cluster-autoscaler restarts detected.
The cluster-autoscaler has restarted VALUE times in the past hour.
Frequent restarts may indicate a problem. The cluster-autoscaler is expected to run continuously without interruption.
Check the logs for details:
d8 k -n d8-cloud-instance-manager logs -f -l app=cluster-autoscaler -c cluster-autoscaler -
D8ClusterAutoscalerTargetAbsent
CE
S8
Cluster-autoscaler target is missing in Prometheus.
The cluster-autoscaler automatically scales nodes in the cluster. If it’s unavailable, it will be impossible to add new nodes when there’s not enough resources for scheduling Pods. It may also lead to unnecessary cloud costs due to unused but still provisioned cloud instances.
To resolve the issue, follow these steps:
-
Check availability and status of cluster-autoscaler Pods:
d8 k -n d8-cloud-instance-manager get pods -l 'app in (cluster-autoscaler,cluster-autoscaler-mcm)' -
Verify that the cluster-autoscaler Deployment exists:
d8 k -n d8-cloud-instance-manager get deploy -l 'app in (cluster-autoscaler,cluster-autoscaler-mcm)' -
Check the Deployment’s status:
d8 k -n d8-cloud-instance-manager describe deploy deployment-name
-
-
D8ClusterAutoscalerTargetDown
CE
S8
Prometheus is unable to scrape cluster-autoscaler’s metrics.
-
D8ClusterAutoscalerTooManyErrors
CE
S8
Cluster-autoscaler is issuing too many errors.
The cluster-autoscaler encountered multiple errors from the cloud provider when attempting to scale the cluster.
Check the logs for details:
d8 k -n d8-cloud-instance-manager logs -f -l app=cluster-autoscaler -c cluster-autoscaler -
D8KubeletCheckpointStateUnpinnedContainers
CE
S4
Pod NAMESPACE/POD_NAME may run in a NUMA zone other than the one recorded by kubelet.
Kubelet on Node
NODE_NAMEreset the memory manager checkpoint and recorded new NUMA zones for PodNAMESPACE/POD_NAME. Zones are applied only when a container is created, so the running containers stay in their previous zones, which may differ from the recorded ones.As a result, the zone the Pod really uses may also be assigned to another Guaranteed Pod, causing both Pods to share its memory resources. The Pod’s CPUs and memory may also be assigned to different NUMA zones, which slows down its memory access.
The Pod is not restarted automatically. The restart time depends on the workload. To restore resource isolation, do the following:
-
To recreate the Pod’s containers in newly assigned NUMA zones, delete the Pod:
d8 k -n NAMESPACE delete pod POD_NAME - For a virtual machine, perform a live migration to another node instead, without stopping it.
- If the node runs many such Pods, you can drain it instead of deleting them one by one.
The alert resolves within a few minutes after the Pod is recreated. No kubelet restart is needed.
-
-
D8MachineControllerManagerPodIsNotReady
CE
S8
The POD_NAME Pod is NOT Ready.
-
D8MachineControllerManagerPodIsNotRunning
CE
S8
The machine-controller-manager Pod is NOT Running.
The POD_NAME Pod is STATUS.
To check the Pod’s status, run the following command:
d8 k -n NAMESPACE get pods POD_NAME -o json | jq .status -
D8MachineControllerManagerPodIsRestartingTooOften
CE
S9
Too many machine-controller-manager restarts detected.
The
machine-controller-managerhas restarted VALUE times in the past hour.Frequent restarts may indicate a problem. The
machine-controller-manageris expected to run continuously without interruption.Check the logs for details:
d8 k -n d8-cloud-instance-manager logs -f -l app=machine-controller-manager -c controller -
D8MachineControllerManagerTargetAbsent
CE
S8
Machine-controller-manager target is missing in Prometheus.
Machine-controller-managercontrols ephemeral nodes in the cluster. If it becomes unavailable, it will be impossible to create or delete nodes in the cluster.To resolve the issue, follow these steps:
-
Check availability and status of
machine-controller-managerPods:d8 k -n d8-cloud-instance-manager get pods -l app=machine-controller-manager -
Verify availability of the
machine-controller-managerDeployment:d8 k -n d8-cloud-instance-manager get deployment machine-controller-manager -
Check the Deployment’s status:
d8 k -n d8-cloud-instance-manager describe deployment machine-controller-manager
-
-
D8MachineControllerManagerTargetDown
CE
S8
Prometheus is unable to scrape the machine-controller-manager’s metrics.
-
D8NeedMigrateStateToOpenTofu
CE
S4
Terraform state must be migrated to OpenTofu.
This likely means the automatic migration to OpenTofu was canceled due to destructive changes detected in the cluster state.
Verify the following:
-
Current Terraform version:
d8 k -n d8-system exec -it deployments/terraform-state-exporter -c exporter -- terraform version -
Version in the Terraform state:
d8 k -n d8-system get secret d8-cluster-terraform-state -o json | jq -r '.data["cluster-tf-state.json"] | @base64d | fromjson | .terraform_version' -
Check for destructive changes:
d8 k exec -it deploy/terraform-state-exporter -n d8-system -- dhctl terraform check
To resolve the issue and migrate to OpenTofu manually, follow these steps:
-
Using the
installcontainer with the previous major Deckhouse release (for example,1.69.X, while the cluster is now on1.70.X), run:dhctl convergeThis should resolve all destructive changes in the cluster.
-
After that, the
terraform-auto-convergerPod should complete the migration automatically.
If the automatic migration doesn’t happen, use the
installcontainer with the current Deckhouse release and run the following command to enforce migration of the Terraform state to OpenTofu:dhctl converge-migrationIf this alert appears in a cluster created by Deckhouse Commander, it means the cluster has been updated to a new Deckhouse version without approving state changes (for example, destructive changes).
To resolve this, follow these steps:
- In Deckhouse Commander, click Delete manually to temporarily remove the cluster from control.
-
In the cluster, remove the
commander-agentmodule using the following command:d8 k delete mc commander-agent -
Using the
installcontainer with the previous major Deckhouse release (for example,1.69.X, while the cluster is now on1.70.X), run the following command to resolve all destructive changes in the cluster:dhctl converge - In Deckhouse Commander, click Attach to reattach the cluster.
-
-
D8NodeCgroupV2NotSupported
CE
S8
Node NODE_NAME is using deprecated cgroup v1 – migration to v2 required.
Node NODE_NAME in NodeGroup NODE_GROUP_NAME does not support cgroup v2. Starting from Kubernetes 1.35, cgroup v1 is deprecated. To migrate to cgroup v2, please upgrade the kernel to version 5.8 or newer. For more information, please refer to the documentation.
-
D8NodeContainerdV2NotSupported
CE
S8
Node NODE_NAME is using deprecated containerd v1 – migration to v2 required.
Node NODE_NAME in NodeGroup NODE_GROUP_NAME does not support containerd v2. Starting from Kubernetes 1.38, containerd v1.y will no longer be supported. Please check the requirements for containerd v2 and schedule your migration plan.
The exact reason is listed in the
node.deckhouse.io/containerd-v2-errannotation on the node.If the reason is
erofsand the node runs Ubuntu in AWS, the module is shipped in a separatelinux-modules-extrapackage. DKP installs it automatically, but for some kernels, mostly outdated ones, the package is no longer published in the APT repository. In that case, the installation is skipped and a warning is written to the node logs. The problem has been confirmed for the5.15.0-1028-aws,6.8.0-1024-aws, and6.8.0-1029-awskernels. Switch the node group to a newer AMI or kernel version that includeserofs. -
D8NodeControllerReconcileErrorsHigh
CE
S8
Node-controller reconcile errors are high for CONTROLLER_NAME.
Controller
CONTROLLER_NAMEhas a reconcile error rate above 0.1 errors per second for more than 10 minutes.Check node-controller logs:
kubectl -n d8-cloud-instance-manager logs deploy/node-controller --all-pods=true -
D8NodeControllerReconcileP99High
CE
S8
Node-controller reconcile p99 is high for CONTROLLER_NAME.
The p99 reconcile duration for controller
CONTROLLER_NAMEhas been above 5 seconds for more than 10 minutes.This may indicate slow reconciliation, Kubernetes API latency, or degraded controller performance.
To inspect node-controller logs:
kubectl -n d8-cloud-instance-manager logs deploy/node-controller --all-pods=true -
D8NodeControllerWorkqueueDepthHigh
CE
S8
Node-controller workqueue NAME has a high backlog.
The node-controller workqueue
NAMEhas more than 50 queued objects for more than 15 minutes.This may indicate that the controller cannot process reconciliation events fast enough.
To inspect node-controller logs:
kubectl -n d8-cloud-instance-manager logs deploy/node-controller --all-pods=true -
D8NodeGroupIsNotUpdating
CE
S8
NodeGroup NODE_GROUP_NAME is not handling the update correctly.
There is a new update available for Nodes in the
NODE_GROUP_NAMENodeGroup. Although Nodes have detected the update, none of them have received approval to start the update process.Most likely, there is a problem with the
update_approvalhook of thenode-managermodule. -
D8NodeIsNotUpdating
CE
S7
Node NODE_NAME cannot complete the update.
Node
NODE_NAMEin NodeGroupNODE_GROUP_NAMEdetected a new update, requested and received approval, started the update, and encountered a step that could cause downtime. The update manager (theupdate_approvalhook of thenode-groupmodule) granted downtime approval, but no success message was received, which indicates that the update has not completed.To investigate the details, view Bashible logs on the Node:
journalctl -fu bashible -
D8NodeIsNotUpdating
CE
S8
Node NODE_NAME cannot complete the update.
Node
NODE_NAMEin NodeGroupNODE_GROUP_NAMEhas detected a new update, requested and received approval, but failed to complete the update.To investigate the details, view Bashible logs on the Node:
journalctl -fu bashible -
D8NodeIsNotUpdating
CE
S9
Node NODE_NAME is not updating.
Node
NODE_NAMEin NodeGroupNODE_GROUP_NAMEhas a pending update but it’s neither receiving it nor attempting to.Most likely, Bashible is not handling the update correctly. It should annotate the Node with
update.node.deckhouse.io/waiting-for-approvalbefore the update can proceed.Options to investigate the details:
-
Check the expected configuration checksum for the NodeGroup:
d8 k -n d8-cloud-instance-manager get secret configuration-checksums -o jsonpath={.data.NODE_GROUP_NAME} | base64 -d -
Check the current configuration checksum on the Node:
d8 k get node NODE_NAME -o jsonpath='{.metadata.annotations.node\.deckhouse\.io/configuration-checksum}' -
View Bashible logs on the Node:
journalctl -fu bashible
-
-
D8NodeIsUnmanaged
CE
S9
The NODE_NAME Node is not managed by the node-manager module.
The NODE_NAME Node is not managed by the
node-managermodule.To resolve this issue, follow the instructions how to clean up the node and add it to the cluster.
-
D8NodeUpdateStuckWaitingForDisruptionApproval
CE
S8
Node NODE_NAME cannot obtain disruption approval.
Node
NODE_NAMEin NodeGroupNODE_GROUP_NAMEdetected a new update, requested and received initial approval, and started the update. However, it reached a stage that could cause downtime and was unable to obtain disruption approval. A disruption approval is normally issued automatically by theupdate_approvalhook of thenode-managermodule.To resolve this issue, investigate why the approval could not be granted to proceed with the update.
-
D8ProblematicNodeGroupConfiguration
CE
S8
Node NODE_NAME cannot begin the update.
There is a new update available for Nodes in the
NODE_GROUP_NAMENodeGroup. However, NodeNODE_NAMEcannot begin the update.The Node is missing the
node.deckhouse.io/configuration-checksumannotation, which may indicate that its bootstrap process did not complete correctly.Troubleshooting options:
- Check the
cloud-initlog (/var/log/cloud-init-output.log) on the node. - Check the NodeGroupConfiguration resource associated with the
NODE_GROUP_NAMENodeGroup for potential issues.
- Check the
-
NodeGroupHasStaticInternalNetworkCIDRsField
CE
S9
NodeGroup NAME uses deprecated field spec.static.internalNetworkCIDRs.
The
spec.static.internalNetworkCIDRsfield is deprecated and has been moved to the static cluster configuration.To resolve this issue, delete the field from NodeGroup NAME. This is safe, as the setting has already been migrated automatically.
-
NodeGroupMasterTaintIsAbsent
CE
S4
The master NodeGroup is missing the required control-plane taint.
The
masterNodeGroup doesn’t have thenode-role.kubernetes.io/control-plane: NoScheduletaint. This may indicate a misconfiguration where control-plane nodes can run non-control-plane Pods.To resolve the issue, add the following to the
masterNodeGroup spec:nodeTemplate: taints: - effect: NoSchedule key: node-role.kubernetes.io/control-planeNote that the taint
key: node-role.kubernetes.io/masteris deprecated and has no effect starting from Kubernetes 1.24. -
NodeGroupProviderTypeIsInvalid
CE
S4
The spec.providerType field is set incorrectly in NodeGroup NAME.
The
spec.providerTypefield of NodeGroupNAMEis set toXXX, which is not the cloud provider the nodes of the group run in.To resolve this issue, set the field to a correct value:
-
If the nodes of the group run in a cloud, set the field to the
typeof that cloud provider, as published in its registration secret:kubectl -n kube-system get secrets -l cloud-provider.deckhouse.io/registration -o json \ | jq -r '.items[] | .data.type | @base64d' -
If the cluster is static, or the NodeGroup has
nodeType: Static, set the field toNoneor leave it empty:kubectl patch nodegroup NAME --type=merge -p '{"spec":{"providerType":"None"}}'
-
-
NodeGroup NODE_GROUP_NAME has no available instances.
This probably means that
machine-controller-manageris unable to create Machines using the cloud provider module.Possible causes:
- Cloud provider resource limits.
- No access to the cloud provider API.
- Misconfiguration of the cloud provider or instance class.
- Problems with bootstrapping the Machine.
Recommended actions:
-
Check the status of the NodeGroup:
d8 k get ng NODE_GROUP_NAME -o yamlLook for errors in the
.status.lastMachineFailuresfield. -
If no Instances stay in the Pending state for more than a couple of minutes, it likely means that Instances are being continuously created and deleted due to an error:
d8 k get instances -
If logs don’t show errors, and an Instance continues to be Pending, check its bootstrap status:
d8 k get instances INSTANCE_NAME -o yaml | grep 'bootstrapStatus' -B0 -A2 -
If the output looks like the example below, use the
logsEndpoint(or the command indescription) to examine bootstrap logs:bootstrapStatus: description: Use 'curl -N http://192.168.199.158:8000' to get bootstrap logs. logsEndpoint: http://192.168.199.158:8000 -
If there’s no bootstrap log endpoint,
cloudInitmay not be working correctly. This could indicate a misconfigured instance class in the cloud provider.
-
Too many unavailable instances in the NODE_GROUP_NAME NodeGroup.
The number of simultaneously unavailable instances in the NODE_GROUP_NAME NodeGroup exceeds the allowed threshold. This may indicate that the autoscaler has provisioned too many nodes at once. Check the state of the Machine in the cluster. This probably means that
machine-controller-manageris unable to create Machines using the cloud provider module.Possible causes:
- Cloud provider resource limits.
- No access to the cloud provider API.
- Misconfiguration of the cloud provider or instance class.
- Problems with bootstrapping the Machine.
Recommended actions:
-
Check the status of the NodeGroup:
d8 k get ng NODE_GROUP_NAME -o yamlLook for errors in the
.status.lastMachineFailuresfield. -
If no Instances stay in the Pending state for more than a couple of minutes, it likely means that Instances are being continuously created and deleted due to an error:
d8 k get instances -
If logs don’t show errors, and an Instance continues to be Pending, check its bootstrap status:
d8 k get instances INSTANCE_NAME -o yaml | grep 'bootstrapStatus' -B0 -A2 -
If the output looks like the example below, use the
logsEndpoint(or the command indescription) to examine bootstrap logs:bootstrapStatus: description: Use 'curl -N http://192.168.199.158:8000' to get bootstrap logs. logsEndpoint: http://192.168.199.158:8000 -
If there’s no bootstrap log endpoint,
cloudInitmay not be working correctly. This could indicate a misconfigured instance class in the cloud provider.
-
NodeGroup NODE_GROUP_NAME has unavailable instances.
There are VALUE unavailable instances in the NodeGroup NODE_GROUP_NAME. This probably means that
machine-controller-manageris unable to create Machines using the cloud provider module.Possible causes:
- Cloud provider resource limits.
- No access to the cloud provider API.
- Misconfiguration of the cloud provider or instance class.
- Problems with bootstrapping the Machine.
Recommended actions:
-
Check the status of the NodeGroup:
d8 k get ng NODE_GROUP_NAME -o yamlLook for errors in the
.status.lastMachineFailuresfield. -
If no Instances stay in the Pending state for more than a couple of minutes, it likely means that Instances are being continuously created and deleted due to an error:
d8 k get instances -
If logs don’t show errors, and an Instance continues to be Pending, check its bootstrap status:
d8 k get instances INSTANCE_NAME -o yaml | grep 'bootstrapStatus' -B0 -A2 -
If the output looks like the example below, use the
logsEndpoint(or the command indescription) to examine bootstrap logs:bootstrapStatus: description: Use 'curl -N http://192.168.199.158:8000' to get bootstrap logs. logsEndpoint: http://192.168.199.158:8000 -
If there’s no bootstrap log endpoint,
cloudInitmay not be working correctly. This could indicate a misconfigured instance class in the cloud provider.
-
NodeGroupUsesDeprecatedInCoreGPU
CE
S9
NodeGroup NAME uses the deprecated built-in GPU support.
NodeGroup
NAMEhasspec.gpuconfigured while thegpumodule is disabled. As a result, GPU nodes in the NodeGroup use the built-in GPU support, which is deprecated and will be removed in a future DKP release.To use the supported GPU implementation, enable the
gpumodule. -
NodeRequiresDisruptionApprovalForUpdate
CE
S8
Node NODE_NAME requires disruption approval to proceed with the update.
Node
NODE_NAMEin NodeGroupNODE_GROUP_NAMEhas detected a new update, received initial approval, and started the update. However, it encountered a stage that may cause downtime and requires manual disruption approval, because the NodeGroup is configured withdisruptions.approvalMode: Manual.To resolve the issue, ensure the Node is ready for unsafe updates (drained) and grant disruption approval by annotating the Node with
update.node.deckhouse.io/disruption-approved=.Caution:
- Nodes in manual mode aren’t drained automatically.
- Do not drain master nodes.
-
To drain the Node and grant the update approval, run the following command:
d8 k drain NODE_NAME --delete-emptydir-data --ignore-daemonsets --force=true && d8 k annotate node NODE_NAME update.node.deckhouse.io/disruption-approved= -
Uncordon the Node once the update is complete and the annotation
update.node.deckhouse.io/approvedis removed:while d8 k get node NODE_NAME -o json | jq -e '.metadata.annotations | has("update.node.deckhouse.io/approved")' > /dev/null; do sleep 1; done d8 k uncordon NODE_NAME
If the NodeGroup has multiple Nodes, repeat this process for each one, since only one Node is updated at a time. Consider temporarily switching to automatic disruption approval (
disruptions.approvalMode: Automatic). -
NodeStuckInDraining
CE
S6
Node NODE_NAME keeps failing to drain.
Node
NODE_NAMEin NodeGroupNODE_GROUP_NAMEis stuck in the draining process.The Node has the error from the last attempt in the
update.node.deckhouse.io/drain-failedannotation, truncated to 1 KB. To read it, run:d8 k get node NODE_NAME -o json | jq -r '.metadata.annotations["update.node.deckhouse.io/drain-failed"]'The full error text is in the
DrainFailedevents on the Node:d8 k -n default get event --field-selector involvedObject.name=NODE_NAME,reason=DrainFailed --sort-by='.metadata.creationTimestamp'The drain is retried until it succeeds, so the alert clears on its own once the cause is gone. Until then the Node holds the update slot of its NodeGroup, and no other Node in that group is updated.
The usual causes are a PodDisruptionBudget that never allows an eviction and a pod that never terminates. Fix the cause named in the error above.
-
NodeStuckInDrainingForDisruptionDuringUpdate
CE
S6
Node NODE_NAME is stuck in draining.
Node
NODE_NAMEin NodeGroupNODE_GROUP_NAMEhas detected a new update, requested and received approval, started the update, and reached a step that could cause downtime. It is currently stuck in the draining process while waiting for automatic disruption approval.To get more details, run the following:
d8 k -n default get event --field-selector involvedObject.name=NODE_NAME,reason=ScaleDown --sort-by='.metadata.creationTimestamp' -
No available replicas in Deployment standby-holder-NODE_GROUP_NAME.
Deckhouse has detected that there are no available replicas in the
standby-holder-NODE_GROUP_NAMEDeployment in thed8-cloud-instance-managernamespace.Check the Deployment and associated Pods for issues.
-
UnmetCloudConditions
CE
S6
Deckhouse update is unavailable due to unmet cloud provider conditions.
Deckhouse has detected that some cloud provider–specific conditions have not been met. Until these issues are resolved, updating to the new Deckhouse release is not possible.
Troubleshooting details:
- Name: NAME
- Message: MESSAGE_CONTENTS
Модуль okmeter
-
D8OkmeterAgentPodIsNotReady
CE
S6
Okmeter agent is not Ready.
Модуль openvpn
-
OpenVPNClientCertificateExpired
CE
S4
OpenVPN client certificate expired for XXX
The OpenVPN client certificate for XXX has expired.
Check the certificate information and make sure it actually expires:
d8 k -n d8-openvpn get secrets -l name="XXX" -o jsonpath='{.items[0].data.tls\.crt}' | base64 -d | openssl x509 -text -nooutRenew or delete the expired certificate. Check the documentation for details.
-
OpenVPNClientCertificateExpired
CE
S5
OpenVPN client certificate expires for XXX in less than 7 days.
The OpenVPN client certificate for XXX is set to expire in VALUE days.
Renewal of certificate required. Check the documentation for details.
View certificate details to display the exact expiration date:
d8 k -n d8-openvpn get secrets -l name=XXX -o jsonpath='{.items[0].data.tls\.crt}' | base64 -d | openssl x509 -text -noout -
OpenVPNClientCertificateExpired
CE
S6
OpenVPN client certificate expires for XXX in less than 30 days.
The OpenVPN client certificate for XXX is set to expire in VALUE days.
Renewal of certificate required. Check the documentation for details.
View certificate details to display the exact expiration date:
d8 k -n d8-openvpn get secrets -l name=XXX -o jsonpath='{.items[0].data.tls\.crt}' | base64 -d | openssl x509 -text -noout -
OpenVPNServerCACertificateExpired
CE
S4
OpenVPN CA certificate has expired.
OpenVPN CA certificate renews automatically 1 days before expiration. Automatic rotation did not work. Check the module status or perform manual rotation.
View certificate details to display the exact expiration date:
d8 k -n d8-openvpn get secrets openvpn-pki-ca -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -text -nooutThe hook should rotate CA and server certificates before expiry.
-
OpenVPNServerCACertificateExpiresTomorrow
CE
S4
OpenVPN CA certificate will expire tomorrow
OpenVPN CA certificate renews automatically 1 days before expiration. Automatic rotation did not work. Check the module status or perform manual rotation.
View certificate details to display the exact expiration date:
d8 k -n d8-openvpn get secrets openvpn-pki-ca -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -text -nooutThe hook should rotate CA and server certificates before expiry.
-
OpenVPNServerCACertificateExpiringInAWeek
CE
S5
OpenVPN CA certificate expires in less than 7 days.
The OpenVPN CA certificate is set to expire in VALUE days.
Renew the CA certificate if necessary. After renewing the certificate, you will need to reissue all client and server certificates. Check the documentation for details.
View certificate details to display the exact expiration date:
d8 k -n d8-openvpn get secrets -l name=server -o jsonpath='{.items[0].data.tls\.crt}' | base64 -d | openssl x509 -text -noout -
OpenVPNServerCACertificateExpiringSoon
CE
S5
OpenVPN CA certificate expires in less than 30 days.
The OpenVPN CA certificate is set to expire in VALUE days.
Renew the CA certificate if necessary. After renewing the certificate, you will need to reissue all client and server certificates. Check the documentation for details.
View certificate details to display the exact expiration date:
d8 k -n d8-openvpn get secrets -l name=server -o jsonpath='{.items[0].data.tls\.crt}' | base64 -d | openssl x509 -text -noout -
OpenVPNServerCertificateExpired
CE
S4
OpenVPN server certificate has expired.
The OpenVPN server certificate has expired.
OpenVPN server certificate renews automatically 1 days before expiration. Automatic rotation did not work. Check the module status or perform manual rotation.
Check the certificate information and make sure it actually expires.
d8 k -n d8-openvpn get secrets -l name=server -o jsonpath='{.items[0].data.tls\.crt}' | base64 -d | openssl x509 -text -noout -
OpenVPNServerCertificateExpiresTomorrow
CE
S4
OpenVPN server certificate will expire tomorrow.
The OpenVPN server certificate is set to expire in less than 1 day.
OpenVPN server certificate renews automatically 1 days before expiration. Automatic rotation did not work. Check the module status or perform manual rotation.
Check the certificate information and make sure it actually expires:
d8 k -n d8-openvpn get secrets -l name=server -o jsonpath='{.items[0].data.tls\.crt}' | base64 -d | openssl x509 -text -noout
Модуль registry
-
D8RegistryAirGapTransitionHeld
CE
S5
The registry upstream cannot be removed yet.
The configuration has no upstream, so the cluster is meant to be air-gapped, and the module is still holding the previous upstream: either the cache is not complete enough to stand alone, or workloads in the platform namespaces (
kube-systemandd8-*) still reference the upstream and would have nowhere to pull from without it. Workloads in other namespaces are not counted and do not hold the transition.This is the safe outcome and the cluster is pulling images normally. It is also the one transition in this module that could cut every node off from images, which is why it waits rather than proceeds — and why a wait this long is worth looking at: nothing about it resolves on its own if the cache has stopped filling, or if a rollout onto the in-cluster address is stuck.
Check the cache and the current count of references to the upstream (
upstreamReferences):d8 k get registrystorage registry -o jsonpath='{.status}' | jq '{phase,fill,safeToDropUpstream,upstreamReferences,leader}' d8 k get registryconfig registry -o jsonpath='{.status.effectiveUpstream}' | jqThe
registry-controllerlog names up to five of the referencing objects each time the count changes. To see the last such line:d8 k -n d8-system logs -l app=registry-controller -c registry-controller --prefix --tail=-1 | grep 'still names the upstream' | tail -1 -
D8RegistryConfigInvalid
CE
S4
The registry configuration was rejected.
The
registrymodule cannot use its configuration, so the cluster keeps whatever arrangement it already had. Nothing has broken yet; nothing new will take effect either.What was wrong is in the resource:
d8 k get registryconfig registry -o jsonpath='{.status.conditions}' | jq -
D8RegistryDrainStuck
CE
S6
The registry module cannot finish leaving the pull path.
The
registryModuleConfig asks forUnmanaged, and the module is still running its components and still servingregistry.d8-system.svc:5001. That is deliberate: workloads in the cluster still name that address, and taking it away before they move would leave them unable to pull. It has been waiting for half an hour, which is longer than it should take.Nothing is degraded while this alert is firing. The cluster pulls, the module serves, and the only thing not happening is the withdrawal.
What to look at:
-
What still names the address. The module logs the first few on every pass, and the count is a metric:
d8 k -n d8-system logs deploy/deckhouse -c deckhouse | grep "still serving the in-cluster registry" -
Then the workloads themselves, which is where the answer usually is:
d8 k get pods,deployments,daemonsets,statefulsets -A -o json \ | jq -r '.items[] | select([.spec.template.spec.containers[]?.image, .spec.containers[]?.image] | any(startswith("registry.d8-system.svc:5001"))) | "\(.kind) \(.metadata.namespace)/\(.metadata.name)"'
A third cause is a cluster with nowhere to go, and it is the one to check first on a cluster that was air-gapped or installed with no upstream. Leaving the pull path means pointing the cluster back at the registry the module was fetching from, and a module serving purely from its own store has no such registry to name. It says so in the log:
d8 k -n d8-system logs deploy/deckhouse -c deckhouse | grep "no upstream to point the cluster back at"Give the cluster a registry to pull from, or ask for
Managedagain. Nothing is degraded while it waits, and the withdrawal will not complete until one of the two happens.Otherwise two causes account for it. Either a release is not being re-rendered — check that the operator queue is not stuck, since the references move only as each module’s release is rendered again:
d8 k -n d8-system exec deploy/deckhouse -c deckhouse -- deckhouse-controller queue mainOr something outside the platform’s own renders names the address: a workload of yours that hardcoded it, or a manually edited manifest. Those will never move on their own, and until they are changed to pull from the registry the cluster was installed with, the module will keep serving them — which is the intended behaviour, not a failure.
One shape of this is worth naming, because it was hit the first time this ran on a live cluster: a rolling update stuck for reasons of its own. The new pod is already on the upstream registry and never becomes ready, so the superseded ReplicaSet keeps its old pod, and that pod names the in-cluster address. A pod that has already pulled is not waited on, so this alone does not hold the withdrawal — but a pod stuck BEFORE its containers start does, and rightly, since it is exactly what would fail. Fix the rollout, or delete the pod that cannot start:
d8 k get pods -A --field-selector status.phase=PendingA drain can also be abandoned by asking for
Managedagain: the module then keeps the pull path it never finished giving up, and this alert goes away. -
-
D8RegistryMigrationPending
CE
S8
The registry module is still running its previous implementation.
This cluster still pulls images the way the previous implementation of the
registrymodule arranged it, and the handover to the current one has not happened.Reason:
XXXRead the reason first, because it separates two very different situations:
-
The reason says the previous implementation has not recorded a mode yet, or that it is transitioning. Nothing is wrong: the handover is waiting for a state to settle and will happen on its own.
-
The reason names a mode other than
Unmanaged—Direct,ProxyorLocal. Then this cluster’s pull path is already degraded, and this alert is how it shows: this release renders none of the previous implementation’s objects, so the in-cluster proxy, theregistryService and the per-node secrets it served are gone, while the nodes still point at them. Images already on a node keep working; anything that has to be pulled will not. Do not wait for this to resolve itself — it will not. Go toD8RegistryMigrationPreflightBlocked, which says what to do per case, and forLocalnote that the documented procedure does not apply at all.
The handover waits because both implementations configure the same thing on every node: which registry the container runtime asks, and with which credentials. Running both would not merge those two answers, it would race them. So the current implementation takes over only once the previous one has let go of the pull path, which is its
Unmanagedstate.What to do:
-
Bring the registry configuration in the
deckhouseModuleConfig toUnmanagedand wait for that transition to finish:d8 k get mc deckhouse -o jsonpath='{.spec.settings.registry.mode}' d8 k -n d8-system get secret registry-state -o jsonpath='{.data.state}' | base64 -d | head -
Once the state reports
mode: Unmanagedwith no pending target mode, the handover happens on the module’s next reconciliation and this alert clears. The cluster keeps pulling from the same registry throughout. -
To have the module manage the pull path afterwards, set
mode: Managedin theregistryModuleConfig together with the registry to pull from. The module publishes a ready-made configuration for this cluster in theregistry-suggested-configsecret ind8-system.
-
-
D8RegistryMigrationPreflightBlocked
CE
S6
The registry migration must not be started on this cluster yet.
A precondition of the
registrymodule’s migration is not met, and the migration must not be started until it is:XXX— XXX.Whether anything is broken right now depends on which check it is, and the list below says so per case:
upstream_reachableandnode_containerd_registry_configare work to do before starting, whilemodeandnot_localmean the cluster is already past the point where the documented procedure could be started cleanly.What each blocking check means:
-
mode— the cluster arrived on this release without having been brought toUnmanagedfirst, or the previous implementation is mid-transition. This release renders none of the previous implementation’s objects, so whatever they served — the in-cluster proxy inProxy, theregistryService — is already gone, and the nodes still point at it. The discriminator has NOT flipped while this is failing, so the way back is the image: return the previous release, bring the cluster toUnmanagedby the documented procedure, then upgrade again. -
not_local— the cluster’s registry is the cluster (Local). The ordinary procedure brings the cluster throughUnmanaged, where every node pulls straight from an upstream, and this cluster has no upstream to pull from: the previous implementation does not even write node configuration inUnmanagedwithout one. This cluster has a procedure of its own instead — an OCI registry stood up in a namespace of your own, loaded with the image set and declared as the upstream for the length of the migration, then removed once the in-cluster storage holds the set itself. The blobs already on the control-plane nodes are adopted rather than downloaded again; what it costs is a second copy of the set on disk while the temporary registry exists. See “How do I migrate an air-gapped Local cluster?” in the module’s FAQ, and do not start the ordinary procedure here. -
node_containerd_registry_config— one or more nodes carry a containerdconf.dfile that sets registry fields of its own. Under the current implementation that file is not merged: the node’s registry configuration comes from/etc/containerd/registry.d, and the bashible step refuses to merge a file that would contradict it — by failing, which stops that node’s whole convergence, including kubelet configuration and version upgrades. The detail names the nodes. Move those settings into/etc/containerd/registry.dbefore the handover. -
upstream_reachable— the registry this cluster pulls from does not answer. The procedure points every node straight at it, so starting now turns a documented step into an outage. Fix the reachability first:d8 k -n d8-system get secret registry-state -o jsonpath='{.data.state}' | base64 -d | head d8 k -n d8-system logs deploy/deckhouse -c deckhouse | grep -i 'registry checker'
The non-blocking checks are reported by the same metric with
blocking="false":d8_registry_migration_preflight -
-
D8RegistryNodeForeignRegistryConfig
CE
S5
Node NODE_NAME carries container runtime registry configuration the registry module did not write.
Node
NODE_NAMEhas a file under/etc/containerd/conf.d/(containerd v1) or/etc/containerd/conf2.d/(containerd v2) that configures a registry, and theregistrymodule manages this cluster’s registry configuration. Two writers of that configuration is not a state the platform supports, so bashible refuses to merge such a file.Right now nothing is broken, and that is the danger. The refusal happens inside the bashible step that builds the container runtime configuration, and that step only runs when something makes it run. Until then the file has no effect at all: bashible compares the node’s configuration checksum, finds it unchanged and reports “Configuration is in sync, nothing to do”.
The step does run on its own, though: a node re-applies its whole configuration periodically (roughly every four hours), and also on any registry change, platform upgrade or reboot. At that point the step fails with
Failed to merge /etc/containerd/conf.d/file: it contains custom registry fields, configure them in /etc/containerd/registry.d insteadand retries, so the node stops applying configuration entirely — hours after the change that caused it, and with nothing else to connect the two.
What to do, before that happens:
-
Find the file on the node:
ls /etc/containerd/conf.d/ /etc/containerd/conf2.d/ 2>/dev/null grep -l registry /etc/containerd/conf.d/*.toml /etc/containerd/conf2.d/*.toml 2>/dev/null -
Move the registry part of it to a host directory, which is where this platform configures registries and where the module’s node agent leaves other people’s entries alone:
/etc/containerd/registry.d/registry host/hosts.toml -
Remove the registry section from the
conf.dfile (anything non-registry in it can stay), and remove theNodeGroupConfigurationthat writes it if that is where it comes from.
Doing it across a fleet with a
NodeGroupConfigurationhas one catch worth knowing in advance: give it a weight below 32. The step that refuses the file is032_configure_containerd, and a node stops at the step that fails — so a repair placed at a later weight never runs on the nodes that need it most. Measured: a cleanup configuration at weight 10 reached both nodes and cleared the label in 90 seconds.A node already stuck in the retry loop recovers on its own once the file is gone: measured, the configuration checksum returned in 75 seconds.
-
-
D8RegistryNodeNotConverged
CE
S5
Some nodes have not applied their registry configuration.
The agent on one or more nodes has not applied the layout it was given. Those nodes keep pulling images the way they were configured before, so this is not an outage — but a change made to the registry configuration has not reached them, and the next one will not either.
Which nodes, and what their agents say:
d8 k get registrynodes -o custom-columns=\ NODE:.metadata.name,GEN:.metadata.generation,APPLIED:.status.observedGeneration,OK:.status.reconciled d8 k -n kube-system logs -l component=registry-agent --tail=50Twenty minutes, because the agent re-reads its layout on a timer and a node that is merely slow or briefly unreachable resolves this on its own.
-
D8RegistryNodeRunningFromDisk
CE
S6
Some nodes are routing pulls from their on-disk copy of the configuration.
The agent on one or more nodes cannot reach the API server and is routing pulls from the copy it keeps on disk. That is the copy working as designed — those nodes pull images normally, which is exactly why this is worth saying out loud: from every other angle it looks like success, and their configuration can drift arbitrarily far behind the cluster’s.
An hour, because a node that briefly loses the API server is not news; a node that has not seen it since is.
d8 k get registrynodes -o json | jq -r ' .items[] | select(.status.conditions[]? | select(.type=="Reconciled" and .reason=="AppliedFromCache")) | .metadata.name' -
D8RegistryStaleCacheData
CE
S8
A node still holds registry cache data that nothing uses.
Node
NODE_NAMEholds data of the in-cluster registry cache while no cache is configured. Nothing reads it, and nothing will unless the cache is turned back on.It is kept on purpose. Turning the cache back on refills from what is already there rather than from scratch, and over a slow link that difference is hours — so the module does not delete it, because that would make the decision irreversible in the one direction that hurts. What it will not do is keep it quietly, which is what this alert is.
Nothing is wrong and nothing needs doing urgently. To reclaim the space, remove the directory the store kept its blobs in:
/var/lib/deckhouse/registryon a node of a NodeGroup withsystemType: Immutable,/opt/deckhouse/registryon other nodes. With the cache off there is no RegistryStorage left to ask, so the command below looks at both.Open a root shell on the node over SSH. A node of a NodeGroup with
systemType: Immutablehas no SSH: start a debug pod on it and switch to the node’s root filesystem:d8 k debug node/NODE_NAME -it --image=ubuntu chroot /hostThen remove the data:
for dir in /opt/deckhouse/registry /var/lib/deckhouse/registry; do [ -d "$dir" ] && du -sh "$dir" && rm -rf "$dir" doneTwenty-four hours, so that turning the cache off and on again in one working session never raises it.
-
D8RegistryStorageIncomplete
CE
S6
Some registry cache replicas do not hold the whole image set.
One or more replicas of the in-cluster cache are still filling, or have stopped short. While an upstream is configured this costs nothing at pull time — a node falls back to it — but it does mean the cluster could not survive losing that upstream, and it is what holds an air-gap transition back.
Two hours, because filling a cache over a slow link legitimately takes that long.
d8 k get registrystorage registry -o jsonpath='{.status.replicas}' | jq -
D8RegistryStorageNotReclaimed
CE
S6
The registry cache has not reclaimed its disk for a week.
No replica of the in-cluster cache has finished a garbage collection in the last week. Nothing is broken yet: the cache serves images normally, and it will keep doing so until the disk fills.
It is worth attention because the collection is the only thing that ever removes anything. Every release adds a slice of the repository, so a store nobody reclaims grows in one direction — and a full store cannot be written to, which in an air-gapped cluster means it cannot be updated.
Where to look:
d8 k get registrystorage registry -o jsonpath='{.status.replicas}' | jq \ 'map({node, collectedAt, collectionError})' d8 k get registrystorage registry -o jsonpath='{.spec.garbageCollection}' | jqThe likely reasons, in the order they are worth checking:
- the collection is turned off in the
registryModuleConfig understorage.garbageCollection.enabled; - the schedule has not come round yet, or names an hour that never arrives — a collection only runs on the schedule, and an unreadable expression is refused rather than guessed at;
- no release is deployed, which is the one input that justifies deleting anything: every deletion is “older than what the cluster runs”, and without that there is nothing to compare against;
collectionErroron a replica, which says what its own last attempt hit.
One reading tells the first two apart from the rest. Each replica logs the time of its next collection, so its absence means none was ever scheduled — a different problem from one that is scheduled and failing:
d8 k -n d8-system logs registry-storage-0 -c syncer | grep -i "garbage collection"Collecting puts one replica read-only while it runs. That is not an outage — it keeps serving every image it holds — but it does mean the schedule belongs at a quiet hour, which is where it defaults to.
- the collection is turned off in the
-
D8RegistryStoreNearlyFull
CE
S6
The registry cache on node NODE_NAME holds over 85% of storage.size.
The in-cluster registry cache on node
NODE_NAMEholds more than 85% of its budget,storage.sizein theregistryModuleConfig. Nothing is refused yet. The next release may not fit: once the budget is reached, the cache stops accepting writes andD8RegistryStoreWritesRefusedfollows.d8 k get registrystorage registry -o json | jq '.status.replicas[] | {node, store}'Raise
storage.sizeif the disk under the store has room —filesystemFreeBytesabovereserveBytesis what is left — or check that the garbage collection runs: it is the only thing that reclaims space, andD8RegistryStorageNotReclaimedsays when it has not. -
D8RegistryStoreUnbounded
CE
S7
The registry cache has no storage.size, so only the node's disk limits it.
The in-cluster registry cache is on, and
storage.sizeis not set in theregistryModuleConfig. The node is still protected: the store never takes the space kept free for the kubelet. But that is the only limit, so the store may grow until it leaves the node exactly that and no more — and on a master that shares its disk with the store, everything else on it then works with the minimum.Set
storage.sizeto what the store may take on each master: two releases of the image set is the usual floor, and it has to fit on the disk under the store, above the reserve:d8 k get registrystorage registry -o json | jq '.status.replicas[] | {node, store}'An hour, so that turning the cache on and setting the size in two steps does not raise it.
-
D8RegistryStoreWritesRefused
CE
S4
The registry cache on node NODE_NAME refuses writes (XXX).
The in-cluster registry cache on node
NODE_NAMEhas stopped accepting writes, becauseXXX. The node is safe — this is the limit doing its job — and the cache keeps serving every image it holds. What stops is everything that ADDS to it: filling the next release, replicating from the leader,d8 mirror push. Images the store cannot keep are streamed from the upstream while there is one; in an air-gapped cluster a release that is not in the cache cannot be installed.What the replica measured:
d8 k get registrystorage registry -o json | jq '.status.replicas[] | {node, store}'BudgetExhausted— the store holds as much asstorage.sizeallows. Either raisestorage.sizein theregistryModuleConfig, if the disk has room for it, or let the garbage collection reclaim what no deployed release needs any more: it runs onstorage.garbageCollection.scheduleand keeps the deployed release, the previous one and everything newer.ReserveExhausted— the filesystem under the store is down to the space kept free for the node: the kubelet’s eviction threshold plus a margin.storage.sizeis not what stops it, the disk is. Free space on the node, or — which is what fixes it for good — give the store a disk of its own, sized forstorage.size. -
D8RegistryUpstreamProbeFailing
CE
S4
The configured registry upstream does not pass its preflight check.
A change to the primary upstream was refused, and the cluster is still using the last one that worked. Nothing is degraded — that is what holding the previous upstream is for — but the change has not taken effect and will not until the check passes.
The
outcomelabel says which of three things is wrong, and they are not the same problem:unreachable— the registry did not answer at all: network, firewall, or the registry itself.auth— it answered and rejected the credentials. Usually an expired or wrong license key.sentinel— it answered and accepted the credentials, but does not hold the Deckhouse images. Usually the wrong repository path.
Current outcome:
XXXd8 k get registryconfig registry -o jsonpath='{.status.conditions}' | jq -
D8RegistryUpstreamRejected
CE
S6
An additional registry was refused.
A
RegistryUpstreamresource was not accepted, so pulls for the registry it names are not intercepted on any node. Whatever asked for it — a module, or an operator — is not getting it.Reason:
XXXd8 k get registryupstreams -o custom-columns=\ NAME:.metadata.name,MATCH:.spec.match,ACCEPTED:.status.conditions[0].status,REASON:.status.conditions[0].reason
Модуль secret-copier
-
D8SecretCopierDeprecatedLabels
CE
S9
Obsolete antiopa_secret_copier=yes label detected.
The
secret-copiermodule has changed its labeling approach for original secrets in thedefaultnamespace.The label
antiopa-secret-copier: "yes"is deprecated and will be removed soon.To resolve this issue, replace the label
antiopa-secret-copier: "yes"withsecret-copier.deckhouse.io/enabled: ""for all secrets used by thesecret-copiermodule in thedefaultnamespace.
Модуль terraform-manager
-
D8TerraformStateExporterClusterStateChanged
CE
S8
Terraform-state-exporter cluster state change detected.
The current Kubernetes cluster state is
STATUS_REFERENCEcompared to the Terraform state.It is important to reconcile the states.
Troubleshooting steps:
-
View the differences:
dhctl terraform check -
Apply the necessary changes to bring the cluster in sync:
dhctl converge
-
-
D8TerraformStateExporterClusterStateError
CE
S8
Terraform-state-exporter cluster state error.
The
terraform-state-exportercan’t check difference between the Kubernetes cluster state and the Terraform state.That was likely caused by
terraform-state-exporterfailing to run Terraform with the current state and configuration.Troubleshooting steps:
-
View the differences:
dhctl terraform check -
Apply the necessary changes to bring the cluster in sync:
dhctl converge
-
-
D8TerraformStateExporterHasErrors
CE
S8
Terraform-state-exporter has encountered errors.
Errors occurred during the operation of the
terraform-state-exporter.To get more details, check the Pod logs:
d8 k -n d8-system logs -l app=terraform-state-exporter -c exporter -
D8TerraformStateExporterNodeStateChanged
CE
S8
Terraform-state-exporter node state change detected.
The current state of node
NODE_GROUP_NAME/NAMEisSTATUS_REFERENCEcompared to the Terraform state.It is important to reconcile the states.
Troubleshooting steps:
-
View the differences:
dhctl terraform check -
Apply the necessary changes to bring the cluster in sync:
dhctl converge
-
-
D8TerraformStateExporterNodeStateError
CE
S8
Terraform-state-exporter node state error.
The
terraform-state-exportercan’t check the difference between the nodeNODE_GROUP_NAME/NAMEstate and the Terraform state.Probably, it occurred because
terraform-managerhad failed to run Terraform with the current state and configuration.Troubleshooting steps:
-
View the differences:
dhctl terraform check -
Apply the necessary changes to bring the cluster in sync:
dhctl converge
-
-
D8TerraformStateExporterNodeTemplateChanged
CE
S8
Terraform-state-exporter node template change detected.
The
terraform-state-exporterhas detected a mismatch between the node template in the cluster provider configuration and the one specified in the NodeGroup NAME`.Node template is
STATUS_REFERENCE.Troubleshooting steps:
-
View the differences:
dhctl terraform check -
Adjust NodeGroup settings to fix the issue or bring the cluster in sync via the following command:
dhctl converge
-
-
D8TerraformStateExporterPodIsNotReady
CE
S8
Terraform-state-exporter Pod is not Ready.
The
terraform-state-exportercannot check the difference between the actual Kubernetes cluster state and the Terraform state.To resolve the issue, check the following:
-
Deployment description:
d8 k -n d8-system describe deployment terraform-state-exporter -
Pod status:
d8 k -n d8-system describe pod -l app=terraform-state-exporter
-
-
D8TerraformStateExporterPodIsNotRunning
CE
S8
Terraform-state-exporter Pod is not Running.
The
terraform-state-exportercannot check the difference between the actual Kubernetes cluster state and the Terraform state.To resolve the issue, check the following:
-
Deployment description:
d8 k -n d8-system describe deployment terraform-state-exporter -
Pod status:
d8 k -n d8-system describe pod -l app=terraform-state-exporter
-
-
D8TerraformStateExporterTargetAbsent
CE
S8
Terraform-state-exporter target is missing in Prometheus.
Prometheus cannot find the
terraform-state-exportertarget.To investigate the details:
-
Check the Pod status:
d8 k -n d8-system get pod -l app=terraform-state-exporter -
Check the container logs:
d8 k -n d8-system logs -l app=terraform-state-exporter -c exporter
-
-
D8TerraformStateExporterTargetDown
CE
S8
Prometheus can't scrape terraform-state-exporter.
Prometheus is unable to scrape metrics from the
terraform-state-exporter.To investigate the details:
-
Check the Pod status:
d8 k -n d8-system get pod -l app=terraform-state-exporter -
Check the container logs:
d8 k -n d8-system logs -l app=terraform-state-exporter -c exporter
-
Модуль user-authn
-
D8DexAllTargetsDown
CE
S6
Prometheus is unable to scrape Dex metrics.
Prometheus cannot scrape any Dex pod in the
d8-user-authnnamespace. Users may be unable to sign in.Check the Dex pods and their logs:
d8 k -n d8-user-authn get pods -l app=dex d8 k -n d8-user-authn logs deploy/dex -
D8DexAuthenticatorNamespaceUnusable
CE
S7
DexAuthenticator NAMESPACE/NAME is left out of the release because its namespace accepts no objects.
The
NAMESPACEnamespace is terminating, so the API server refuses every create in it. Theuser-authnmodule leaves the DexAuthenticatorNAMEout of its release: with it, the release would fail on the objects it cannot create and the Deckhouse main queue would stop behind the retrying module.A namespace does not finish terminating while something in it holds a finalizer, and the authenticator is usually that something. Check what keeps the namespace:
d8 k get namespace NAMESPACE -o jsonpath='{.status.conditions}' d8 k -n NAMESPACE get dexauthenticator NAME -o jsonpath='{.metadata.finalizers}'Let the deletion finish: remove the finalizer that holds the authenticator, or delete the object that owns it. The authenticator is deleted with its namespace; to keep it, recreate it in a live namespace. The alert resolves once the authenticator is gone.
-
D8DexAuthRequestsQuotaExhausted
CE
S3
Dex AuthRequest objects ResourceQuota is exhausted in namespace "d8-user-authn".
The ResourceQuota for
authrequests.dex.coreos.comobjects in namespaced8-user-authnhas been fully exhausted.Dex is currently unable to create new AuthRequest custom resources, which will cause:
- Dex health checks to fail immediately.
- Authentication through external identity providers to stop working.
- Users unable to log in via OAuth/OIDC flows.
Immediate actions required:
- Check current AuthRequest objects and clean up stale ones:
d8 k get authrequests.dex.coreos.com -n d8-user-authn --no-headers | wc -l d8 k delete authrequests.dex.coreos.com --all -n d8-user-authnDeleting AuthRequest objects interrupts sign-ins that are in progress.
- Temporarily increase the ResourceQuota limit:
d8 k patch resourcequota authrequest-quota -n d8-user-authn --type='json' -p='[{"op": "replace", "path": "/spec/hard/count\/authrequests.dex.coreos.com", "value": "20000"}]'The module restores the quota on its next run.
-
Investigate why Dex is not cleaning up AuthRequest objects automatically.
- AuthRequest objects expire after 10 minutes. A growing count usually means that a client or a bot repeatedly starts sign-ins. Find the source in the Dex logs.
-
D8DexAuthRequestsQuotaHigh
CE
S4
Dex AuthRequest objects quota usage is higher than 80% in namespace "d8-user-authn".
The ResourceQuota for
authrequests.dex.coreos.comobjects in namespaced8-user-authnis approaching its limit.Current usage: XXX%
When the quota is exhausted, Dex will be unable to create new AuthRequest custom resources, which may cause:
- Dex health checks to fail.
- Authentication through external identity providers (GitLab, GitHub, etc.) to stop working.
Investigation steps:
- Check for stale AuthRequest objects that Dex should have cleaned up:
d8 k get authrequests.dex.coreos.com -n d8-user-authn -
AuthRequest objects expire after 10 minutes. A growing count usually means that a client or a bot repeatedly starts sign-ins. Find the source in the Dex logs.
- Consider temporarily increasing the ResourceQuota limit if needed. The module restores the quota on its next run.
-
D8DexProviderLDAPTLSConflict
CE
S8
DexProvider NAME has a conflicting LDAP TLS configuration.
DexProvider
NAMEcombines mutually exclusive LDAP TLS settings:XXX. Dex silently ignores the redundant flag, which masks misconfiguration:insecureNoSSL + startTLS: TLS is disabled (ldap://, port 389), sostartTLSis ignored.insecureNoSSL + insecureSkipVerify: TLS is disabled, there is no certificate to verify.insecureNoSSL + rootCAData: TLS is disabled, the CA chain is ignored.
The CRD schema rejects this combination on create/update; this DexProvider was created before the validation was added and remains active.
Update the DexProvider to remove the conflict:
- Plaintext LDAP (port 389): keep
spec.ldap.insecureNoSSL: true, removestartTLS,insecureSkipVerify, androotCAData. - STARTTLS on port 389: set
spec.ldap.insecureNoSSL: false,spec.ldap.startTLS: true. UseinsecureSkipVerifyorrootCADataas needed. ldaps://on port 636: leaveinsecureNoSSLandstartTLSatfalse. UseinsecureSkipVerifyorrootCADataas appropriate.
Audit all LDAP DexProvider objects:
d8 k get dexproviders.deckhouse.io -o yaml | yq '.items[] | select(.spec.type=="LDAP") | {name: .metadata.name, ldap: .spec.ldap | pick(["insecureNoSSL","startTLS","insecureSkipVerify","rootCAData"])}' -
D8UserAuthnControllerReconcileErrorsHigh
CE
S8
JOB_NAME reconcile errors are high for CONTROLLER_NAME.
Controller
CONTROLLER_NAMEofJOB_NAMEhas a reconcile error rate above 0.1 errors per second for more than 10 minutes.Check logs:
d8 k -n d8-user-authn logs deploy/JOB_NAME --all-pods=true -
D8UserAuthnControllerTargetDown
CE
S6
Prometheus is unable to scrape user-authn-controller.
Prometheus cannot scrape metrics from
user-authn-controllerin namespaced8-user-authn.The controller is down, not Ready (informer cache has not synced), or the PodMonitor is missing. Static user login, UserAccount, expire, and provider checks will not run.
Check:
d8 k -n d8-user-authn get pods -l app=user-authn-controller d8 k -n d8-user-authn describe pods -l app=user-authn-controller -
user-authn-controller has unavailable replicas.
Deckhouse has detected unavailable replicas in the
user-authn-controllerdeployment in thed8-user-authnnamespace.While this alert is active, static Users may not get Dex Password objects, UserAccount projections stall, expired Users are not deleted, and DexProviderCheck / UserOperation stay pending.
Check deployment and pod states:
d8 k -n d8-user-authn get deploy user-authn-controller d8 k -n d8-user-authn get pods -l app=user-authn-controller d8 k -n d8-user-authn logs deploy/user-authn-controller --all-pods=true -
D8UserAuthnDexClientControllerTargetDown
CE
S6
Prometheus is unable to scrape dexclient-controller.
Prometheus cannot scrape metrics from
dexclient-controllerin namespaced8-user-authn.The controller is down, not Ready (informer cache has not synced), or the PodMonitor is missing. The credentials of DexClients are not kept up to date.
Check:
d8 k -n d8-user-authn get pods -l app=dexclient-controller d8 k -n d8-user-authn describe pods -l app=dexclient-controller -
dexclient-controller has unavailable replicas.
Deckhouse has detected unavailable replicas in the
dexclient-controllerdeployment in thed8-user-authnnamespace.While this alert is active, a new DexClient gets no credentials Secret and no Dex client, and changes of DexClients are not applied.
Check deployment and pod states:
d8 k -n d8-user-authn get deploy dexclient-controller d8 k -n d8-user-authn get pods -l app=dexclient-controller d8 k -n d8-user-authn logs deploy/dexclient-controller --all-pods=true -
D8UserAuthnIdentityMigrationIncomplete
CE
S6
Dex user data is not fully copied into UserIdentity objects.
For more than 30 minutes,
user-authn-controllerhas not finished copying the 2FA (TOTP) secret and the lock of Dex users from OfflineSessions and Password objects into UserIdentity objects.Until the copy of a provider and user pair completes, its 2FA secret and lock are stored only in the OfflineSessions and Password objects.
The controller retries failed pairs by itself. Find the reason in its logs:
d8 k -n d8-user-authn logs deploy/user-authn-controller --all-pods=true | grep -E 'identitymigration|UserIdentity'Typical reasons are API server errors and missing rights on
useridentities.dex.coreos.com. Pairs that cannot be copied at all, for example an OfflineSessions object that cannot be decoded, are logged asNot copying the pair into UserIdentityand do not raise this alert. -
D8UserAuthnIDTokenTTLTooLong
CE
S6
user-authn idTokenTTL is XXX, which is too long.
The ModuleConfig
user-authnsetsidTokenTTL: XXX.Dex rotates the key that signs ID tokens every 6 hours (
signer.config.keysRotationPeriod: 6h) and keeps a previous key only while tokens signed with it can still be valid.idTokenTTLmaps to Dexexpiry.idTokens. If that lifetime is greater than or equal to the signing-key rotation period (6h), every rotation must retain an extra previous key until all tokens from that key expire. Over time the set of retained signing keys grows without bound and Dex persists that growing key material.That is why
idTokenTTLmust be strictly less than6h. Lower it, for example:apiVersion: deckhouse.io/v1alpha1 kind: ModuleConfig metadata: name: user-authn spec: version: 3 settings: idTokenTTL: 1hSettings version 3 rejects
idTokenTTL >= 6h. A ModuleConfig of an earlier settings version with such a value is still accepted and its value is converted to5h59m, so Dex already runs with5h59m; this alert keeps firing until the ModuleConfig itself is updated. -
D8UserAuthnRevocationFeedLagging
CE
S6
The revocation feed of user-authn-controller is not delivering to dex-authenticator.
For more than 5 minutes, a stream of the revocation feed of
user-authn-controllerhas not written to its dex-authenticator for over 30 seconds. A stream writes at least a heartbeat every 10 seconds, so the stream is stuck.While the stream is stuck, a session that is revoked (user lock, password reset, logout) keeps working in that dex-authenticator until its next refresh in Dex: up to 30 seconds while Dex is reachable, and no longer than
idTokenTTLotherwise.Check the logs of the controller and of the dex-authenticator pods:
d8 k -n d8-user-authn logs deploy/user-authn-controller --all-pods=true | grep revocation-feedThe controller closes a stream that falls behind, and the dex-authenticator reconnects by itself. A lag that does not go away usually means a network problem between the dex-authenticator pods and the controller pods.
-
D8UserAuthnRevocationFeedNotConsumed
CE
S6
The dex-authenticator of the Dex client XXX does not receive the revocation feed.
For more than 15 minutes, no replica of
user-authn-controllerhas had a stream of the revocation feed open for the Dex clientXXX. The client belongs to a DexAuthenticator (the client ID isdex-authenticator-name@namespace).The dex-authenticator of this client works without the feed: a session revoked by a user lock, a password reset, or a logout stops working there only at its next refresh in Dex, within 30 seconds while Dex is reachable, and no later than
idTokenTTL.What to check:
- the logs of the dex-authenticator pods: errors connecting to
https://revocation-feed.d8-user-authn/revocationsand answers 401 or 429; - that the Secret of the DexAuthenticator holds the CA of the feed in the
revocation-feed-ca.crtkey; - network policies in the namespace of the DexAuthenticator: they must allow connections to the
user-authn-controllerpods ind8-user-authnon port 8443.
d8 k -n d8-user-authn get endpoints revocation-feed d8 k -n d8-user-authn logs deploy/user-authn-controller --all-pods=true | grep revocation-feed - the logs of the dex-authenticator pods: errors connecting to
Модуль user-authz
-
The bindings of XXX XXXXXX/XXXNAME cannot be applied (XXX).
user-authz-controllercannot apply the bindings of XXXXXXXXX/XXXNAME; theReadycondition of the object isFalsewith the reasonXXX.InvalidSpec: the rule cannot be rendered into bindings (unsupportedaccessLevel, anaccessLevelnot allowed for a namespaced rule, anadditionalRolesentry that is not a ClusterRole or has an invalid name). Fix the object.ApplyError: the API server rejected a write. The message of the condition names the binding and the error; a binding whoseroleRefwas changed by hand has to be deleted so that the controller recreates it.
d8 k XXX-n XXX XXXget XXX NAME -o jsonpath='{.status.conditions}' -
VALUE XXX objects cannot be applied (XXX).
user-authz-controllerreports VALUE XXX objects whose bindings cannot be applied, reasonXXX. Up to 50 of them are named by theD8UserAuthzAuthorizationRuleInvalidalerts; a large number with the reasonApplyErrorpoints at a cluster-wide cause (an admission webhook, API server errors) rather than at the objects.d8 k get XXX -A -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name,READY:'.status.conditions[?(@.type=="Ready")].status',REASON:'.status.conditions[?(@.type=="Ready")].reason' | grep -v True d8 k -n d8-user-authz logs deploy/user-authz-controller --all-pods=true -
D8UserAuthzBindingsDrift
CE
S7
user-authz-controller cannot converge the bindings of XXX.
For more than 15 minutes some bindings of
XXXobjects differ from the stateuser-authz-controllerwants (missing, superfluous, or with different subjects, roleRef, labels or owner). The controller reports drift only while its writes fail, so users may be missing access or keep access they should have lost.Find the objects and the reason:
d8 k get clusterauthorizationrules -o custom-columns=NAME:.metadata.name,READY:'.status.conditions[?(@.type=="Ready")].status',REASON:'.status.conditions[?(@.type=="Ready")].reason',MESSAGE:'.status.conditions[?(@.type=="Ready")].message' d8 k get authorizationrules -A -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name,READY:'.status.conditions[?(@.type=="Ready")].status',MESSAGE:'.status.conditions[?(@.type=="Ready")].message' d8 k -n d8-user-authz logs deploy/user-authz-controller --all-pods=true -
D8UserAuthzControllerReconcileErrorsHigh
CE
S8
user-authz-controller reconcile errors are high for CONTROLLER_NAME.
Controller
CONTROLLER_NAMEofuser-authz-controllerhas a reconcile error rate above 0.1 errors per second for more than 10 minutes.Check logs:
d8 k -n d8-user-authz logs deploy/user-authz-controller --all-pods=true -
D8UserAuthzControllerTargetDown
CE
S6
Prometheus is unable to scrape user-authz-controller.
Prometheus cannot scrape metrics from
user-authz-controllerin thed8-user-authznamespace.The controller is down, not Ready (its informer cache has not synced), or the PodMonitor is missing. Access rules are not reconciled while it is down.
Check:
d8 k -n d8-user-authz get pods -l app=user-authz-controller d8 k -n d8-user-authz describe pods -l app=user-authz-controller d8 k -n d8-monitoring get podmonitor user-authz-controller -
user-authz-controller has unavailable replicas.
Deckhouse has detected unavailable replicas in the
user-authz-controllerdeployment in thed8-user-authznamespace.While this alert is active, changes to ClusterAuthorizationRule and AuthorizationRule objects are not applied to their ClusterRoleBindings and RoleBindings, and the
d8:dictbindings and the RoleBindings of system and subsystem roles in module namespaces are not updated. Existing bindings keep working.Check deployment and pod states:
d8 k -n d8-user-authz get deploy user-authz-controller d8 k -n d8-user-authz get pods -l app=user-authz-controller d8 k -n d8-user-authz logs deploy/user-authz-controller --all-pods=true -
D8UserAuthzCustomRolesNotAggregated
CE
S6
The aggregated ClusterRole of the XXX access level has no rules although custom roles for it exist.
Custom ClusterRoles annotated with
user-authz.deckhouse.io/access-levelare granted to users through the aggregated ClusterRoleuser-authz:level:custom, whichkube-controller-managerfills from the roles labelled with the level. For more than 10 minutes the aggregated role of theXXXlevel has no rules while custom roles it must aggregate exist, so users of that level (and every level above it) have none of the custom permissions.Check that the aggregated role exists and that the
clusterrole-aggregationcontroller ofkube-controller-manageris running:d8 k get clusterrole -l user-authz.deckhouse.io/access-level d8 k get clusterrole -o name | grep 'user-authz:.*:custom' | xargs -n1 d8 k get -o yaml d8 k -n kube-system logs -l component=kube-controller-manager --tail=200 | grep -i aggregat -
D8UserAuthzDeprecatedRBACv2CapabilityInUse
CE
S5
A binding references a deprecated RBACv2 capability that no longer grants access.
The
XXXXXXXXX in namespaceNAMESPACEXXX binds the deprecated RBACv2 capabilityXXXdirectly.Capabilities (
d8:manage:permission:*,d8:use:capability:*) are aggregation building blocks — they are meant to be composed into thed8:{system,subsystem,namespace,project}:*roles, not bound directly. They were renamed and have NO compatibility alias, so this binding already grants nothing after the upgrade.No ClusterRole named
XXXexists in the cluster. The alert also names a binding to an old role name that a module no longer ships, for example after the module moved to the new role names.Recreate the binding against the appropriate new role (or a custom role aggregating the new capability). Because
roleRefis immutable, delete and recreate the binding:d8 k get XXX XXXXXX -n NAMESPACEXXX -o yaml -
D8UserAuthzDeprecatedRBACv2ModuleRoleInUse
CE
S7
A binding references the old name of a role a module renamed.
The
XXXXXXXXX in namespaceNAMESPACEXXX referencesXXX, the old name of a role that a module renamed toXXX.The module keeps the old name as a compatibility alias, so the binding keeps working. The alias may grant less than
XXX, for example when the module moved into a wider subsystem and the alias kept the rights of the old role, so check what the subjects of the binding need before recreating it. The module removes the alias in one of its own releases; the Deckhouse release is not held back by this binding. See the documentation of the module for when.Recreate the binding on the new name. Because
roleRefis immutable, delete and recreate the binding pointing atXXX:d8 k get XXX XXXXXX -n NAMESPACEXXX -o yaml -
D8UserAuthzDeprecatedRBACv2RoleInUse
CE
S7
A binding still references a deprecated RBACv2 role.
The
XXXXXXXXX in namespaceNAMESPACEXXX references the deprecated RBACv2 ClusterRoleXXX.The RBACv2 role model was renamed:
d8:manage:subsystem|all:levelbecamed8:system:*/d8:subsystem:*:*, andd8:use:role:levelbecamed8:namespace:level. This name still works via a compatibility alias kept for one release and will be removed in the next one — after that this binding will grant nothing. The release that removes the aliases is held back by thedeprecatedRBACv2BindingsCountrelease requirement until this binding is recreated on the new name.Migrate the binding to the new role name. Because
roleRefis immutable, delete and recreate the binding pointing at the new role:d8 k get XXX XXXXXX -n NAMESPACEXXX -o yaml # Recreate it with roleRef.name set to the new role (d8:system:*, d8:subsystem:*, or d8:namespace:*).XXX
user-authz-controllerrenders this binding fromspec.additionalRolesof the ClusterAuthorizationRuleXXXand creates it again when it is deleted. ReplaceXXXwith the new role name inspec.additionalRolesof that ClusterAuthorizationRule instead.XXXIf a project template renders this binding, replace the role name in the ProjectTemplate instead, becausemultitenancy-managerrenders the binding again from it.XXXXXXXXXIn the new model the rights for
user-authnanduser-authzXXX and the right to assign rolesXXX come withd8:subsystem:iam:XXX, not withd8:subsystem:security:XXX. To keep them, replace this binding with two bindings with the same subjects, one tod8:subsystem:iam:XXXand one tod8:subsystem:security:XXX.d8:subsystem:iam:XXXalso grants the rights formultitenancy-manager.XXXThe list of subsystems changed as well.
deckhouse,infrastructureandkuberneteswere merged intocluster,networkingbecamenetwork, theuser-authzanduser-authnmodules moved fromsecuritytoiam, andmultitenancy-managermoved fromdeckhousetoiam. The aliases of the old subsystem roles select the capabilities of the modules these roles covered, and the old subsystem labels that modules released on their own may still carry. The capabilities themselves changed in this release, so the rights of the binding are close to the ones it had before the upgrade, not the same. The replacementd8:subsystem:cluster:levelcovers the wholeclustersubsystem and grants more, and so do the roles of the other subsystems that the description of the alias names, so check which roles the subjects of the binding need. The user-authz documentation lists the remaining differences.A ClusterRoleBinding to a deprecated
d8:manage:*name also keeps the RoleBindingsd8:use:use role:binding:namethat the previous release created for it in the namespaces of the modules of its old subsystem (d8-cloud-provider-*,d8-monitoringand the rest). The use role isviewerfor avieweralias anduserfor amanageralias. When the binding is recreated on the new role name, they are replaced by RoleBindings to the namespace role of the new role in the namespaces of the modules of the new subsystem.Note: the new
d8:namespace:adminno longer grantsserviceaccounts/tokencreation or impersonation — these disaster-grade actions now require asuperadminrole by design. -
D8UserAuthzForeignAggregationLabel
CE
S6
ClusterRole NAME carries the XXX aggregation label without being a custom capability.
The ClusterRole
NAMEcarries therbac.deckhouse.io/aggregate-to-XXX-aslabel but is not labelledrbac.deckhouse.io/kind: custom-capabilityXXX (its kind label isXXX)XXX. The aggregation controller reads nothing but that label, so it merges the rules of this role into XXXthe platformd8:XXX:*rolesXXXthe deprecatedd8:manage:all:*andd8:use:role:*roles and every custom role that selects the labelXXXthed8:subsystem:XXX:*roles, if a subsystem has this name, and into every custom role that selects the labelXXX. Every holder of these roles in the cluster gets the rules, outside the role model’s contract.For the aggregation label of the system scope, of the namespace or project scope, or of a built-in subsystem, the
rbacv2-cluster-roles.deckhouse.iowebhook refuses such an object, and everyUPDATEof this role, including a GitOps re-apply, is denied until it is fixed. Choose one:- If the role is meant to extend the platform roles, replace it with a custom capability. The name of an object cannot be changed, so create
d8:custom:scope-capability:namewith the same rules and aggregation label, therbac.deckhouse.io/kind: custom-capabilityandrbac.deckhouse.io/scope: scopelabels, and noaggregationRule, and then delete this role. Deckhouse readsrbac.deckhouse.io/namespaceonly on the ClusterRoles it ships: if this role has that label, neither it nor its replacement gives RoleBinding objects in that namespace, so bind the subjects to a namespace role there with a RoleBinding. A capability of the old scheme with therbac.deckhouse.io/kind: uselabel andrbac.deckhouse.io/aggregate-to-kubernetes-as: LEVELorrbac.deckhouse.io/aggregate-to-all-as: LEVELextended the namespace roles, so its replacement isd8:custom:namespace-capability:namewithrbac.deckhouse.io/scope: namespaceandrbac.deckhouse.io/aggregate-to-namespace-as: LEVELinstead. For the commands, refer to the corresponding section in theuser-authzmodule FAQ. - Otherwise remove the
rbac.deckhouse.io/aggregate-to-*-aslabels from it.
List every such role:
d8 k get clusterroles -o json | jq -r '.items[] | select((.metadata.labels // {}) | to_entries | any(.key | startswith("rbac.deckhouse.io/aggregate-to-"))) | select((.metadata.labels.heritage // "") != "deckhouse") | select((.metadata.labels["rbac.deckhouse.io/kind"] // "") != "custom-capability") | .metadata.name' - If the role is meant to extend the platform roles, replace it with a custom capability. The name of an object cannot be changed, so create
-
D8UserAuthzLegacyRBACv2CustomRoleFound
CE
S7
The custom role NAME has lost access it gave through the labels of an earlier role model.
The ClusterRole
NAMEhas noheritage: deckhouselabel and has anaggregationRulefield, and one of the following holds:- A selector of its
aggregationRulefield requires therbac.deckhouse.io/kind: manageoruselabel of the experimental role model. The built-in capabilities no longer carry these labels, so such a selector matches none of them. The Kubernetes aggregation controller keeps from it only the rules of the custom capabilities that still carry the old labels, and the subjects of the role have lost the other permissions it gave. Custom roles get no compatibility aliases. - The role has the
rbac.deckhouse.io/use-rolelabel withoutrbac.deckhouse.io/scope: systemorsubsystem. Deckhouse creates the RoleBinding objects for the subjects of a role in the namespaces of the modules only for roles with that scope, so it has deleted the ones it had created for this role, even if its selectors are already rewritten. - A selector of its
aggregationRulefield requires the aggregation label of a lineage that no built-in role collects, such asrbac.deckhouse.io/aggregate-to-all-asof the old scheme, the label of a subsystem the role model no longer has, or the label of a subsystem a module has left. The modules label their capabilities only with the lineages that the built-in roles collect, so such a selector matches none of the built-in capabilities either. A selector by a lineage that a custom capability carries is not counted, because it still gets the rules of that capability. A custom capability here is a ClusterRole without theheritage: deckhouselabel and without anaggregationRulefield. Neither is a selector by the lineage of the subsystem in therbac.deckhouse.io/subsystemlabel of the role, because the custom capabilities of that subsystem carry it. Neither exception applies to theall,deckhouse,infrastructure,kubernetesandnetworkinglineages, which do not count as custom ones. A compatibility alias of an old role, a ClusterRole with therbac.deckhouse.io/deprecated: "true"label, does not count as a built-in role that collects a lineage, because it collects the lineage of an old subsystem only for the bindings to the old name.
Repair the access in this order:
- Create a role of the new scheme next to this one. Give it the
d8:custom:name prefix and therbac.deckhouse.io/kind: custom-rolelabel, and select the capabilities by the labels of the new scheme, withoutrbac.deckhouse.io/kind. Select the capabilities that a selector by a lineage no built-in role collects was meant for by theirrbac.deckhouse.io/capabilitylabels, or byrbac.deckhouse.io/scope: systemand themodulelabel of their module. If this role has therbac.deckhouse.io/use-rolelabel, keep the label on the new role and addrbac.deckhouse.io/scope: subsystemwithrbac.deckhouse.io/subsystem: SUBSYSTEM, orrbac.deckhouse.io/scope: system, so that Deckhouse creates the RoleBinding objects in the namespaces of the modules again. - Create capabilities of the new scheme in place of the custom capabilities of the old scheme that this role aggregates. The
D8UserAuthzForeignAggregationLabelalert names them. - For every RoleBinding and ClusterRoleBinding object to this role, create one with the same subjects to the new role. If this role has the
rbac.deckhouse.io/aggregate-to-all-as: LEVELlabel, what it extended depends on its kind label. Withrbac.deckhouse.io/kind: manage, its permissions also reached the subjects ofd8:manage:all:LEVEL. A custom role cannot be aggregated intod8:system:LEVEL, so bind the new role to those subjects with a ClusterRoleBinding. Withrbac.deckhouse.io/kind: use, they reached the subjects ofd8:use:role:LEVELin every namespace, so move the permissions into a namespace capability withrbac.deckhouse.io/aggregate-to-namespace-as: LEVEL, which extendsd8:namespace:LEVEL. - Check the permissions of the subjects with
d8 k auth can-i VERB RESOURCE --as=USER_NAME. - Delete the old bindings, this role and the old capabilities.
For the commands, refer to the corresponding section in the
user-authzmodule FAQ.List all such roles:
d8 k get clusterroles -o json | jq -r ' def lineages: [((.matchLabels // {}) | keys[]), (.matchExpressions[]? | select(.operator == "In" or .operator == "Exists") | .key)] | map(capture("^rbac\\.deckhouse\\.io/aggregate-to-(?lineage.+)-as$").lineage); ([.items[] | select(.metadata.labels.heritage == "deckhouse" and .metadata.labels["rbac.deckhouse.io/deprecated"] != "true") | .aggregationRule.clusterRoleSelectors[]? | lineages[]] + ["system", "namespace", "project"]) as $collected | ([.items[] | select(.metadata.labels.heritage != "deckhouse" and .aggregationRule == null) | (.metadata.labels // {}) | keys[] | capture("^rbac\\.deckhouse\\.io/aggregate-to-(?lineage.+)-as$").lineage]) as $carried | .items[] | select(.metadata.labels.heritage != "deckhouse" and .aggregationRule != null) | (.metadata.labels["rbac.deckhouse.io/subsystem"] // "") as $own | select( ( ((.metadata.labels["rbac.deckhouse.io/use-role"] // "") != "") and (((.metadata.labels["rbac.deckhouse.io/scope"] // "") | IN("system", "subsystem")) | not) ) or ( [ .aggregationRule.clusterRoleSelectors[]? | (.matchLabels["rbac.deckhouse.io/kind"] // empty), (.matchExpressions[]? | select(.key == "rbac.deckhouse.io/kind" and .operator == "In") | .values[]) ] | any(IN("manage", "use")) ) or ( [ .aggregationRule.clusterRoleSelectors[]? | lineages[] | select((IN($collected[]) | not) and (IN("all", "deckhouse", "infrastructure", "kubernetes", "networking") or (. != $own and (IN($carried[]) | not)))) ] | length > 0 ) ) | .metadata.name' - A selector of its
-
D8UserAuthzLegacyUseCapability
CE
S7
ClusterRole NAME carries the use labels of the previous scheme, which the namespace and project roles do not collect.
The ClusterRole
NAMEXXX of theMODULE_NAMEmoduleXXX carries therbac.deckhouse.io/kind: useandrbac.deckhouse.io/aggregate-to-XXX-as: XXXlabelsXXX of the use roles that a module with a subsystem of its own shipped in the previous schemeXXX of a use capability of the previous schemeXXX.rbac.deckhouse.io/kind: useis the label of a use capability of the previous schemeXXX. XXXThe moduleXXXThe capabilityXXX is still on that scheme.XXXThe
d8:namespace:*andd8:project:*roles do not collect this label. Only the deprecatedd8:use:role:*aliases still collect it, and they will be removed in the next release. A RoleBinding moved fromd8:use:role:XXXtod8:namespace:XXXand a project role therefore do not get the rules of this ClusterRole.XXXNo role collects a ClusterRole withrbac.deckhouse.io/kind: useand this label. Thed8:system:*andd8:subsystem:*roles and the deprecatedd8:manage:*aliases leave outrbac.deckhouse.io/kind: use, and thed8:namespace:*,d8:project:*andd8:use:role:*roles do not select this label. Only a binding to this ClusterRole itself gives its rules.XXXChoose one:
- If the ClusterRole belongs to a module, update the module to a release that labels its namespace capabilities with
rbac.deckhouse.io/kind: capabilityandrbac.deckhouse.io/aggregate-to-namespace-as. Until then, give the subjects that need these rules a RoleBinding toNAMEin their namespace, next to their RoleBinding to thed8:namespace:*role of their level. Neither role is a deprecated alias, so these RoleBinding objects do not hold the next release. In a project namespace, thecluster-objects-grants-validator.multitenancy.deckhouse.iowebhook admits a RoleBinding toNAMEonly if the ClusterRole has therbac.deckhouse.io/delegatable: "true"labelXXX, which the use capabilities of the previous scheme do not haveXXX.XXX Where the webhook refuses it, keep the RoleBinding to thed8:use:role:*alias: it keeps these rules, but theD8UserAuthzDeprecatedRBACv2RoleInUsealert reports it, and the next release, which removes the aliases, stays pending until the module is updated and the RoleBinding is moved to thed8:namespace:*role.XXX Where the webhook refuses it, the subjects get these rules only once the module is updated.XXX - If it is a custom capability, replace it with
d8:custom:namespace-capability:NAMEwith the same rules and therbac.deckhouse.io/kind: custom-capability,rbac.deckhouse.io/scope: namespaceandrbac.deckhouse.io/aggregate-to-namespace-as: XXXlabels. For the commands, refer to the corresponding section in theuser-authzmodule FAQ.
List every such ClusterRole:
d8 k get clusterroles -l rbac.deckhouse.io/kind=use -o json | jq -r '.items[] | select(.metadata.labels | keys | map(capture("^rbac\\.deckhouse\\.io/aggregate-to-(?lineage.+)-as$").lineage) | any(IN("kubernetes", "all", "system", "iam", "security", "cluster", "delivery", "network", "storage", "observability", "managed-services", "deckhouse", "infrastructure", "networking"))) | .metadata.name' - If the ClusterRole belongs to a module, update the module to a release that labels its namespace capabilities with
-
Permission Browser API server has unavailable replicas.
Deckhouse has detected unavailable replicas in the
permission-browser-apiserverdeployment in thed8-user-authznamespace. Permission Browser requests can fail while this alert is active.Check deployment and pod states:
d8 k -n d8-user-authz get deploy permission-browser-apiserver d8 k -n d8-user-authz get pods -l app=permission-browser-apiserver -
D8UserAuthzReleaseSlow
CE
S6
The user-authz module release repeatedly takes more than 5 minutes.
Applying the
user-authzHelm release took more than 5 minutes on average over the last hour, and it was applied at least twice in that hour, so this is not the single slow pass of a cluster bootstrap or of the one-time migration touser-authz-controller. A release that does not finish within the module release timeout (20 minutes) fails, changes to ClusterAuthorizationRule and AuthorizationRule objects stop being applied and platform updates stall (theD8DeckhouseCouldNotRunModulealert fires in that case).The release itself no longer grows with the number of rules: bindings are managed by
user-authz-controller, and custom ClusterRoles are aggregated. A slow release therefore points outside the module: an API server that answers slowly, an object stuck with a finalizer, a Deckhouse Pod short of CPU, or the release engine itself. Check what the release is waiting on:d8 s queue list d8 k -n d8-system logs deploy/deckhouse | grep '"module":"user-authz"'If the cluster has just been updated to the release that moved the bindings to the controller, one slow pass is expected and does not raise this alert by itself; if it fires anyway, the pass is being retried. It is proportional to the number of bindings and can exceed the timeout on clusters with more than 5000 of them; the module FAQ describes what to do in that case.
-
D8UserAuthzRenderSlow
CE
S7
Rendering the user-authz module templates repeatedly takes more than 30 seconds.
Rendering the templates of the
user-authzmodule took more than 30 seconds on average over the last 30 minutes, across at least three renders; normally one render takes about a second. Rendering is CPU work inside the Deckhouse Pod and does not depend on the number of ClusterAuthorizationRule or AuthorizationRule objects, so the cause is the node, not the module: most often the Deckhouse Pod is short of CPU (CPU steal on a virtual machine, a node running at its limits, a bootstrap that starts every module at once).A single slow render during a cluster bootstrap does not raise this alert by itself. If it fires, compare the module with the others and look at the node:
topk(10, increase(deckhouse_helm_operation_seconds_sum{operation="template"}[30m]) / increase(deckhouse_helm_operation_seconds_count{operation="template"}[30m])) rate(node_cpu_seconds_total{mode="steal"}[5m])d8 k -n d8-system logs deploy/deckhouse | grep '"module":"user-authz"' -
D8UserAuthzRetiredAggregationLabel
CE
S7
ClusterRole NAME aggregates by the label of the retired XXX subsystem.
The ClusterRole
NAMEXXX of theMODULE_NAMEmoduleXXX carries therbac.deckhouse.io/aggregate-to-XXX-aslabel.The role model has no
XXXsubsystem any more.deckhouse,infrastructureandkuberneteswere merged intocluster, andnetworkingwas renamed tonetwork. Nod8:system:*ord8:subsystem:*role collects this label, so the holders of these roles do not get the rules of this ClusterRole. Only the deprecatedd8:manage:*aliases still collect it, and they will be removed in the next release.Choose one:
- If the ClusterRole belongs to a module, update the module to a release that labels its capabilities with the lineage of its new subsystem. For most modules of the old subsystem that is
rbac.deckhouse.io/aggregate-to-XXX-as. The subsystem of each module is listed in the user-authz documentation. - If it is a custom capability, replace the label with
rbac.deckhouse.io/aggregate-to-XXX-asor with the label of the subsystem the capability belongs to now.
Until then, a subject bound to a new role gets the rules of such a capability of a module only through a custom role. Create a
d8:custom:system:NAMEClusterRole with therbac.deckhouse.io/kind: custom-roleandrbac.deckhouse.io/scope: systemlabels and bind it to the subjects with a ClusterRoleBinding. A capability of the previous scheme has norbac.deckhouse.io/capabilitylabel, so the role selects the capabilities of the module by themodule: XXXMODULE_NAMEXXXMODULEXXXandrbac.deckhouse.io/kind: managelabels. Such a selector takes the capabilities of every level, so addrbac.deckhouse.io/aggregate-to-XXX-as: viewerto it for a role that only views. TheD8UserAuthzLegacyRBACv2CustomRoleFoundalert names this role, because it selects by a label of the previous scheme. Once the module carries the new labels, select its capabilities by theirrbac.deckhouse.io/capabilitylabel instead. A capability that already carriesrbac.deckhouse.io/kind: capabilityis selected by itsrbac.deckhouse.io/capabilitylabel right away.List every such ClusterRole:
d8 k get clusterroles -o json | jq -r '.items[] | select((.metadata.labels["rbac.deckhouse.io/kind"] // "") != "use") | select((.metadata.labels // {}) | keys | any(IN("rbac.deckhouse.io/aggregate-to-deckhouse-as", "rbac.deckhouse.io/aggregate-to-infrastructure-as", "rbac.deckhouse.io/aggregate-to-kubernetes-as", "rbac.deckhouse.io/aggregate-to-networking-as"))) | .metadata.name' - If the ClusterRole belongs to a module, update the module to a release that labels its capabilities with the lineage of its new subsystem. For most modules of the old subsystem that is
-
D8UserAuthzRevocationCheckNotSynced
CE
S6
The revocation check of the user-authz webhook has not loaded the revocations.
For more than 10 minutes the
user-authz-webhookinstancePOD_NAMEhas not loaded theRevocationobjects of theuser-authnmodule (the objects ind8-user-authnthat record revoked user credentials): it cannot list them, or cannot find out whether the API server serves them.Until it loads them, the instance has no opinion about revoked credentials: on the master node of this instance,
kubectlwith the token of a locked or logged-out user keeps working until the token expires. Other authorization decisions are not affected.Check the webhook’s access to the API and its logs:
d8 k -n d8-user-authz logs POD_NAME -c webhook --tail=100 | grep -i revocation d8 k auth can-i list revocations.dex.coreos.com -n d8-user-authn --as=system:serviceaccount:d8-user-authz:webhook -
D8UserAuthzRevocationCheckStale
CE
S6
The revocation check of the user-authz webhook no longer sees new revocations.
For more than 15 minutes the
user-authz-webhookinstancePOD_NAMEhas been unable to watch theRevocationobjects of theuser-authnmodule (the objects ind8-user-authnthat record revoked user credentials).The instance keeps refusing the Dex tokens it already knows to be revoked, but a revocation made since its watch broke does not reach it: on the master node of this instance,
kubectlwith the token of a locked or logged-out user keeps working until the token expires.Check the webhook’s access to the API and its logs:
d8 k -n d8-user-authz logs POD_NAME -c webhook --tail=100 | grep -i revocation d8 k auth can-i watch revocations.dex.coreos.com -n d8-user-authn --as=system:serviceaccount:d8-user-authz:webhook -
D8UserAuthzRuleNeedsMultiTenancy
CE
S6
A ClusterAuthorizationRule asks for namespace limits that nothing enforces.
The
ClusterAuthorizationRuleNAMEsetsXXX, but theenableMultiTenancysetting of theuser-authzmodule is off, so the authorization webhook that enforces those options is not deployed.The rule is not partially applied. It is applied without its limits: the subjects named in it hold its access level in every namespace of the cluster, the system ones included.
Either enable multi-tenancy, or remove the options from the rule:
d8 k get clusterauthorizationrule NAME -o yaml d8 k get moduleconfig user-authz -o jsonpath='{.spec.settings.enableMultiTenancy}' -
D8UserAuthzRulePropagationLag
CE
S6
One user-authz webhook instance stopped picking up rule changes.
One instance of
user-authz-webhookhas not updated its rules for more than an hour while another instance has. The rules are changing in the cluster and this instance does not see the changes.Find the instance and check its log:
d8 k -n d8-user-authz get pods -l app=user-authz-webhook -o wide d8 k -n d8-user-authz logs -l app=user-authz-webhook -c webhook --tail=100An instance whose watch keeps failing becomes not ready, so check the readiness of the Pod as well.
-
D8UserAuthzRulesNeedMultiTenancy
CE
S6
More ClusterAuthorizationRules ask for namespace limits than the per-rule alert names.
VALUEClusterAuthorizationRules setlimitNamespaces,namespaceSelectororallowAccessToSystemNamespaceswhile theenableMultiTenancysetting of theuser-authzmodule is off.D8UserAuthzRuleNeedsMultiTenancynames the first 50 of them; this alert accounts for the rest.None of those rules is partially applied: the subjects named in each of them hold its access level in every namespace of the cluster, the system ones included.
Check whether multi-tenancy was meant to be enabled, and list the affected rules:
d8 k get moduleconfig user-authz -o jsonpath='{.spec.settings.enableMultiTenancy}' d8 k get clusterauthorizationrule -o json | jq -r '.items[] | select((.spec.limitNamespaces // [] | length > 0) or (.spec.namespaceSelector != null) or (.spec.allowAccessToSystemNamespaces == true)) | .metadata.name' -
D8UserAuthzWebhookDirectoryDiverged
CE
S6
The masters disagree about the multi-tenancy rules.
Instances of
user-authz-webhookhave been using different sets ofClusterAuthorizationRulesfor 10 minutes.Each master node authorizes the requests that reach it, so the same request is answered differently depending on the node: a user can be inside their namespace limits on one node and outside them on another.
Find the instance that is behind and look at why:
d8 k -n d8-user-authz get pods -l app=user-authz-webhook -o wide d8 k -n d8-user-authz logs -l app=user-authz-webhook -c webhook --tail=100 | grep -i 'list/watch'A growing
user_authz_webhook_rules_watch_errors_totalon one instance points at its watch; auser_authz_webhook_rules_directory_updated_timestamp_secondsthat has stopped moving points at rules that are no longer updated. Deleting the lagging Pod is the last resort: the DaemonSet recreates it, and on a cluster with a single master node every request that the authorization webhook has to answer is denied while the Pod restarts. Control plane components, kubelets, and the ServiceAccounts of thekube-systemandd8-*namespaces keep working, because the webhook does not check them. -
D8UserAuthzWebhookRulesQuarantined
CE
S7
A ClusterAuthorizationRule cannot be compiled by the webhook.
For more than 10 minutes the
user-authz-webhookhas quarantined at least oneClusterAuthorizationRule: itslimitNamespacespattern ornamespaceSelectordoes not compile, or the rule cannot be read at all.A rule with a broken filter is applied without that filter, so its subjects get a narrower scope than written and are denied where the filter was meant to allow. A rule that cannot be read is not applied at all, and its subjects are denied every namespace.
Find the rule:
d8 k get clusterauthorizationrules -o custom-columns=NAME:.metadata.name,LIMIT:.spec.limitNamespaces,SELECTOR:.spec.namespaceSelector d8 k -n d8-user-authz logs -l app=user-authz-webhook -c webhook --tail=100 | grep -i quarantin -
D8UserAuthzWebhookRulesWatchErrors
CE
S7
The user-authz webhook cannot watch the ClusterAuthorizationRules.
For more than 10 minutes the
user-authz-webhookrules informer has been failing to watch theClusterAuthorizationRules(a non-zero rate of watch errors). New or changed rules may not be reaching the webhook, so multi-tenancy decisions can lag behind what users configure.Check the webhook’s access to the API and its logs:
d8 k -n d8-user-authz logs -l app=user-authz-webhook -c webhook --tail=100 d8 k auth can-i watch clusterauthorizationrules.deckhouse.io --as=system:serviceaccount:d8-user-authz:webhook -
D8UserAuthzWebhookTargetDown
CE
S6
Prometheus is unable to scrape the user-authz webhook.
Prometheus cannot collect metrics from at least one instance of
user-authz-webhookin thed8-user-authznamespace. One instance without metrics is enough for the alert to fire.If the instance is running and only its metrics are unreachable, it keeps answering authorization requests, but the other alerts of the module cannot see its state. If it is not running or has not read the rules yet, it answers
503to every authorization request, and the API server denies the request, because the webhook is configured withfailurePolicy: Deny.Check the DaemonSet, its metrics sidecar and the scrape target:
d8 k -n d8-user-authz get pods -l app=user-authz-webhook -o wide d8 k -n d8-user-authz logs -l app=user-authz-webhook -c kube-rbac-proxy --tail=50
Модуль vertical-pod-autoscaler
-
VerticalPodAutoscalerDeprecatedUpdateModeAuto
CE
S9
VerticalPodAutoscaler objects use the deprecated Auto update mode.
There are
VALUEVerticalPodAutoscaler object(s) in the cluster configured with the deprecated update mode (spec.updatePolicy.updateMode: Auto).The
Autoupdate mode is deprecated. It currently behaves likeRecreate(the VPA updater evicts pods to apply new resource requests) and its semantics are reserved to change in future versions, which makes cluster behavior ambiguous and potentially disruptive.Set the affected VPA object(s) to one of the supported update modes (
spec.updatePolicy.updateMode):InPlaceOrRecreate: Apply recommendations in place when possible, fall back to recreation (recommended).Recreate: Evict and recreate pods to apply recommendations.Initial: Apply only when pods are (re)created.Off: Recommendations only, no changes to running pods.
To list the affected objects, open the VPA Deprecated Update Mode Grafana dashboard, or run:
kube_verticalpodautoscaler_spec_updatepolicy_updatemode{update_mode="Auto"} == 1