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 }