node_lifecycle_controller

时间:2025-05-13 07:29:36
// tryUpdateNodeHealth checks a given node's conditions and tries to update it. Returns grace period to // which given node is entitled, state of current and last observed Ready Condition, and an error if it occurred. func (nc *Controller) tryUpdateNodeHealth(node *v1.Node) (time.Duration, v1.NodeCondition, *v1.NodeCondition, error) { nodeHealth := nc.nodeHealthMap.getDeepCopy(node.Name) defer func() { nc.nodeHealthMap.set(node.Name, nodeHealth) }() var gracePeriod time.Duration var observedReadyCondition v1.NodeCondition _, currentReadyCondition := nodeutil.GetNodeCondition(&node.Status, v1.NodeReady) // conditions: // - lastHeartbeatTime: "2021-01-30T07:02:26Z" // lastTransitionTime: "2021-01-17T08:11:46Z" // message: kubelet has sufficient memory available // reason: KubeletHasSufficientMemory // status: "False" // type: MemoryPressure // - lastHeartbeatTime: "2021-01-30T07:02:26Z" // lastTransitionTime: "2021-01-17T08:11:46Z" // message: kubelet has no disk pressure // reason: KubeletHasNoDiskPressure // status: "False" // type: DiskPressure // - lastHeartbeatTime: "2021-01-30T07:02:26Z" // lastTransitionTime: "2021-01-17T08:11:46Z" // message: kubelet has sufficient PID available // reason: KubeletHasSufficientPID // status: "False" // type: PIDPressure // - lastHeartbeatTime: "2021-01-30T07:02:26Z" // lastTransitionTime: "2021-01-20T12:47:31Z" // message: kubelet is posting ready status // reason: KubeletReady // status: "True" // type: Ready // 如果为空,说明kubelet从开始就没有上报数据,开始将observedReadyCondition 进行设置, if currentReadyCondition == nil { // 属于新加入节点一类。 // If ready condition is nil, then kubelet (or nodecontroller) never posted node status. // A fake ready condition is created, where LastHeartbeatTime and LastTransitionTime is set // to to avoid handle the corner case. observedReadyCondition = v1.NodeCondition{ Type: v1.NodeReady, Status: v1.ConditionUnknown, LastHeartbeatTime: node.CreationTimestamp, LastTransitionTime: node.CreationTimestamp, } gracePeriod = nc.nodeStartupGracePeriod // 如果健康的节点数据中有他的信息的话,那么将健康状态进行修改 if nodeHealth != nil { nodeHealth.status = &node.Status } else { // 否则开始更新数据 nodeHealth = &nodeHealthData{ status: &node.Status, probeTimestamp: node.CreationTimestamp, readyTransitionTimestamp: node.CreationTimestamp, } } } else { // 如果有数据了,那么当前状态设定为 observedReadyCondition // If ready condition is not nil, make a copy of it, since we may modify it in place later. observedReadyCondition = *currentReadyCondition gracePeriod = nc.nodeMonitorGracePeriod } // There are following cases to check: // - both saved and new status have no Ready Condition set - we leave everything as it is, // - saved status have no Ready Condition, but current one does - Controller was restarted with Node data already present in etcd, // - saved status have some Ready Condition, but current one does not - it's an error, but we fill it up because that's probably a good thing to do, // - both saved and current statuses have Ready Conditions and they have the same LastProbeTime - nothing happened on that Node, it may be // unresponsive, so we leave it as it is, // - both saved and current statuses have Ready Conditions, they have different LastProbeTimes, but the same Ready Condition State - // everything's in order, no transition occurred, we update only probeTimestamp, // - both saved and current statuses have Ready Conditions, different LastProbeTimes and different Ready Condition State - // Ready Condition changed it state since we last seen it, so we update both probeTimestamp and readyTransitionTimestamp. // TODO: things to consider: // - if 'LastProbeTime' have gone back in time its probably an error, currently we ignore it, // - currently only correct Ready State transition outside of Node Controller is marking it ready by Kubelet, we don't check // if that's the case, but it does not seem necessary. var savedCondition *v1.NodeCondition var savedLease *coordv1.Lease if nodeHealth != nil { _, savedCondition = nodeutil.GetNodeCondition(nodeHealth.status, v1.NodeReady) savedLease = nodeHealth.lease } // 针对新加入的节点,删除节点做一些操作 if nodeHealth == nil { klog.Warningf("Missing timestamp for Node %s. Assuming now as a timestamp.", node.Name) nodeHealth = &nodeHealthData{ status: &node.Status, probeTimestamp: nc.now(), readyTransitionTimestamp: nc.now(), } } else if savedCondition == nil && currentReadyCondition != nil { klog.V(1).Infof("Creating timestamp entry for newly observed Node %s", node.Name) nodeHealth = &nodeHealthData{ status: &node.Status, probeTimestamp: nc.now(), readyTransitionTimestamp: nc.now(), } } else if savedCondition != nil && currentReadyCondition == nil { klog.Errorf("ReadyCondition was removed from Status of Node %s", node.Name) // TODO: figure out what to do in this case. For now we do the same thing as above. nodeHealth = &nodeHealthData{ status: &node.Status, probeTimestamp: nc.now(), readyTransitionTimestamp: nc.now(), } } else if savedCondition != nil && currentReadyCondition != nil && savedCondition.LastHeartbeatTime != currentReadyCondition.LastHeartbeatTime { var transitionTime metav1.Time // If ReadyCondition changed since the last time we checked, we update the transition timestamp to "now", // otherwise we leave it as it is. if savedCondition.LastTransitionTime != currentReadyCondition.LastTransitionTime { klog.V(3).Infof("ReadyCondition for Node %s transitioned from %v to %v", node.Name, savedCondition, currentReadyCondition) transitionTime = nc.now() } else { transitionTime = nodeHealth.readyTransitionTimestamp } if klog.V(5) { klog.Infof("Node %s ReadyCondition updated. Updating timestamp: %+v vs %+v.", node.Name, nodeHealth.status, node.Status) } else { klog.V(3).Infof("Node %s ReadyCondition updated. Updating timestamp.", node.Name) } // 针对日志界别不同,打印出不同级别的信息 nodeHealth = &nodeHealthData{ status: &node.Status, probeTimestamp: nc.now(), readyTransitionTimestamp: transitionTime, } } // Always update the probe time if node lease is renewed. // Note: If kubelet never posted the node status, but continues renewing the // heartbeat leases, the node controller will assume the node is healthy and // take no action. observedLease, _ := nc.leaseLister.Leases(v1.NamespaceNodeLease).Get(node.Name) if observedLease != nil && (savedLease == nil || savedLease.Spec.RenewTime.Before(observedLease.Spec.RenewTime)) { nodeHealth.lease = observedLease nodeHealth.probeTimestamp = nc.now() } if nc.now().After(nodeHealth.probeTimestamp.Add(gracePeriod)) { // 如果超出了规定的时间,那么将更新节点的状态,也就是notready的主流程。 // NodeReady condition or lease was last set longer ago than gracePeriod, so // update it to Unknown (regardless of its current value) in the master. nodeConditionTypes := []v1.NodeConditionType{ v1.NodeReady, v1.NodeMemoryPressure, v1.NodeDiskPressure, v1.NodePIDPressure, // We don't change 'NodeNetworkUnavailable' condition, as it's managed on a control plane level. // , } nowTimestamp := nc.now() for _, nodeConditionType := range nodeConditionTypes { _, currentCondition := nodeutil.GetNodeCondition(&node.Status, nodeConditionType) if currentCondition == nil { // kubelet没有更新状态,开始更改conditions,例如新加入节点的 klog.V(2).Infof("Condition %v of node %v was never updated by kubelet", nodeConditionType, node.Name) node.Status.Conditions = append(node.Status.Conditions, v1.NodeCondition{ Type: nodeConditionType, Status: v1.ConditionUnknown, Reason: "NodeStatusNeverUpdated", Message: "Kubelet never posted node status.", LastHeartbeatTime: node.CreationTimestamp, LastTransitionTime: nowTimestamp, }) } else { // kubelet网络中断等原因没有更新节点信息的 klog.V(2).Infof("node %v hasn't been updated for %+v. Last %v is: %+v", node.Name, nc.now().Time.Sub(nodeHealth.probeTimestamp.Time), nodeConditionType, currentCondition) if currentCondition.Status != v1.ConditionUnknown { currentCondition.Status = v1.ConditionUnknown currentCondition.Reason = "NodeStatusUnknown" currentCondition.Message = "Kubelet stopped posting node status." currentCondition.LastTransitionTime = nowTimestamp } } } // We need to update currentReadyCondition due to its value potentially changed. _, currentReadyCondition = nodeutil.GetNodeCondition(&node.Status, v1.NodeReady) // 根据拷贝信息对比进行更改。 if !apiequality.Semantic.DeepEqual(currentReadyCondition, &observedReadyCondition) { if _, err := nc.kubeClient.CoreV1().Nodes().UpdateStatus(node); err != nil { klog.Errorf("Error updating node %s: %v", node.Name, err) return gracePeriod, observedReadyCondition, currentReadyCondition, err } nodeHealth = &nodeHealthData{ status: &node.Status, probeTimestamp: nodeHealth.probeTimestamp, readyTransitionTimestamp: nc.now(), lease: observedLease, } return gracePeriod, observedReadyCondition, currentReadyCondition, nil } } return gracePeriod, observedReadyCondition, currentReadyCondition, nil }