k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/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 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 "k8s.io/apimachinery/pkg/types" 25 internalapi "k8s.io/cri-api/pkg/apis" 26 statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1" 27 "k8s.io/kubernetes/pkg/kubelet/cadvisor" 28 kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" 29 "k8s.io/kubernetes/pkg/kubelet/server/stats" 30 "k8s.io/kubernetes/pkg/kubelet/stats/pidlimit" 31 "k8s.io/kubernetes/pkg/kubelet/status" 32 kubetypes "k8s.io/kubernetes/pkg/kubelet/types" 33 "k8s.io/utils/ptr" 34 ) 35 36 // PodManager is the subset of methods the manager needs to observe the actual state of the kubelet. 37 // See pkg/k8s.io/kubernetes/pkg/kubelet/pod.Manager for method godoc. 38 type PodManager interface { 39 TranslatePodUID(uid types.UID) kubetypes.ResolvedPodUID 40 } 41 42 // NewCRIStatsProvider returns a Provider that provides the node stats 43 // from cAdvisor and the container stats from CRI. 44 func NewCRIStatsProvider( 45 cadvisor cadvisor.Interface, 46 resourceAnalyzer stats.ResourceAnalyzer, 47 podManager PodManager, 48 runtimeCache kubecontainer.RuntimeCache, 49 runtimeService internalapi.RuntimeService, 50 imageService internalapi.ImageManagerService, 51 hostStatsProvider HostStatsProvider, 52 podAndContainerStatsFromCRI bool, 53 ) *Provider { 54 return newStatsProvider(cadvisor, podManager, runtimeCache, newCRIStatsProvider(cadvisor, resourceAnalyzer, 55 runtimeService, imageService, hostStatsProvider, podAndContainerStatsFromCRI)) 56 } 57 58 // NewCadvisorStatsProvider returns a containerStatsProvider that provides both 59 // the node and the container stats from cAdvisor. 60 func NewCadvisorStatsProvider( 61 cadvisor cadvisor.Interface, 62 resourceAnalyzer stats.ResourceAnalyzer, 63 podManager PodManager, 64 runtimeCache kubecontainer.RuntimeCache, 65 imageService kubecontainer.ImageService, 66 statusProvider status.PodStatusProvider, 67 hostStatsProvider HostStatsProvider, 68 ) *Provider { 69 return newStatsProvider(cadvisor, podManager, runtimeCache, newCadvisorStatsProvider(cadvisor, resourceAnalyzer, imageService, statusProvider, hostStatsProvider)) 70 } 71 72 // newStatsProvider returns a new Provider that provides node stats from 73 // cAdvisor and the container stats using the containerStatsProvider. 74 func newStatsProvider( 75 cadvisor cadvisor.Interface, 76 podManager PodManager, 77 runtimeCache kubecontainer.RuntimeCache, 78 containerStatsProvider containerStatsProvider, 79 ) *Provider { 80 return &Provider{ 81 cadvisor: cadvisor, 82 podManager: podManager, 83 runtimeCache: runtimeCache, 84 containerStatsProvider: containerStatsProvider, 85 } 86 } 87 88 // Provider provides the stats of the node and the pod-managed containers. 89 type Provider struct { 90 cadvisor cadvisor.Interface 91 podManager PodManager 92 runtimeCache kubecontainer.RuntimeCache 93 containerStatsProvider 94 } 95 96 // containerStatsProvider is an interface that provides the stats of the 97 // containers managed by pods. 98 type containerStatsProvider interface { 99 ListPodStats(ctx context.Context) ([]statsapi.PodStats, error) 100 ListPodStatsAndUpdateCPUNanoCoreUsage(ctx context.Context) ([]statsapi.PodStats, error) 101 ListPodCPUAndMemoryStats(ctx context.Context) ([]statsapi.PodStats, error) 102 ImageFsStats(ctx context.Context) (*statsapi.FsStats, *statsapi.FsStats, error) 103 ImageFsDevice(ctx context.Context) (string, error) 104 } 105 106 // RlimitStats returns base information about process count 107 func (p *Provider) RlimitStats() (*statsapi.RlimitStats, error) { 108 return pidlimit.Stats() 109 } 110 111 // GetCgroupStats returns the stats of the cgroup with the cgroupName. Note that 112 // this function doesn't generate filesystem stats. 113 func (p *Provider) GetCgroupStats(cgroupName string, updateStats bool) (*statsapi.ContainerStats, *statsapi.NetworkStats, error) { 114 info, err := getCgroupInfo(p.cadvisor, cgroupName, updateStats) 115 if err != nil { 116 return nil, nil, fmt.Errorf("failed to get cgroup stats for %q: %v", cgroupName, err) 117 } 118 // Rootfs and imagefs doesn't make sense for raw cgroup. 119 s := cadvisorInfoToContainerStats(cgroupName, info, nil, nil) 120 n := cadvisorInfoToNetworkStats(info) 121 return s, n, nil 122 } 123 124 // GetCgroupCPUAndMemoryStats returns the CPU and memory stats of the cgroup with the cgroupName. Note that 125 // this function doesn't generate filesystem stats. 126 func (p *Provider) GetCgroupCPUAndMemoryStats(cgroupName string, updateStats bool) (*statsapi.ContainerStats, error) { 127 info, err := getCgroupInfo(p.cadvisor, cgroupName, updateStats) 128 if err != nil { 129 return nil, fmt.Errorf("failed to get cgroup stats for %q: %v", cgroupName, err) 130 } 131 // Rootfs and imagefs doesn't make sense for raw cgroup. 132 s := cadvisorInfoToContainerCPUAndMemoryStats(cgroupName, info) 133 return s, nil 134 } 135 136 // RootFsStats returns the stats of the node root filesystem. 137 func (p *Provider) RootFsStats() (*statsapi.FsStats, error) { 138 rootFsInfo, err := p.cadvisor.RootFsInfo() 139 if err != nil { 140 return nil, fmt.Errorf("failed to get rootFs info: %v", err) 141 } 142 143 var nodeFsInodesUsed *uint64 144 if rootFsInfo.Inodes != nil && rootFsInfo.InodesFree != nil { 145 nodeFsIU := *rootFsInfo.Inodes - *rootFsInfo.InodesFree 146 nodeFsInodesUsed = &nodeFsIU 147 } 148 149 // Get the root container stats's timestamp, which will be used as the 150 // imageFs stats timestamp. Don't force a stats update, as we only want the timestamp. 151 rootStats, err := getCgroupStats(p.cadvisor, "/", false) 152 if err != nil { 153 return nil, fmt.Errorf("failed to get root container stats: %v", err) 154 } 155 156 return &statsapi.FsStats{ 157 Time: metav1.NewTime(rootStats.Timestamp), 158 AvailableBytes: &rootFsInfo.Available, 159 CapacityBytes: &rootFsInfo.Capacity, 160 UsedBytes: &rootFsInfo.Usage, 161 InodesFree: rootFsInfo.InodesFree, 162 Inodes: rootFsInfo.Inodes, 163 InodesUsed: nodeFsInodesUsed, 164 }, nil 165 } 166 167 // HasDedicatedImageFs returns true if a dedicated image filesystem exists for storing images. 168 // KEP Issue Number 4191: Enhanced this to allow for the containers to be separate from images. 169 func (p *Provider) HasDedicatedImageFs(ctx context.Context) (bool, error) { 170 device, err := p.containerStatsProvider.ImageFsDevice(ctx) 171 if err != nil { 172 return false, err 173 } 174 rootFsInfo, err := p.cadvisor.RootFsInfo() 175 if err != nil { 176 return false, err 177 } 178 // KEP Enhancement: DedicatedImageFs can mean either container or image fs are separate from root 179 // CAdvisor reports this a bit differently than Container runtimes 180 if device == rootFsInfo.Device { 181 imageFs, containerFs, err := p.ImageFsStats(ctx) 182 if err != nil { 183 return false, err 184 } 185 if !equalFileSystems(imageFs, containerFs) { 186 return true, nil 187 } 188 } 189 return device != rootFsInfo.Device, nil 190 } 191 192 func equalFileSystems(a, b *statsapi.FsStats) bool { 193 if a == nil || b == nil { 194 return false 195 } 196 if !ptr.Equal(a.AvailableBytes, b.AvailableBytes) { 197 return false 198 } 199 if !ptr.Equal(a.CapacityBytes, b.CapacityBytes) { 200 return false 201 } 202 if !ptr.Equal(a.InodesUsed, b.InodesUsed) { 203 return false 204 } 205 if !ptr.Equal(a.InodesFree, b.InodesFree) { 206 return false 207 } 208 if !ptr.Equal(a.Inodes, b.Inodes) { 209 return false 210 } 211 return true 212 }