| 622 | } |
| 623 | |
| 624 | func run(ctx context.Context, s *options.KubeletServer, kubeDeps *kubelet.Dependencies, featureGate featuregate.FeatureGate) (err error) { |
| 625 | logger := klog.FromContext(ctx) |
| 626 | // NewHealthChecker returns an error indicating that the watchdog is configured but the configuration is incorrect, |
| 627 | // the kubelet will not be started. |
| 628 | healthChecker, err := watchdog.NewHealthChecker(logger) |
| 629 | if err != nil { |
| 630 | return fmt.Errorf("create health checker: %w", err) |
| 631 | } |
| 632 | kubeDeps.HealthChecker = healthChecker |
| 633 | healthChecker.Start(ctx) |
| 634 | // Set global feature gates based on the value on the initial KubeletServer |
| 635 | err = utilfeature.DefaultMutableFeatureGate.SetFromMap(s.KubeletConfiguration.FeatureGates) |
| 636 | if err != nil { |
| 637 | return err |
| 638 | } |
| 639 | // Propagate feature gate state to the metrics subsystem. This must be called |
| 640 | // after feature gates are set and before any histogram metrics are registered. |
| 641 | metricsfeatures.ApplyFeatureGates(featureGate) |
| 642 | // validate the initial KubeletServer (we set feature gates first, because this validation depends on feature gates) |
| 643 | if err := options.ValidateKubeletServer(s); err != nil { |
| 644 | return err |
| 645 | } |
| 646 | |
| 647 | // Warn about MemoryQoS compatibility issues |
| 648 | if utilfeature.DefaultFeatureGate.Enabled(features.MemoryQoS) { |
| 649 | if !kubeletutil.IsCgroup2UnifiedMode() { |
| 650 | logger.Info("Warning: MemoryQoS feature only works with cgroups v2 on Linux, but enabled with cgroups v1") |
| 651 | } else { |
| 652 | kernelVersion, err := utilkernel.GetVersion() |
| 653 | if err != nil { |
| 654 | logger.Error(err, "Failed to detect kernel version for MemoryQoS compatibility check") |
| 655 | } else if kernelVersion.LessThan(utilversion.MustParseGeneric(utilkernel.MemoryQoSMinKernelVersion)) { |
| 656 | logger.Info("Warning: MemoryQoS memory.high throttling may cause process livelock on older kernels", |
| 657 | "currentKernel", kernelVersion, |
| 658 | "minimumKernel", utilkernel.MemoryQoSMinKernelVersion) |
| 659 | } |
| 660 | } |
| 661 | } |
| 662 | // Obtain Kubelet Lock File |
| 663 | if s.ExitOnLockContention && s.LockFilePath == "" { |
| 664 | return errors.New("cannot exit on lock file contention: no lock file specified") |
| 665 | } |
| 666 | done := make(chan struct{}) |
| 667 | if s.LockFilePath != "" { |
| 668 | logger.Info("Acquiring file lock", "path", s.LockFilePath) |
| 669 | if err := flock.Acquire(s.LockFilePath); err != nil { |
| 670 | return fmt.Errorf("unable to acquire file lock on %q: %w", s.LockFilePath, err) |
| 671 | } |
| 672 | if s.ExitOnLockContention { |
| 673 | logger.Info("Watching for inotify events", "path", s.LockFilePath) |
| 674 | if err := watchForLockfileContention(ctx, s.LockFilePath, done); err != nil { |
| 675 | return err |
| 676 | } |
| 677 | } |
| 678 | } |
| 679 | |
| 680 | if len(s.ShowHiddenMetricsForVersion) > 0 { |
| 681 | metrics.SetShowHidden() |