k8s.io/kubernetes@v1.29.3/pkg/kubelet/stats/provider.go (about)

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package stats
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  
    23  	cadvisorapiv1 "github.com/google/cadvisor/info/v1"
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	"k8s.io/apimachinery/pkg/types"
    26  	internalapi "k8s.io/cri-api/pkg/apis"
    27  	statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
    28  	"k8s.io/kubernetes/pkg/kubelet/cadvisor"
    29  	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
    30  	"k8s.io/kubernetes/pkg/kubelet/server/stats"
    31  	"k8s.io/kubernetes/pkg/kubelet/stats/pidlimit"
    32  	"k8s.io/kubernetes/pkg/kubelet/status"
    33  	kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
    34  	"k8s.io/utils/ptr"
    35  )
    36  
    37  // PodManager is the subset of methods the manager needs to observe the actual state of the kubelet.
    38  // See pkg/k8s.io/kubernetes/pkg/kubelet/pod.Manager for method godoc.
    39  type PodManager interface {
    40  	TranslatePodUID(uid types.UID) kubetypes.ResolvedPodUID
    41  }
    42  
    43  // NewCRIStatsProvider returns a Provider that provides the node stats
    44  // from cAdvisor and the container stats from CRI.
    45  func NewCRIStatsProvider(
    46  	cadvisor cadvisor.Interface,
    47  	resourceAnalyzer stats.ResourceAnalyzer,
    48  	podManager PodManager,
    49  	runtimeCache kubecontainer.RuntimeCache,
    50  	runtimeService internalapi.RuntimeService,
    51  	imageService internalapi.ImageManagerService,
    52  	hostStatsProvider HostStatsProvider,
    53  	podAndContainerStatsFromCRI bool,
    54  ) *Provider {
    55  	return newStatsProvider(cadvisor, podManager, runtimeCache, newCRIStatsProvider(cadvisor, resourceAnalyzer,
    56  		runtimeService, imageService, hostStatsProvider, podAndContainerStatsFromCRI))
    57  }
    58  
    59  // NewCadvisorStatsProvider returns a containerStatsProvider that provides both
    60  // the node and the container stats from cAdvisor.
    61  func NewCadvisorStatsProvider(
    62  	cadvisor cadvisor.Interface,
    63  	resourceAnalyzer stats.ResourceAnalyzer,
    64  	podManager PodManager,
    65  	runtimeCache kubecontainer.RuntimeCache,
    66  	imageService kubecontainer.ImageService,
    67  	statusProvider status.PodStatusProvider,
    68  	hostStatsProvider HostStatsProvider,
    69  ) *Provider {
    70  	return newStatsProvider(cadvisor, podManager, runtimeCache, newCadvisorStatsProvider(cadvisor, resourceAnalyzer, imageService, statusProvider, hostStatsProvider))
    71  }
    72  
    73  // newStatsProvider returns a new Provider that provides node stats from
    74  // cAdvisor and the container stats using the containerStatsProvider.
    75  func newStatsProvider(
    76  	cadvisor cadvisor.Interface,
    77  	podManager PodManager,
    78  	runtimeCache kubecontainer.RuntimeCache,
    79  	containerStatsProvider containerStatsProvider,
    80  ) *Provider {
    81  	return &Provider{
    82  		cadvisor:               cadvisor,
    83  		podManager:             podManager,
    84  		runtimeCache:           runtimeCache,
    85  		containerStatsProvider: containerStatsProvider,
    86  	}
    87  }
    88  
    89  // Provider provides the stats of the node and the pod-managed containers.
    90  type Provider struct {
    91  	cadvisor     cadvisor.Interface
    92  	podManager   PodManager
    93  	runtimeCache kubecontainer.RuntimeCache
    94  	containerStatsProvider
    95  }
    96  
    97  // containerStatsProvider is an interface that provides the stats of the
    98  // containers managed by pods.
    99  type containerStatsProvider interface {
   100  	ListPodStats(ctx context.Context) ([]statsapi.PodStats, error)
   101  	ListPodStatsAndUpdateCPUNanoCoreUsage(ctx context.Context) ([]statsapi.PodStats, error)
   102  	ListPodCPUAndMemoryStats(ctx context.Context) ([]statsapi.PodStats, error)
   103  	ImageFsStats(ctx context.Context) (*statsapi.FsStats, *statsapi.FsStats, error)
   104  	ImageFsDevice(ctx context.Context) (string, error)
   105  }
   106  
   107  // RlimitStats returns base information about process count
   108  func (p *Provider) RlimitStats() (*statsapi.RlimitStats, error) {
   109  	return pidlimit.Stats()
   110  }
   111  
   112  // GetCgroupStats returns the stats of the cgroup with the cgroupName. Note that
   113  // this function doesn't generate filesystem stats.
   114  func (p *Provider) GetCgroupStats(cgroupName string, updateStats bool) (*statsapi.ContainerStats, *statsapi.NetworkStats, error) {
   115  	info, err := getCgroupInfo(p.cadvisor, cgroupName, updateStats)
   116  	if err != nil {
   117  		return nil, nil, fmt.Errorf("failed to get cgroup stats for %q: %v", cgroupName, err)
   118  	}
   119  	// Rootfs and imagefs doesn't make sense for raw cgroup.
   120  	s := cadvisorInfoToContainerStats(cgroupName, info, nil, nil)
   121  	n := cadvisorInfoToNetworkStats(info)
   122  	return s, n, nil
   123  }
   124  
   125  // GetCgroupCPUAndMemoryStats returns the CPU and memory stats of the cgroup with the cgroupName. Note that
   126  // this function doesn't generate filesystem stats.
   127  func (p *Provider) GetCgroupCPUAndMemoryStats(cgroupName string, updateStats bool) (*statsapi.ContainerStats, error) {
   128  	info, err := getCgroupInfo(p.cadvisor, cgroupName, updateStats)
   129  	if err != nil {
   130  		return nil, fmt.Errorf("failed to get cgroup stats for %q: %v", cgroupName, err)
   131  	}
   132  	// Rootfs and imagefs doesn't make sense for raw cgroup.
   133  	s := cadvisorInfoToContainerCPUAndMemoryStats(cgroupName, info)
   134  	return s, nil
   135  }
   136  
   137  // RootFsStats returns the stats of the node root filesystem.
   138  func (p *Provider) RootFsStats() (*statsapi.FsStats, error) {
   139  	rootFsInfo, err := p.cadvisor.RootFsInfo()
   140  	if err != nil {
   141  		return nil, fmt.Errorf("failed to get rootFs info: %v", err)
   142  	}
   143  
   144  	var nodeFsInodesUsed *uint64
   145  	if rootFsInfo.Inodes != nil && rootFsInfo.InodesFree != nil {
   146  		nodeFsIU := *rootFsInfo.Inodes - *rootFsInfo.InodesFree
   147  		nodeFsInodesUsed = &nodeFsIU
   148  	}
   149  
   150  	// Get the root container stats's timestamp, which will be used as the
   151  	// imageFs stats timestamp.  Don't force a stats update, as we only want the timestamp.
   152  	rootStats, err := getCgroupStats(p.cadvisor, "/", false)
   153  	if err != nil {
   154  		return nil, fmt.Errorf("failed to get root container stats: %v", err)
   155  	}
   156  
   157  	return &statsapi.FsStats{
   158  		Time:           metav1.NewTime(rootStats.Timestamp),
   159  		AvailableBytes: &rootFsInfo.Available,
   160  		CapacityBytes:  &rootFsInfo.Capacity,
   161  		UsedBytes:      &rootFsInfo.Usage,
   162  		InodesFree:     rootFsInfo.InodesFree,
   163  		Inodes:         rootFsInfo.Inodes,
   164  		InodesUsed:     nodeFsInodesUsed,
   165  	}, nil
   166  }
   167  
   168  // GetContainerInfo returns stats (from cAdvisor) for a container.
   169  func (p *Provider) GetContainerInfo(ctx context.Context, podFullName string, podUID types.UID, containerName string, req *cadvisorapiv1.ContainerInfoRequest) (*cadvisorapiv1.ContainerInfo, error) {
   170  	// Resolve and type convert back again.
   171  	// We need the static pod UID but the kubecontainer API works with types.UID.
   172  	podUID = types.UID(p.podManager.TranslatePodUID(podUID))
   173  
   174  	pods, err := p.runtimeCache.GetPods(ctx)
   175  	if err != nil {
   176  		return nil, err
   177  	}
   178  	pod := kubecontainer.Pods(pods).FindPod(podFullName, podUID)
   179  	container := pod.FindContainerByName(containerName)
   180  	if container == nil {
   181  		return nil, kubecontainer.ErrContainerNotFound
   182  	}
   183  
   184  	ci, err := p.cadvisor.DockerContainer(container.ID.ID, req)
   185  	if err != nil {
   186  		return nil, err
   187  	}
   188  	return &ci, nil
   189  }
   190  
   191  // GetRawContainerInfo returns the stats (from cadvisor) for a non-Kubernetes
   192  // container.
   193  func (p *Provider) GetRawContainerInfo(containerName string, req *cadvisorapiv1.ContainerInfoRequest, subcontainers bool) (map[string]*cadvisorapiv1.ContainerInfo, error) {
   194  	if subcontainers {
   195  		return p.cadvisor.SubcontainerInfo(containerName, req)
   196  	}
   197  	containerInfo, err := p.cadvisor.ContainerInfo(containerName, req)
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  	return map[string]*cadvisorapiv1.ContainerInfo{
   202  		containerInfo.Name: containerInfo,
   203  	}, nil
   204  }
   205  
   206  // HasDedicatedImageFs returns true if a dedicated image filesystem exists for storing images.
   207  // KEP Issue Number 4191: Enhanced this to allow for the containers to be separate from images.
   208  func (p *Provider) HasDedicatedImageFs(ctx context.Context) (bool, error) {
   209  	device, err := p.containerStatsProvider.ImageFsDevice(ctx)
   210  	if err != nil {
   211  		return false, err
   212  	}
   213  	rootFsInfo, err := p.cadvisor.RootFsInfo()
   214  	if err != nil {
   215  		return false, err
   216  	}
   217  	// KEP Enhancement: DedicatedImageFs can mean either container or image fs are separate from root
   218  	// CAdvisor reports this a bit differently than Container runtimes
   219  	if device == rootFsInfo.Device {
   220  		imageFs, containerFs, err := p.ImageFsStats(ctx)
   221  		if err != nil {
   222  			return false, err
   223  		}
   224  		if !equalFileSystems(imageFs, containerFs) {
   225  			return true, nil
   226  		}
   227  	}
   228  	return device != rootFsInfo.Device, nil
   229  }
   230  
   231  func equalFileSystems(a, b *statsapi.FsStats) bool {
   232  	if a == nil || b == nil {
   233  		return false
   234  	}
   235  	if !ptr.Equal(a.AvailableBytes, b.AvailableBytes) {
   236  		return false
   237  	}
   238  	if !ptr.Equal(a.CapacityBytes, b.CapacityBytes) {
   239  		return false
   240  	}
   241  	if !ptr.Equal(a.InodesUsed, b.InodesUsed) {
   242  		return false
   243  	}
   244  	if !ptr.Equal(a.InodesFree, b.InodesFree) {
   245  		return false
   246  	}
   247  	if !ptr.Equal(a.Inodes, b.Inodes) {
   248  		return false
   249  	}
   250  	return true
   251  }